maintainability-agent 2.5.0__tar.gz → 2.6.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (320) hide show
  1. {maintainability_agent-2.5.0/src/maintainability_agent.egg-info → maintainability_agent-2.6.0}/PKG-INFO +11 -7
  2. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/README.md +10 -6
  3. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/pyproject.toml +1 -1
  4. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0/src/maintainability_agent.egg-info}/PKG-INFO +11 -7
  5. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_agent.egg-info/SOURCES.txt +3 -0
  6. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/__init__.py +1 -1
  7. maintainability_agent-2.6.0/src/maintainability_audit/_arguments.py +186 -0
  8. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/_gates.py +28 -4
  9. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/_history_view.py +46 -0
  10. maintainability_agent-2.6.0/src/maintainability_audit/_run_comparison.py +184 -0
  11. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/_scan_history.py +19 -1
  12. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/cli.py +37 -165
  13. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/config.py +1 -1
  14. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/renderers.py +6 -1
  15. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_history_schema2.py +18 -3
  16. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_identity_resolution.py +4 -1
  17. maintainability_agent-2.6.0/tests/test_run_comparison.py +321 -0
  18. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/LICENSE +0 -0
  19. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/setup.cfg +0 -0
  20. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_agent.egg-info/dependency_links.txt +0 -0
  21. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_agent.egg-info/entry_points.txt +0 -0
  22. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_agent.egg-info/requires.txt +0 -0
  23. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_agent.egg-info/top_level.txt +0 -0
  24. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/__main__.py +0 -0
  25. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/_adapters.py +0 -0
  26. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/_analysis.py +0 -0
  27. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/_aspects.py +0 -0
  28. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/_assets/analyzer-catalog.json +0 -0
  29. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/_assets/standard.md +0 -0
  30. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/_attestation.py +0 -0
  31. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/_backfill.py +0 -0
  32. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/_bands.py +0 -0
  33. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/_built_ins.py +0 -0
  34. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/_calibration.py +0 -0
  35. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/_catalog.py +0 -0
  36. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/_charts.py +0 -0
  37. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/_cognitive.py +0 -0
  38. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/_config_defaults.py +0 -0
  39. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/_conformance.py +0 -0
  40. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/_corroborate.py +0 -0
  41. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/_coverage_notes.py +0 -0
  42. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/_derive.py +0 -0
  43. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/_discovery.py +0 -0
  44. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/_documents.py +0 -0
  45. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/_economics.py +0 -0
  46. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/_economics_view.py +0 -0
  47. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/_environment.py +0 -0
  48. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/_evidence_view.py +0 -0
  49. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/_finding_match.py +0 -0
  50. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/_first_run.py +0 -0
  51. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/_formula.py +0 -0
  52. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/_generic.py +0 -0
  53. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/_grant_ledger.py +0 -0
  54. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/_hostile_prompt.py +0 -0
  55. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/_hotspots.py +0 -0
  56. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/_html_report_sections.py +0 -0
  57. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/_html_view.py +0 -0
  58. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/_identity.py +0 -0
  59. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/_jvm_adapters.py +0 -0
  60. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/_markdown_sections.py +0 -0
  61. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/_masking.py +0 -0
  62. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/_mcp_audit.py +0 -0
  63. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/_mcp_gate.py +0 -0
  64. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/_mcp_grants.py +0 -0
  65. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/_mcp_refusals.py +0 -0
  66. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/_mcp_resources.py +0 -0
  67. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/_mcp_setup.py +0 -0
  68. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/_metric_adapters.py +0 -0
  69. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/_metrics_types.py +0 -0
  70. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/_pillars.py +0 -0
  71. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/_practice.py +0 -0
  72. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/_pressures.py +0 -0
  73. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/_ranges_c.py +0 -0
  74. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/_ranges_core.py +0 -0
  75. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/_ranges_cpp.py +0 -0
  76. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/_ranges_csharp.py +0 -0
  77. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/_ranges_fortran.py +0 -0
  78. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/_ranges_java.py +0 -0
  79. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/_ranges_js.py +0 -0
  80. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/_ranges_swift.py +0 -0
  81. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/_ratchet.py +0 -0
  82. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/_recurrence.py +0 -0
  83. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/_runner.py +0 -0
  84. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/_safe_write.py +0 -0
  85. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/_scan_view.py +0 -0
  86. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/_second_source.py +0 -0
  87. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/_selection.py +0 -0
  88. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/_semantic.py +0 -0
  89. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/_semantic_policy.py +0 -0
  90. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/_semantic_ts.py +0 -0
  91. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/_semantic_view.py +0 -0
  92. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/_setup_errors.py +0 -0
  93. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/_setup_persist.py +0 -0
  94. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/_skill_data/SKILL.md +0 -0
  95. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/_skill_data/agents/anthropic.yaml +0 -0
  96. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/_skill_data/agents/copilot.yaml +0 -0
  97. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/_skill_data/agents/openai.yaml +0 -0
  98. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/_skill_data/copilot/maintainability-agent.prompt.md +0 -0
  99. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/_skill_data/references/finding-taxonomy.md +0 -0
  100. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/_skill_install.py +0 -0
  101. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/_stored_grants.py +0 -0
  102. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/_tdd_view.py +0 -0
  103. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/_test_commands.py +0 -0
  104. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/_test_execution.py +0 -0
  105. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/_test_pairing.py +0 -0
  106. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/_tokens.py +0 -0
  107. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/_tool_adapters.py +0 -0
  108. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/_trends.py +0 -0
  109. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/_user_config.py +0 -0
  110. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/_verdict_adapters.py +0 -0
  111. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/_verification.py +0 -0
  112. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/_work_order.py +0 -0
  113. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/_work_order_view.py +0 -0
  114. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/_work_order_weights.py +0 -0
  115. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/_xml.py +0 -0
  116. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/baseline.py +0 -0
  117. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/deadcode.py +0 -0
  118. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/declarations.py +0 -0
  119. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/duplication.py +0 -0
  120. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/evidence.py +0 -0
  121. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/git_tools.py +0 -0
  122. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/history.py +0 -0
  123. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/idioms.py +0 -0
  124. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/instructions.py +0 -0
  125. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/mcp_server.py +0 -0
  126. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/metrics.py +0 -0
  127. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/prompts.py +0 -0
  128. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/report.py +0 -0
  129. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/sarif.py +0 -0
  130. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/scoring.py +0 -0
  131. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/similarity.py +0 -0
  132. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/src/maintainability_audit/source.py +0 -0
  133. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_acquisition_trust.py +0 -0
  134. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_adapter_docs.py +0 -0
  135. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_adapter_recordings.py +0 -0
  136. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_adapters.py +0 -0
  137. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_added_lines.py +0 -0
  138. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_analysis_coverage.py +0 -0
  139. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_analysis_execution.py +0 -0
  140. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_analyzer_bridge.py +0 -0
  141. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_analyzer_config_isolation.py +0 -0
  142. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_analyzer_estimate_claims.py +0 -0
  143. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_analyzer_pinning.py +0 -0
  144. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_analyzer_primary_estimate.py +0 -0
  145. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_analyzer_provenance.py +0 -0
  146. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_analyzer_provenance_exclusions.py +0 -0
  147. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_analyzer_scoring_path.py +0 -0
  148. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_analyzer_spread_range.py +0 -0
  149. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_analyzer_xml_bounds.py +0 -0
  150. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_annotations_match_behaviour.py +0 -0
  151. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_anticipated_refusals.py +0 -0
  152. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_architecture.py +0 -0
  153. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_artifact_write_route_class.py +0 -0
  154. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_aspect_coverage.py +0 -0
  155. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_asset_snapshot_class.py +0 -0
  156. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_ast_reading_resolves_spellings.py +0 -0
  157. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_attestation.py +0 -0
  158. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_audit_components.py +0 -0
  159. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_authorization_freshness.py +0 -0
  160. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_authorship_gates.py +0 -0
  161. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_backfill.py +0 -0
  162. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_band_concealment_class.py +0 -0
  163. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_band_concealment_p3.py +0 -0
  164. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_band_pressures.py +0 -0
  165. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_bands.py +0 -0
  166. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_body_or_signature_class.py +0 -0
  167. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_c_declarations.py +0 -0
  168. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_calibration_corpus.py +0 -0
  169. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_calibration_drift.py +0 -0
  170. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_calibration_tooling.py +0 -0
  171. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_catalog_selection.py +0 -0
  172. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_catalog_tier_promise.py +0 -0
  173. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_chat_primary_docs.py +0 -0
  174. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_checkstyle_adapter.py +0 -0
  175. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_checkstyle_catalog.py +0 -0
  176. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_ci_history_recipe.py +0 -0
  177. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_ci_installs_the_analyzer_pool.py +0 -0
  178. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_claimed_languages.py +0 -0
  179. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_cli.py +0 -0
  180. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_clone_group_class.py +0 -0
  181. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_cognitive_complexity.py +0 -0
  182. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_cohort_statistics.py +0 -0
  183. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_concealment_properties.py +0 -0
  184. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_config_shape.py +0 -0
  185. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_consent_and_grant.py +0 -0
  186. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_consumer_migration.py +0 -0
  187. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_contract_claims.py +0 -0
  188. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_corroborate.py +0 -0
  189. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_coverage_by_language.py +0 -0
  190. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_cpp_declarations.py +0 -0
  191. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_csharp_declarations.py +0 -0
  192. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_d15_composition.py +0 -0
  193. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_d15_goal_directed.py +0 -0
  194. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_dead_code.py +0 -0
  195. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_declaration_edge_cases.py +0 -0
  196. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_declaration_grading.py +0 -0
  197. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_declaration_ranges.py +0 -0
  198. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_declaration_source.py +0 -0
  199. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_declared_authorship.py +0 -0
  200. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_declared_imports.py +0 -0
  201. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_derivation_mix.py +0 -0
  202. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_determinism.py +0 -0
  203. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_dimension_ratchet.py +0 -0
  204. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_direct_runner_availability_class.py +0 -0
  205. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_discovery.py +0 -0
  206. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_doc_claims.py +0 -0
  207. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_docs_links.py +0 -0
  208. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_economic_context.py +0 -0
  209. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_empty_output_not_clean.py +0 -0
  210. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_empty_output_not_clean_adapters.py +0 -0
  211. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_environment_work_order.py +0 -0
  212. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_evidence_invariants.py +0 -0
  213. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_evidence_normalization.py +0 -0
  214. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_evidence_properties.py +0 -0
  215. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_exclusion_dialects.py +0 -0
  216. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_falsifier_standard.py +0 -0
  217. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_file_list_cap_class.py +0 -0
  218. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_finding_identity.py +0 -0
  219. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_first_run_elicitation.py +0 -0
  220. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_first_run_prompt.py +0 -0
  221. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_first_run_reelicitation.py +0 -0
  222. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_fix_breadth_window.py +0 -0
  223. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_fixed_form_fortran.py +0 -0
  224. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_format_ask.py +0 -0
  225. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_fortran_declarations.py +0 -0
  226. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_fortran_metrics.py +0 -0
  227. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_fortran_practice.py +0 -0
  228. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_git_argv.py +0 -0
  229. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_git_read_only.py +0 -0
  230. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_git_readonly_class.py +0 -0
  231. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_grant_only_user_tier.py +0 -0
  232. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_history.py +0 -0
  233. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_history_boundary.py +0 -0
  234. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_history_manifest.py +0 -0
  235. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_history_window.py +0 -0
  236. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_hostile_prompt.py +0 -0
  237. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_html_executive.py +0 -0
  238. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_html_section_parity_class.py +0 -0
  239. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_identity_docs.py +0 -0
  240. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_idiom_divergence.py +0 -0
  241. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_installed_wheel_runtime.py +0 -0
  242. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_instruction_targets.py +0 -0
  243. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_java_range_guard.py +0 -0
  244. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_java_ranges.py +0 -0
  245. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_java_scored.py +0 -0
  246. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_java_wiring.py +0 -0
  247. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_js_complexity_operators.py +0 -0
  248. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_js_declarations.py +0 -0
  249. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_language_coverage.py +0 -0
  250. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_mcp_baseline_payload.py +0 -0
  251. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_mcp_history.py +0 -0
  252. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_mcp_server.py +0 -0
  253. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_migration_1_0.py +0 -0
  254. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_near_duplicates.py +0 -0
  255. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_network_disclosure.py +0 -0
  256. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_one_setup_across_surfaces_class.py +0 -0
  257. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_pattern_budget.py +0 -0
  258. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_phase6_claims.py +0 -0
  259. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_pillars_and_practice.py +0 -0
  260. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_platform_claim.py +0 -0
  261. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_pmd_adapter.py +0 -0
  262. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_pmd_audit_closures.py +0 -0
  263. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_pool_runs_by_config.py +0 -0
  264. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_population_floors.py +0 -0
  265. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_practice_nested_gates_class.py +0 -0
  266. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_presentation_refusals.py +0 -0
  267. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_promises.py +0 -0
  268. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_prompt_escalation_once.py +0 -0
  269. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_prompt_honesty.py +0 -0
  270. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_prompt_location_escalation_class.py +0 -0
  271. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_prove_falsifiers.py +0 -0
  272. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_python_declarations.py +0 -0
  273. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_read_boundary.py +0 -0
  274. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_readme_claims.py +0 -0
  275. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_recurrence.py +0 -0
  276. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_release_plan.py +0 -0
  277. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_release_plan_status.py +0 -0
  278. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_report_remedy_copy.py +0 -0
  279. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_roles_recorded.py +0 -0
  280. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_root_grants.py +0 -0
  281. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_rubric_ignores_project_lint_config.py +0 -0
  282. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_runner.py +0 -0
  283. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_sarif.py +0 -0
  284. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_scan_history.py +0 -0
  285. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_scan_scope.py +0 -0
  286. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_scanning.py +0 -0
  287. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_schema_fidelity.py +0 -0
  288. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_scope_conformance.py +0 -0
  289. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_scoring_calibration.py +0 -0
  290. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_semantic_policy.py +0 -0
  291. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_setup_gate_completeness.py +0 -0
  292. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_setup_gate_independent_contract.py +0 -0
  293. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_setup_precondition.py +0 -0
  294. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_skill_install.py +0 -0
  295. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_source_index.py +0 -0
  296. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_spotbugs_adapter.py +0 -0
  297. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_spotbugs_catalog.py +0 -0
  298. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_stage8_contract.py +0 -0
  299. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_suite_isolation.py +0 -0
  300. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_swift_declarations.py +0 -0
  301. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_tdd_structure.py +0 -0
  302. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_test_commands.py +0 -0
  303. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_test_execution_class.py +0 -0
  304. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_three_presentations.py +0 -0
  305. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_trends.py +0 -0
  306. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_type_fields_not_functions_class.py +0 -0
  307. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_uat_falsifiers.py +0 -0
  308. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_unread_code.py +0 -0
  309. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_user_config_tier.py +0 -0
  310. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_verification_audit_closures.py +0 -0
  311. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_verified_grade.py +0 -0
  312. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_version_claim.py +0 -0
  313. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_wheel_contents.py +0 -0
  314. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_work_order.py +0 -0
  315. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_work_order_items.py +0 -0
  316. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_work_order_selection.py +0 -0
  317. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_workflow_supply_chain.py +0 -0
  318. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_write_boundary.py +0 -0
  319. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_write_route_class.py +0 -0
  320. {maintainability_agent-2.5.0 → maintainability_agent-2.6.0}/tests/test_written_record.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: maintainability-agent
3
- Version: 2.5.0
3
+ Version: 2.6.0
4
4
  Summary: Maintainability gate and AI remediation prompt generator for CI.
5
5
  Author: Marshall Guillory
6
6
  License: MIT
@@ -44,7 +44,7 @@ Dynamic: license-file
44
44
  **A deterministic, offline maintainability audit whose output is a _bounded
45
45
  work order_ for an AI coding agent** — a copy-paste prompt, per finding, that
46
46
  says *fix exactly these and refactor nothing else*. Chat-primary; CLI for CI.
47
- Version **2.5.0**.
47
+ Version **2.6.0**.
48
48
 
49
49
  **Languages parsed:** Python, Java, C, C++, C#, Swift, Fortran (free-form
50
50
  *and* fixed-form), and the JS/TS family — each by a scanner written for it, and
@@ -152,9 +152,8 @@ registered verdict stands at **INCONCLUSIVE**. Method, limits and raw data:
152
152
  every claim the project could not stand behind was removed. A scoring engine
153
153
  rebuilt after it was found to grade repo *size*; a headline claim about AI
154
154
  authorship retracted against a matched control; a score that is withheld rather
155
- than guessed. That arc is the credibility, and it is recorded in full — with the
156
- figures quoted from their approved summaries — in
157
- [the track record](docs/track-record.md).
155
+ than guessed. That arc is the credibility, and it is recorded in full, with the
156
+ figures quoted from their approved summaries, in [the track record](docs/track-record.md).
158
157
 
159
158
  ## Install
160
159
 
@@ -223,8 +222,8 @@ withheld and the scope is named as the reason.
223
222
  ### Checking that the agent did the work
224
223
 
225
224
  The work order tells an agent to fix exactly these findings and refactor nothing
226
- else. These flags check that the diff that came back obeyed it — read the
227
- diff's _shape_, not its correctness:
225
+ else. These flags check that the diff obeyed it — they read its _shape_, not its
226
+ correctness:
228
227
 
229
228
  ```bash
230
229
  maintainability-agent \
@@ -251,6 +250,11 @@ maintainability-agent \
251
250
  work order, and what moved. It is reproducible and **not signed** — nothing
252
251
  here holds a key, and the document says so in its own text. A check nobody ran
253
252
  renders as _not asked_, never as passed.
253
+ - **`--transformation NAME`** names the class of work a scan followed and
254
+ reports how this run of it compares with earlier ones. **A report, never a
255
+ gate.** It says one run "moved further" than another, never that it was
256
+ _better_ — two runs of one codemod land on different code — and it measures
257
+ the interval, not the transformation.
254
258
 
255
259
  The [roadmap](docs/roadmap.md#the-remediation-hole-closed-in-210-through-230)
256
260
  has the history of why this was the hole under the product's central claim.
@@ -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 **2.5.0**.
8
+ Version **2.6.0**.
9
9
 
10
10
  **Languages parsed:** Python, Java, C, C++, C#, Swift, Fortran (free-form
11
11
  *and* fixed-form), and the JS/TS family — each by a scanner written for it, and
@@ -113,9 +113,8 @@ registered verdict stands at **INCONCLUSIVE**. Method, limits and raw data:
113
113
  every claim the project could not stand behind was removed. A scoring engine
114
114
  rebuilt after it was found to grade repo *size*; a headline claim about AI
115
115
  authorship retracted against a matched control; a score that is withheld rather
116
- than guessed. That arc is the credibility, and it is recorded in full — with the
117
- figures quoted from their approved summaries — in
118
- [the track record](docs/track-record.md).
116
+ than guessed. That arc is the credibility, and it is recorded in full, with the
117
+ figures quoted from their approved summaries, in [the track record](docs/track-record.md).
119
118
 
120
119
  ## Install
121
120
 
@@ -184,8 +183,8 @@ withheld and the scope is named as the reason.
184
183
  ### Checking that the agent did the work
185
184
 
186
185
  The work order tells an agent to fix exactly these findings and refactor nothing
187
- else. These flags check that the diff that came back obeyed it — read the
188
- diff's _shape_, not its correctness:
186
+ else. These flags check that the diff obeyed it — they read its _shape_, not its
187
+ correctness:
189
188
 
190
189
  ```bash
191
190
  maintainability-agent \
@@ -212,6 +211,11 @@ maintainability-agent \
212
211
  work order, and what moved. It is reproducible and **not signed** — nothing
213
212
  here holds a key, and the document says so in its own text. A check nobody ran
214
213
  renders as _not asked_, never as passed.
214
+ - **`--transformation NAME`** names the class of work a scan followed and
215
+ reports how this run of it compares with earlier ones. **A report, never a
216
+ gate.** It says one run "moved further" than another, never that it was
217
+ _better_ — two runs of one codemod land on different code — and it measures
218
+ the interval, not the transformation.
215
219
 
216
220
  The [roadmap](docs/roadmap.md#the-remediation-hole-closed-in-210-through-230)
217
221
  has the history of why this was the hole under the product's central claim.
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "maintainability-agent"
7
- version = "2.5.0"
7
+ version = "2.6.0"
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: 2.5.0
3
+ Version: 2.6.0
4
4
  Summary: Maintainability gate and AI remediation prompt generator for CI.
5
5
  Author: Marshall Guillory
6
6
  License: MIT
@@ -44,7 +44,7 @@ Dynamic: license-file
44
44
  **A deterministic, offline maintainability audit whose output is a _bounded
45
45
  work order_ for an AI coding agent** — a copy-paste prompt, per finding, that
46
46
  says *fix exactly these and refactor nothing else*. Chat-primary; CLI for CI.
47
- Version **2.5.0**.
47
+ Version **2.6.0**.
48
48
 
49
49
  **Languages parsed:** Python, Java, C, C++, C#, Swift, Fortran (free-form
50
50
  *and* fixed-form), and the JS/TS family — each by a scanner written for it, and
@@ -152,9 +152,8 @@ registered verdict stands at **INCONCLUSIVE**. Method, limits and raw data:
152
152
  every claim the project could not stand behind was removed. A scoring engine
153
153
  rebuilt after it was found to grade repo *size*; a headline claim about AI
154
154
  authorship retracted against a matched control; a score that is withheld rather
155
- than guessed. That arc is the credibility, and it is recorded in full — with the
156
- figures quoted from their approved summaries — in
157
- [the track record](docs/track-record.md).
155
+ than guessed. That arc is the credibility, and it is recorded in full, with the
156
+ figures quoted from their approved summaries, in [the track record](docs/track-record.md).
158
157
 
159
158
  ## Install
160
159
 
@@ -223,8 +222,8 @@ withheld and the scope is named as the reason.
223
222
  ### Checking that the agent did the work
224
223
 
225
224
  The work order tells an agent to fix exactly these findings and refactor nothing
226
- else. These flags check that the diff that came back obeyed it — read the
227
- diff's _shape_, not its correctness:
225
+ else. These flags check that the diff obeyed it — they read its _shape_, not its
226
+ correctness:
228
227
 
229
228
  ```bash
230
229
  maintainability-agent \
@@ -251,6 +250,11 @@ maintainability-agent \
251
250
  work order, and what moved. It is reproducible and **not signed** — nothing
252
251
  here holds a key, and the document says so in its own text. A check nobody ran
253
252
  renders as _not asked_, never as passed.
253
+ - **`--transformation NAME`** names the class of work a scan followed and
254
+ reports how this run of it compares with earlier ones. **A report, never a
255
+ gate.** It says one run "moved further" than another, never that it was
256
+ _better_ — two runs of one codemod land on different code — and it measures
257
+ the interval, not the transformation.
254
258
 
255
259
  The [roadmap](docs/roadmap.md#the-remediation-hole-closed-in-210-through-230)
256
260
  has the history of why this was the hole under the product's central claim.
@@ -11,6 +11,7 @@ src/maintainability_audit/__init__.py
11
11
  src/maintainability_audit/__main__.py
12
12
  src/maintainability_audit/_adapters.py
13
13
  src/maintainability_audit/_analysis.py
14
+ src/maintainability_audit/_arguments.py
14
15
  src/maintainability_audit/_aspects.py
15
16
  src/maintainability_audit/_attestation.py
16
17
  src/maintainability_audit/_backfill.py
@@ -67,6 +68,7 @@ src/maintainability_audit/_ranges_js.py
67
68
  src/maintainability_audit/_ranges_swift.py
68
69
  src/maintainability_audit/_ratchet.py
69
70
  src/maintainability_audit/_recurrence.py
71
+ src/maintainability_audit/_run_comparison.py
70
72
  src/maintainability_audit/_runner.py
71
73
  src/maintainability_audit/_safe_write.py
72
74
  src/maintainability_audit/_scan_history.py
@@ -274,6 +276,7 @@ tests/test_report_remedy_copy.py
274
276
  tests/test_roles_recorded.py
275
277
  tests/test_root_grants.py
276
278
  tests/test_rubric_ignores_project_lint_config.py
279
+ tests/test_run_comparison.py
277
280
  tests/test_runner.py
278
281
  tests/test_sarif.py
279
282
  tests/test_scan_history.py
@@ -1,3 +1,3 @@
1
1
  """Maintainability Audit CI."""
2
2
 
3
- __version__ = "2.5.0"
3
+ __version__ = "2.6.0"
@@ -0,0 +1,186 @@
1
+ """What the command line accepts, separate from what the command does.
2
+
3
+ Split out of `cli` when it crossed this project's own `max_file_lines`
4
+ gate — the second time that gate has shaped this module, after
5
+ `_add_gate_arguments` was split from `add_arguments` for the function
6
+ budget. Both splits were forced by the tool on a change to the tool, which
7
+ is the gate doing the job it exists for rather than an inconvenience.
8
+
9
+ The boundary is deliberate and not merely a line count: everything here
10
+ declares a flag and nothing here runs an audit. `cli` imports it, never
11
+ the reverse.
12
+ """
13
+ from __future__ import annotations
14
+
15
+ import argparse
16
+
17
+ from .config import VERSION
18
+
19
+
20
+ def _add_gate_arguments(parser: argparse.ArgumentParser) -> None:
21
+ """What can make a run fail, and the conformance record behind one.
22
+
23
+ Split from `add_arguments` when the conformance flags took it past this
24
+ project's own function-length gate — which is the gate doing its job on
25
+ the change that added a gate.
26
+ """
27
+ parser.add_argument("--fail-on-gate", action="store_true", help="Exit 1 when hard gates fail.")
28
+ parser.add_argument(
29
+ "--conformance",
30
+ metavar="REVSPEC",
31
+ help="Report how a diff relates to the work order, e.g. `main...HEAD`. "
32
+ "The bounded work order says 'fix exactly these and refactor nothing "
33
+ "else'; without this the bound is an instruction nothing checks. "
34
+ "Reports only unless --fail-on-out-of-scope is passed.",
35
+ )
36
+ parser.add_argument(
37
+ "--fail-on-regression", action="store_true",
38
+ help="Exit 1 when any scoring category is lower than the previous "
39
+ "comparable scan. Reads the recorded history, and refuses to "
40
+ "compare across an instrument change rather than reporting a "
41
+ "false regression: two scans taken under different calibration "
42
+ "cannot be subtracted.",
43
+ )
44
+ parser.add_argument(
45
+ "--fail-on-out-of-scope", action="store_true",
46
+ help="With --conformance, exit 1 when the diff touched files the work "
47
+ "order did not name and that do not pair to one as its test, or "
48
+ "when it added a suppression to a file the work order flagged.",
49
+ )
50
+
51
+
52
+ def _add_artifact_arguments(parser: argparse.ArgumentParser) -> None:
53
+ """The documents a run can write beside its report, and the run's label.
54
+
55
+ Split out for the same reason `_add_gate_arguments` was, and by the same
56
+ gate: `--transformation` took `add_arguments` past this project's own
57
+ function-length threshold, so the gate failed the change that added a
58
+ reporting flag. Grouped by what they produce rather than alphabetically
59
+ — every one of these is an artifact for somebody other than the person
60
+ running the command.
61
+ """
62
+ parser.add_argument("--prompt-output", help="Optional Markdown prompt for AI-assisted remediation.")
63
+ parser.add_argument("--comment-output", help="Optional Markdown body suitable for a PR comment.")
64
+ parser.add_argument("--agent-instructions-output", help="Optional reusable instructions for AI coding agents.")
65
+ parser.add_argument(
66
+ "--attestation-output",
67
+ help="Write the attestation: an independent, reproducible record of "
68
+ "what was measured, what the change was told to do, what it did, "
69
+ "and what moved. Populated by --conformance and "
70
+ "--fail-on-regression; a generator cannot produce this about its "
71
+ "own output.",
72
+ )
73
+ parser.add_argument(
74
+ "--transformation",
75
+ metavar="NAME",
76
+ help="Name the class of work this scan followed, e.g. `react-18`. "
77
+ "Records the name on the scan and reports how this run of it "
78
+ "compares with earlier ones. Nothing in a tree says which "
79
+ "transformation produced it, so this is your claim and the tool "
80
+ "records it without verifying it. A report, never a gate.",
81
+ )
82
+ parser.add_argument("--hostile-prompt-output",
83
+ help="Optional adversarial audit brief seeded from this run (ADR 013). "
84
+ "Text only: it does not gate, score, or send anything.")
85
+
86
+
87
+ def add_arguments(parser: argparse.ArgumentParser) -> None:
88
+ parser.add_argument("--version", action="version", version=f"maintainability-agent {VERSION}")
89
+ parser.add_argument("--root", default=".", help="Repository root to scan.")
90
+ parser.add_argument("--config", help="Path to JSON config.")
91
+ # Default None, not "markdown": the TTY question (8.4) only fires
92
+ # when the user stated nothing, and argparse cannot distinguish a
93
+ # stated default from an omitted flag.
94
+ parser.add_argument("--format", choices=["json", "markdown", "html"], default=None)
95
+ parser.add_argument("--html-output", help="Write the single-file HTML report here (ADR 011).")
96
+ parser.add_argument("--output", help="Output file. Defaults to stdout.")
97
+ _add_artifact_arguments(parser)
98
+ parser.add_argument("--sarif-output", help="Optional SARIF output path for GitHub code scanning.")
99
+ parser.add_argument("--sarif-input", action="append", help="Optional external SARIF file to summarize in reports. Repeatable.")
100
+ parser.add_argument("--changed-only", help="Audit only files changed in a git revspec, for example main...HEAD.")
101
+ parser.add_argument("--baseline", help="Existing baseline JSON. With --fail-on-new, only new findings fail.")
102
+ parser.add_argument("--write-baseline", help="Write current findings to a baseline JSON file.")
103
+ parser.add_argument("--fail-on-new", action="store_true", help="Fail only when findings are not in --baseline.")
104
+ parser.add_argument(
105
+ "--analyzers", action="store_true",
106
+ help="Force the external analyzer pool on for this run. The pool is "
107
+ "the primary evidence source (ADR 006, docs/analyzer-pool.md); a "
108
+ "repository with a config file runs it by default, so this flag "
109
+ "matters only for unconfigured trees or to override "
110
+ "analyzers.run=false. Measurements move the point estimate where "
111
+ "the full concept set was measured; otherwise the built-in "
112
+ "fallback stands and the range widens around the two.",
113
+ )
114
+ parser.add_argument(
115
+ "--no-analyzers", action="store_true",
116
+ help="Force the analyzer pool off for this run, overriding the "
117
+ "config. The report will say the built-in fallback supplied the "
118
+ "evidence (P8); it is a faster scan, not the full audit.",
119
+ )
120
+ parser.add_argument(
121
+ "--work", action="append", metavar="AXIS=VALUE",
122
+ help="Narrow the work order, for example --work band=quick-win or "
123
+ "--work path=src/. Repeatable; every criterion must match. "
124
+ "Axes: band, finding_class, path, verification. Narrowing "
125
+ "changes what is shown and never what anything scored.",
126
+ )
127
+ parser.add_argument(
128
+ "--record-history", action="store_true",
129
+ help="Append this scan to the history at paths.history (default "
130
+ ".maintainability/history.jsonl). Opt-in, like every other write "
131
+ "this tool performs. Once the file exists, every later successful "
132
+ "scan appends to it and reads the resulting history.",
133
+ )
134
+ parser.add_argument(
135
+ "--backfill", metavar="REVSPEC",
136
+ help="Scan each commit in a range into the history and exit, for "
137
+ "example --backfill HEAD~50..HEAD. Each commit is checked out in "
138
+ "a temporary worktree, so the working tree is never touched. "
139
+ "Expensive and therefore explicit: it never runs as part of a "
140
+ "normal scan. Records are marked as reconstructed.",
141
+ )
142
+ parser.add_argument(
143
+ "--backfill-interval", type=int, default=1, metavar="N",
144
+ help="With --backfill, scan every Nth commit instead of all of them. "
145
+ "The shape of a series is what a trend reads, and a thousand "
146
+ "commits is hours of work nobody asked for.",
147
+ )
148
+ _add_gate_arguments(parser)
149
+ _add_setup_actions(parser)
150
+
151
+
152
+ def _add_setup_actions(parser: argparse.ArgumentParser) -> None:
153
+ """Flags that perform a setup action and exit instead of auditing."""
154
+ parser.add_argument("--init-agent-standards", action="store_true", help="Write model/tool-specific instruction files and exit.")
155
+ parser.add_argument(
156
+ "--install-skill", action="store_true",
157
+ help="Copy the packaged agent skill into the skills directory and "
158
+ "exit. Re-run after every upgrade: an installed skill that "
159
+ "drifts from the shipped one teaches agents a dead workflow.",
160
+ )
161
+ parser.add_argument(
162
+ "--skills-dir", default=None, metavar="DIR",
163
+ help="Where --install-skill writes (default: ~/.claude/skills).",
164
+ )
165
+ parser.add_argument(
166
+ "--force-skill", action="store_true",
167
+ help="With --install-skill: overwrite a differing installed copy "
168
+ "and remove files the package no longer ships. Without it, a "
169
+ "differing copy is refused with the list of differences.",
170
+ )
171
+ parser.add_argument(
172
+ "--target-path",
173
+ action="append",
174
+ metavar="TARGET=PATH",
175
+ help="Where a target's standing instructions go, e.g. "
176
+ "`--target-path bob=.bob/instructions.md`. Required for any agent "
177
+ "this tool has no built-in convention for; overrides the built-in "
178
+ "path for one it does. The target list will always trail the "
179
+ "market, and guessing a path writes a file the agent never opens.",
180
+ )
181
+ parser.add_argument(
182
+ "--target",
183
+ action="append",
184
+ help="Instruction target. Repeatable. Used with --init-agent-standards.",
185
+ )
186
+ parser.add_argument("--instructions-output-dir", default=".", help="Directory for generated instruction files.")
@@ -51,18 +51,42 @@ def attach_ratchet(report: dict, history_path: Path) -> None:
51
51
  report["dimension_ratchet"] = dimension_ratchet(read_history(history_path))
52
52
 
53
53
 
54
+ def attach_run_comparison(
55
+ args: argparse.Namespace, report: dict, history_path: Path
56
+ ) -> None:
57
+ """Compare this run of a named transformation with earlier ones.
58
+
59
+ Only when the operator named one: an unnamed run belongs to no series,
60
+ and inventing a series for it would be the tool answering a question
61
+ nobody asked.
62
+ """
63
+ label = getattr(args, "transformation", None)
64
+ if not label or not history_path.exists():
65
+ return
66
+ from ._run_comparison import compare_runs
67
+ from ._scan_history import read_history
68
+
69
+ report["run_comparison"] = compare_runs(read_history(history_path), label)
70
+
71
+
54
72
  def _attach_post_audit_records(
55
73
  args: argparse.Namespace, report: dict, history_path: Path
56
74
  ) -> None:
57
75
  """Records composed from the finished report, before it is rendered.
58
76
 
59
- Both read the report rather than the tree, and neither reaches scoring:
60
- whether a diff obeyed its work order, and whether a dimension slipped
61
- since the last comparable scan, are facts about a change and its
62
- history — not evidence about the code's condition.
77
+ All three read the report or the history rather than the tree, and none
78
+ reaches scoring: whether a diff obeyed its work order, whether a
79
+ dimension slipped since the last comparable scan, and how this run of a
80
+ transformation compares with earlier ones are facts about a change and
81
+ its history — not evidence about the code's condition.
82
+
83
+ The third is the only one that cannot fail a build. It is a report, by
84
+ design: "run seven moved further than run six" is worth knowing and is
85
+ not a thing to block a merge on.
63
86
  """
64
87
  attach_conformance(args, report)
65
88
  attach_ratchet(report, history_path)
89
+ attach_run_comparison(args, report, history_path)
66
90
 
67
91
 
68
92
  def _conformance_exit(args: argparse.Namespace, report: dict) -> int:
@@ -120,3 +120,49 @@ def escalations_markdown(escalated: list[dict[str, Any]] | None) -> list[str]:
120
120
  ])
121
121
  lines.append("")
122
122
  return lines
123
+
124
+
125
+ def run_comparison_markdown(comparison: dict[str, Any] | None) -> list[str]:
126
+ """The markdown section. Presentation only — it computes no score.
127
+
128
+ Empty for a run nobody named, which is most of them.
129
+ """
130
+ if not comparison:
131
+ return []
132
+ label = comparison["label"]
133
+ lines = [f"## Runs of `{label}`", ""]
134
+ runs = comparison["runs"]
135
+ if not runs:
136
+ return [*lines, comparison["trend"].get("reason", "No runs recorded."), ""]
137
+
138
+ lines += ["| Recorded | Commit | Estimate | Moved | Files | Declarations |",
139
+ "|---|---|---|---|---|---|"]
140
+ for run in runs:
141
+ estimate = "withheld" if run["estimate"] is None else f"{run['estimate']:.2f}"
142
+ moved = "—" if run["moved"] is None else f"{run['moved']:+.2f}"
143
+ populations = run["populations"]
144
+ lines.append(
145
+ f"| {run['recorded_at']} | `{(run['commit'] or '')[:8]}` | {estimate} | "
146
+ f"{moved} | {populations.get('files_scanned', '—')} | "
147
+ f"{populations.get('declarations_scanned', '—')} |"
148
+ )
149
+ lines.append("")
150
+
151
+ trend = comparison["trend"]
152
+ lines.append(
153
+ f"**{trend['summary']}.**" if trend.get("comparable")
154
+ else f"**Not established:** {trend['reason']}."
155
+ )
156
+ if comparison.get("excluded_earlier_runs"):
157
+ lines += ["", (
158
+ f"{comparison['excluded_earlier_runs']} earlier run(s) under this "
159
+ f"name are excluded: {comparison['exclusion_reason']}."
160
+ )]
161
+ lines += ["", (
162
+ "*`Moved` is the change in estimate between the previous recorded "
163
+ "scan and this one — the movement across that interval, not the "
164
+ "effect of the transformation. Anything else that happened in the "
165
+ "same interval is inside the number, and two runs of one "
166
+ "transformation land on different code.*"
167
+ ), ""]
168
+ return lines
@@ -0,0 +1,184 @@
1
+ """Did run seven of this transformation land better than run six?
2
+
3
+ The last of the remediation-integrity items, and the only one that is a
4
+ **report rather than a gate**. Where an agent performs one class of work
5
+ repeatedly — a framework upgrade, a migration, a codemod applied across
6
+ services — nobody measures whether the seventh run produced better code
7
+ than the sixth. The generator cannot answer it: its output is not
8
+ reproducible and it keeps no memory across runs. This tool has pinned
9
+ references, structured finding identity and scan history, so the
10
+ comparison is a join, not new machinery.
11
+
12
+ **What names a run.** Nothing in a tree says "this scan followed the React
13
+ 18 upgrade", so the operator says it: `--transformation react-18`. The
14
+ label rides on the scan record and groups runs into a series.
15
+
16
+ **What it measures, stated precisely because the temptation is to
17
+ overstate it.** For each labeled run, the movement between the *previous
18
+ scan in history* and that run. That is the movement across an interval,
19
+ and the transformation is what the operator says happened during that
20
+ interval. This module does not and cannot verify that claim: anything else
21
+ that happened in the same interval is inside the number. So the report
22
+ speaks of a run's *movement*, never of its *effect*, and never says one
23
+ run was "better" — it says one moved further than another, which is what
24
+ was actually measured.
25
+
26
+ **It refuses across an instrument change**, reusing `segments` exactly as
27
+ `_ratchet` does. Two scans taken under different calibration cannot be
28
+ subtracted, and a series that quietly spanned the 2.0 corpus extension
29
+ would have reported every transformation on earth as catastrophic. When
30
+ the newest labeled run sits in a different segment from its predecessors,
31
+ the earlier runs are named as excluded rather than dropped in silence:
32
+ a reader who cannot see the refusal will assume there was no history.
33
+
34
+ Nothing here reaches scoring, and nothing here fails a build.
35
+ """
36
+ from __future__ import annotations
37
+
38
+ from typing import Any
39
+
40
+ from ._scan_history import ScanRecord, segments
41
+
42
+ #: The same rounding boundary `_ratchet` uses, and for the same reason:
43
+ #: estimates are published to one decimal, so a smaller difference is the
44
+ #: rounding and not a movement.
45
+ TOLERANCE = 0.05
46
+
47
+
48
+ def _movement(previous: ScanRecord | None, current: ScanRecord) -> float | None:
49
+ """How far the estimate moved across the interval ending at `current`.
50
+
51
+ `None` where either end is missing an estimate. A withheld estimate is
52
+ not a zero — P7 withholds it precisely because the evidence did not
53
+ support a number, and subtracting from it would manufacture one.
54
+ """
55
+ if previous is None or previous.estimate is None or current.estimate is None:
56
+ return None
57
+ return round(current.estimate - previous.estimate, 3)
58
+
59
+
60
+ def _run_entry(
61
+ record: ScanRecord, previous: ScanRecord | None
62
+ ) -> dict[str, Any]:
63
+ return {
64
+ "recorded_at": record.recorded_at,
65
+ "commit": record.commit,
66
+ "scope": record.scope,
67
+ "estimate": record.estimate,
68
+ "evidence_status": record.evidence_status,
69
+ # Named so a reader can tell a movement in the code from a movement
70
+ # in what was measured: a run that doubled the tree is a different
71
+ # event from one that changed the same tree's condition.
72
+ "populations": dict(record.populations),
73
+ "moved": _movement(previous, record),
74
+ # A reconstructed scan carries today's tooling against an old
75
+ # commit, which is not the scan that would have happened then.
76
+ "backfilled": record.backfilled,
77
+ }
78
+
79
+
80
+ def _direction(difference: float) -> str:
81
+ """How to say it. Never "better" — see `_trend`."""
82
+ if abs(difference) < TOLERANCE:
83
+ return "within tolerance of"
84
+ return "further than" if difference > 0 else "less than"
85
+
86
+
87
+ def _trend(runs: list[dict[str, Any]]) -> dict[str, Any]:
88
+ """How the newest run's movement compares with the one before it.
89
+
90
+ Deliberately not called "better". Two runs of one codemod land on
91
+ different code, so a larger movement can come from the tree it was
92
+ applied to as easily as from the run. "Moved further" is what the
93
+ numbers support; "better" is a judgment about work this tool never saw.
94
+ """
95
+ movements = [run for run in runs if run["moved"] is not None]
96
+ if len(movements) < 2:
97
+ return {
98
+ "comparable": False,
99
+ "reason": (
100
+ "fewer than two runs in this series carry a movement, so "
101
+ "there is nothing to compare them on"
102
+ ),
103
+ }
104
+ latest, prior = movements[-1]["moved"], movements[-2]["moved"]
105
+ difference = round(latest - prior, 3)
106
+ direction = _direction(difference)
107
+ return {
108
+ "comparable": True,
109
+ "latest_moved": latest,
110
+ "previous_moved": prior,
111
+ "difference": difference,
112
+ "summary": (
113
+ f"the newest run moved {latest:+.2f}, {direction} the "
114
+ f"{prior:+.2f} of the run before it"
115
+ ),
116
+ }
117
+
118
+
119
+ def _segment_holding(records: list[ScanRecord], wanted: ScanRecord) -> Any:
120
+ """The instrument-segment containing one record.
121
+
122
+ Membership is by **identity**, not equality: two scans of an unchanged
123
+ tree differ only in their timestamp, and an equality test would find
124
+ the wrong one — silently attributing a run to the wrong instrument.
125
+ """
126
+ return next(
127
+ segment for segment in segments(records)
128
+ if any(item is wanted for item in segment.records)
129
+ )
130
+
131
+
132
+ def _entries_within(segment: Any, labelled: list[ScanRecord]) -> list[dict[str, Any]]:
133
+ """The labelled runs inside this segment, each with its predecessor.
134
+
135
+ A run's predecessor is the scan immediately before it *in the
136
+ segment*, whatever that scan was labelled — the movement being
137
+ measured is across the interval, not between two runs of the same
138
+ name.
139
+ """
140
+ order = {id(record): index for index, record in enumerate(segment.records)}
141
+ return [
142
+ _run_entry(
143
+ record,
144
+ segment.records[order[id(record)] - 1] if order[id(record)] else None,
145
+ )
146
+ for record in labelled if id(record) in order
147
+ ]
148
+
149
+
150
+ def compare_runs(records: list[ScanRecord], label: str) -> dict[str, Any]:
151
+ """Every recorded run of one transformation, and how the last two differ.
152
+
153
+ The current scan is already in `records` when this is called — history
154
+ is appended before the post-audit records are attached — so the newest
155
+ labeled run is this one.
156
+ """
157
+ labelled = [record for record in records if record.transformation == label]
158
+ if not labelled:
159
+ return {
160
+ "label": label,
161
+ "runs": [],
162
+ "excluded_earlier_runs": 0,
163
+ "trend": {
164
+ "comparable": False,
165
+ "reason": f"no scan has been recorded under the name {label!r}",
166
+ },
167
+ }
168
+
169
+ current = _segment_holding(records, labelled[-1])
170
+ runs = _entries_within(current, labelled)
171
+ excluded = len(labelled) - len(runs)
172
+
173
+ comparison = {
174
+ "label": label,
175
+ "runs": runs,
176
+ "excluded_earlier_runs": excluded,
177
+ "trend": _trend(runs),
178
+ }
179
+ if excluded:
180
+ comparison["exclusion_reason"] = (
181
+ current.break_reason
182
+ or "those runs were produced by a different instrument"
183
+ )
184
+ return comparison