maintainability-agent 2.4.0__tar.gz → 2.4.1__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 (315) hide show
  1. {maintainability_agent-2.4.0/src/maintainability_agent.egg-info → maintainability_agent-2.4.1}/PKG-INFO +43 -5
  2. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/README.md +42 -4
  3. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/pyproject.toml +1 -1
  4. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1/src/maintainability_agent.egg-info}/PKG-INFO +43 -5
  5. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_agent.egg-info/SOURCES.txt +1 -0
  6. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/__init__.py +1 -1
  7. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_config_defaults.py +1 -0
  8. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/config.py +1 -1
  9. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_claimed_languages.py +18 -0
  10. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_mcp_server.py +8 -6
  11. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_population_floors.py +30 -0
  12. maintainability_agent-2.4.1/tests/test_suite_isolation.py +139 -0
  13. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/LICENSE +0 -0
  14. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/setup.cfg +0 -0
  15. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_agent.egg-info/dependency_links.txt +0 -0
  16. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_agent.egg-info/entry_points.txt +0 -0
  17. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_agent.egg-info/requires.txt +0 -0
  18. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_agent.egg-info/top_level.txt +0 -0
  19. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/__main__.py +0 -0
  20. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_adapters.py +0 -0
  21. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_analysis.py +0 -0
  22. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_aspects.py +0 -0
  23. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_assets/analyzer-catalog.json +0 -0
  24. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_assets/standard.md +0 -0
  25. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_attestation.py +0 -0
  26. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_backfill.py +0 -0
  27. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_bands.py +0 -0
  28. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_built_ins.py +0 -0
  29. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_calibration.py +0 -0
  30. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_catalog.py +0 -0
  31. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_charts.py +0 -0
  32. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_cognitive.py +0 -0
  33. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_conformance.py +0 -0
  34. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_corroborate.py +0 -0
  35. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_coverage_notes.py +0 -0
  36. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_derive.py +0 -0
  37. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_discovery.py +0 -0
  38. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_documents.py +0 -0
  39. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_economics.py +0 -0
  40. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_economics_view.py +0 -0
  41. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_environment.py +0 -0
  42. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_evidence_view.py +0 -0
  43. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_finding_match.py +0 -0
  44. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_first_run.py +0 -0
  45. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_formula.py +0 -0
  46. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_gates.py +0 -0
  47. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_generic.py +0 -0
  48. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_grant_ledger.py +0 -0
  49. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_history_view.py +0 -0
  50. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_hostile_prompt.py +0 -0
  51. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_hotspots.py +0 -0
  52. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_html_report_sections.py +0 -0
  53. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_html_view.py +0 -0
  54. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_identity.py +0 -0
  55. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_jvm_adapters.py +0 -0
  56. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_markdown_sections.py +0 -0
  57. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_masking.py +0 -0
  58. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_mcp_audit.py +0 -0
  59. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_mcp_gate.py +0 -0
  60. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_mcp_grants.py +0 -0
  61. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_mcp_refusals.py +0 -0
  62. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_mcp_resources.py +0 -0
  63. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_mcp_setup.py +0 -0
  64. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_metric_adapters.py +0 -0
  65. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_metrics_types.py +0 -0
  66. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_pillars.py +0 -0
  67. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_practice.py +0 -0
  68. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_pressures.py +0 -0
  69. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_ranges_c.py +0 -0
  70. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_ranges_core.py +0 -0
  71. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_ranges_cpp.py +0 -0
  72. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_ranges_csharp.py +0 -0
  73. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_ranges_fortran.py +0 -0
  74. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_ranges_java.py +0 -0
  75. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_ranges_js.py +0 -0
  76. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_ranges_swift.py +0 -0
  77. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_ratchet.py +0 -0
  78. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_recurrence.py +0 -0
  79. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_runner.py +0 -0
  80. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_safe_write.py +0 -0
  81. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_scan_history.py +0 -0
  82. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_scan_view.py +0 -0
  83. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_second_source.py +0 -0
  84. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_selection.py +0 -0
  85. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_semantic.py +0 -0
  86. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_semantic_policy.py +0 -0
  87. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_semantic_ts.py +0 -0
  88. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_semantic_view.py +0 -0
  89. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_setup_errors.py +0 -0
  90. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_setup_persist.py +0 -0
  91. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_skill_data/SKILL.md +0 -0
  92. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_skill_data/agents/anthropic.yaml +0 -0
  93. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_skill_data/agents/copilot.yaml +0 -0
  94. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_skill_data/agents/openai.yaml +0 -0
  95. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_skill_data/copilot/maintainability-agent.prompt.md +0 -0
  96. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_skill_data/references/finding-taxonomy.md +0 -0
  97. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_skill_install.py +0 -0
  98. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_stored_grants.py +0 -0
  99. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_tdd_view.py +0 -0
  100. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_test_execution.py +0 -0
  101. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_test_pairing.py +0 -0
  102. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_tokens.py +0 -0
  103. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_tool_adapters.py +0 -0
  104. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_trends.py +0 -0
  105. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_user_config.py +0 -0
  106. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_verdict_adapters.py +0 -0
  107. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_verification.py +0 -0
  108. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_work_order.py +0 -0
  109. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_work_order_view.py +0 -0
  110. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_work_order_weights.py +0 -0
  111. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/_xml.py +0 -0
  112. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/baseline.py +0 -0
  113. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/cli.py +0 -0
  114. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/deadcode.py +0 -0
  115. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/declarations.py +0 -0
  116. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/duplication.py +0 -0
  117. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/evidence.py +0 -0
  118. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/git_tools.py +0 -0
  119. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/history.py +0 -0
  120. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/idioms.py +0 -0
  121. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/instructions.py +0 -0
  122. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/mcp_server.py +0 -0
  123. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/metrics.py +0 -0
  124. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/prompts.py +0 -0
  125. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/renderers.py +0 -0
  126. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/report.py +0 -0
  127. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/sarif.py +0 -0
  128. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/scoring.py +0 -0
  129. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/similarity.py +0 -0
  130. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/src/maintainability_audit/source.py +0 -0
  131. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_acquisition_trust.py +0 -0
  132. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_adapter_docs.py +0 -0
  133. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_adapter_recordings.py +0 -0
  134. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_adapters.py +0 -0
  135. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_added_lines.py +0 -0
  136. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_analysis_coverage.py +0 -0
  137. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_analysis_execution.py +0 -0
  138. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_analyzer_bridge.py +0 -0
  139. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_analyzer_config_isolation.py +0 -0
  140. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_analyzer_estimate_claims.py +0 -0
  141. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_analyzer_pinning.py +0 -0
  142. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_analyzer_primary_estimate.py +0 -0
  143. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_analyzer_provenance.py +0 -0
  144. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_analyzer_provenance_exclusions.py +0 -0
  145. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_analyzer_scoring_path.py +0 -0
  146. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_analyzer_spread_range.py +0 -0
  147. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_analyzer_xml_bounds.py +0 -0
  148. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_annotations_match_behaviour.py +0 -0
  149. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_anticipated_refusals.py +0 -0
  150. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_architecture.py +0 -0
  151. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_artifact_write_route_class.py +0 -0
  152. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_aspect_coverage.py +0 -0
  153. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_asset_snapshot_class.py +0 -0
  154. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_ast_reading_resolves_spellings.py +0 -0
  155. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_attestation.py +0 -0
  156. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_audit_components.py +0 -0
  157. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_authorization_freshness.py +0 -0
  158. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_authorship_gates.py +0 -0
  159. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_backfill.py +0 -0
  160. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_band_concealment_class.py +0 -0
  161. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_band_concealment_p3.py +0 -0
  162. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_band_pressures.py +0 -0
  163. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_bands.py +0 -0
  164. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_body_or_signature_class.py +0 -0
  165. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_c_declarations.py +0 -0
  166. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_calibration_corpus.py +0 -0
  167. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_calibration_drift.py +0 -0
  168. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_calibration_tooling.py +0 -0
  169. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_catalog_selection.py +0 -0
  170. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_catalog_tier_promise.py +0 -0
  171. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_chat_primary_docs.py +0 -0
  172. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_checkstyle_adapter.py +0 -0
  173. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_checkstyle_catalog.py +0 -0
  174. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_ci_history_recipe.py +0 -0
  175. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_ci_installs_the_analyzer_pool.py +0 -0
  176. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_cli.py +0 -0
  177. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_clone_group_class.py +0 -0
  178. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_cognitive_complexity.py +0 -0
  179. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_cohort_statistics.py +0 -0
  180. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_concealment_properties.py +0 -0
  181. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_config_shape.py +0 -0
  182. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_consent_and_grant.py +0 -0
  183. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_consumer_migration.py +0 -0
  184. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_contract_claims.py +0 -0
  185. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_corroborate.py +0 -0
  186. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_coverage_by_language.py +0 -0
  187. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_cpp_declarations.py +0 -0
  188. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_csharp_declarations.py +0 -0
  189. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_d15_composition.py +0 -0
  190. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_d15_goal_directed.py +0 -0
  191. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_dead_code.py +0 -0
  192. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_declaration_edge_cases.py +0 -0
  193. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_declaration_grading.py +0 -0
  194. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_declaration_ranges.py +0 -0
  195. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_declaration_source.py +0 -0
  196. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_declared_authorship.py +0 -0
  197. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_declared_imports.py +0 -0
  198. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_derivation_mix.py +0 -0
  199. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_determinism.py +0 -0
  200. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_dimension_ratchet.py +0 -0
  201. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_direct_runner_availability_class.py +0 -0
  202. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_discovery.py +0 -0
  203. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_doc_claims.py +0 -0
  204. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_docs_links.py +0 -0
  205. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_economic_context.py +0 -0
  206. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_empty_output_not_clean.py +0 -0
  207. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_empty_output_not_clean_adapters.py +0 -0
  208. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_environment_work_order.py +0 -0
  209. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_evidence_invariants.py +0 -0
  210. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_evidence_normalization.py +0 -0
  211. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_evidence_properties.py +0 -0
  212. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_exclusion_dialects.py +0 -0
  213. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_falsifier_standard.py +0 -0
  214. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_file_list_cap_class.py +0 -0
  215. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_finding_identity.py +0 -0
  216. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_first_run_elicitation.py +0 -0
  217. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_first_run_prompt.py +0 -0
  218. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_first_run_reelicitation.py +0 -0
  219. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_fix_breadth_window.py +0 -0
  220. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_fixed_form_fortran.py +0 -0
  221. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_format_ask.py +0 -0
  222. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_fortran_declarations.py +0 -0
  223. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_fortran_metrics.py +0 -0
  224. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_fortran_practice.py +0 -0
  225. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_git_argv.py +0 -0
  226. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_git_read_only.py +0 -0
  227. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_git_readonly_class.py +0 -0
  228. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_grant_only_user_tier.py +0 -0
  229. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_history.py +0 -0
  230. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_history_boundary.py +0 -0
  231. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_history_manifest.py +0 -0
  232. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_history_schema2.py +0 -0
  233. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_history_window.py +0 -0
  234. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_hostile_prompt.py +0 -0
  235. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_html_executive.py +0 -0
  236. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_html_section_parity_class.py +0 -0
  237. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_identity_docs.py +0 -0
  238. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_identity_resolution.py +0 -0
  239. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_idiom_divergence.py +0 -0
  240. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_installed_wheel_runtime.py +0 -0
  241. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_instruction_targets.py +0 -0
  242. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_java_range_guard.py +0 -0
  243. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_java_ranges.py +0 -0
  244. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_java_scored.py +0 -0
  245. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_java_wiring.py +0 -0
  246. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_js_complexity_operators.py +0 -0
  247. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_js_declarations.py +0 -0
  248. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_language_coverage.py +0 -0
  249. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_mcp_baseline_payload.py +0 -0
  250. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_mcp_history.py +0 -0
  251. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_migration_1_0.py +0 -0
  252. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_near_duplicates.py +0 -0
  253. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_network_disclosure.py +0 -0
  254. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_one_setup_across_surfaces_class.py +0 -0
  255. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_pattern_budget.py +0 -0
  256. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_phase6_claims.py +0 -0
  257. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_pillars_and_practice.py +0 -0
  258. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_platform_claim.py +0 -0
  259. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_pmd_adapter.py +0 -0
  260. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_pmd_audit_closures.py +0 -0
  261. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_pool_runs_by_config.py +0 -0
  262. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_practice_nested_gates_class.py +0 -0
  263. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_presentation_refusals.py +0 -0
  264. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_promises.py +0 -0
  265. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_prompt_escalation_once.py +0 -0
  266. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_prompt_honesty.py +0 -0
  267. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_prompt_location_escalation_class.py +0 -0
  268. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_prove_falsifiers.py +0 -0
  269. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_python_declarations.py +0 -0
  270. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_read_boundary.py +0 -0
  271. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_readme_claims.py +0 -0
  272. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_recurrence.py +0 -0
  273. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_release_plan.py +0 -0
  274. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_release_plan_status.py +0 -0
  275. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_report_remedy_copy.py +0 -0
  276. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_roles_recorded.py +0 -0
  277. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_root_grants.py +0 -0
  278. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_rubric_ignores_project_lint_config.py +0 -0
  279. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_runner.py +0 -0
  280. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_sarif.py +0 -0
  281. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_scan_history.py +0 -0
  282. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_scan_scope.py +0 -0
  283. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_scanning.py +0 -0
  284. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_schema_fidelity.py +0 -0
  285. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_scope_conformance.py +0 -0
  286. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_scoring_calibration.py +0 -0
  287. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_semantic_policy.py +0 -0
  288. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_setup_gate_completeness.py +0 -0
  289. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_setup_gate_independent_contract.py +0 -0
  290. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_setup_precondition.py +0 -0
  291. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_skill_install.py +0 -0
  292. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_source_index.py +0 -0
  293. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_spotbugs_adapter.py +0 -0
  294. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_spotbugs_catalog.py +0 -0
  295. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_stage8_contract.py +0 -0
  296. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_swift_declarations.py +0 -0
  297. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_tdd_structure.py +0 -0
  298. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_test_execution_class.py +0 -0
  299. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_three_presentations.py +0 -0
  300. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_trends.py +0 -0
  301. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_type_fields_not_functions_class.py +0 -0
  302. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_uat_falsifiers.py +0 -0
  303. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_unread_code.py +0 -0
  304. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_user_config_tier.py +0 -0
  305. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_verification_audit_closures.py +0 -0
  306. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_verified_grade.py +0 -0
  307. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_version_claim.py +0 -0
  308. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_wheel_contents.py +0 -0
  309. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_work_order.py +0 -0
  310. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_work_order_items.py +0 -0
  311. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_work_order_selection.py +0 -0
  312. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_workflow_supply_chain.py +0 -0
  313. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_write_boundary.py +0 -0
  314. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/tests/test_write_route_class.py +0 -0
  315. {maintainability_agent-2.4.0 → maintainability_agent-2.4.1}/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.4.0
3
+ Version: 2.4.1
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.4.0**.
47
+ Version **2.4.1**.
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
@@ -124,9 +124,12 @@ the independent check on their own work, so a platform that generates code and
124
124
  grades it is producing a self-assessment — a property of the arrangement, not a
125
125
  criticism of any one of them. This writes nothing and runs no model, which is
126
126
  what lets its verdict be evidence ([the principle](docs/philosophy.md#principles)).
127
- The limit, stated in the same breath: step 3 bounds the agent by **instruction**,
128
- and nothing yet verifies the returned diff stayed inside the work order
129
- ([the three checks that would](docs/roadmap.md#the-remediation-hole-an-agent-can-satisfy-this-gate-without-doing-the-work)).
127
+ Since 2.1.0 the work order is also **checked**: `--conformance` compares the
128
+ returned diff against the paths the report named, `--fail-on-regression`
129
+ ratchets the dimension scores, and `--attestation-output` composes them into one
130
+ record ([how that hole was closed](docs/roadmap.md#the-remediation-hole-closed-in-210-through-230)).
131
+ The limit, stated in the same breath: those checks read the diff's **shape**,
132
+ never its correctness — whether the change works is not a claim this tool makes.
130
133
 
131
134
  One pre-registered experiment has tested the bounded prompt.
132
135
  Generic prompting made 2 of 6 repositories worse; bounded prompting made 1 of 6 worse and improved 5 of 6, under this tool's own finding count.
@@ -217,6 +220,41 @@ withheld estimate. For PR work, add `--changed-only main...HEAD` to audit the
217
220
  diff; on a change too small to support a rate, the estimate and grade are
218
221
  withheld and the scope is named as the reason.
219
222
 
223
+ ### Checking that the agent did the work
224
+
225
+ 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:
228
+
229
+ ```bash
230
+ maintainability-agent \
231
+ --config maintainability-agent.json \
232
+ --conformance main...HEAD \
233
+ --fail-on-out-of-scope \
234
+ --fail-on-regression \
235
+ --attestation-output maintainability-attestation.md
236
+ ```
237
+
238
+ - **`--conformance <revspec>`** compares the diff against the paths the report
239
+ named, and answers two questions separately: did it **stay in scope**, and did
240
+ it **silence nothing**. They stay separate because a change can obey the work
241
+ order and still add a `# noqa` to a finding inside it. A test added for a fix
242
+ stays in scope even though the work order never named the test file.
243
+ - **`--fail-on-out-of-scope`** turns that into a CI failure.
244
+ - **`--fail-on-regression`** ratchets the _dimension_ scores against scan
245
+ history, catching a change that improves one dimension while silently
246
+ regressing another. It has three outcomes, not two — held, regressed, and
247
+ **not comparable**, because two scans taken under different calibration cannot
248
+ be differenced.
249
+ - **`--attestation-output`** writes the three into one per-change record: what
250
+ was measured, what the agent was told to change, whether it stayed inside the
251
+ work order, and what moved. It is reproducible and **not signed** — nothing
252
+ here holds a key, and the document says so in its own text. A check nobody ran
253
+ renders as _not asked_, never as passed.
254
+
255
+ The [roadmap](docs/roadmap.md#the-remediation-hole-closed-in-210-through-230)
256
+ has the history of why this was the hole under the product's central claim.
257
+
220
258
  ## What it analyzes
221
259
 
222
260
  The deterministic scanner reads code from your repo (no LLM calls) and produces
@@ -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.4.0**.
8
+ Version **2.4.1**.
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
@@ -85,9 +85,12 @@ the independent check on their own work, so a platform that generates code and
85
85
  grades it is producing a self-assessment — a property of the arrangement, not a
86
86
  criticism of any one of them. This writes nothing and runs no model, which is
87
87
  what lets its verdict be evidence ([the principle](docs/philosophy.md#principles)).
88
- The limit, stated in the same breath: step 3 bounds the agent by **instruction**,
89
- and nothing yet verifies the returned diff stayed inside the work order
90
- ([the three checks that would](docs/roadmap.md#the-remediation-hole-an-agent-can-satisfy-this-gate-without-doing-the-work)).
88
+ Since 2.1.0 the work order is also **checked**: `--conformance` compares the
89
+ returned diff against the paths the report named, `--fail-on-regression`
90
+ ratchets the dimension scores, and `--attestation-output` composes them into one
91
+ record ([how that hole was closed](docs/roadmap.md#the-remediation-hole-closed-in-210-through-230)).
92
+ The limit, stated in the same breath: those checks read the diff's **shape**,
93
+ never its correctness — whether the change works is not a claim this tool makes.
91
94
 
92
95
  One pre-registered experiment has tested the bounded prompt.
93
96
  Generic prompting made 2 of 6 repositories worse; bounded prompting made 1 of 6 worse and improved 5 of 6, under this tool's own finding count.
@@ -178,6 +181,41 @@ withheld estimate. For PR work, add `--changed-only main...HEAD` to audit the
178
181
  diff; on a change too small to support a rate, the estimate and grade are
179
182
  withheld and the scope is named as the reason.
180
183
 
184
+ ### Checking that the agent did the work
185
+
186
+ 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:
189
+
190
+ ```bash
191
+ maintainability-agent \
192
+ --config maintainability-agent.json \
193
+ --conformance main...HEAD \
194
+ --fail-on-out-of-scope \
195
+ --fail-on-regression \
196
+ --attestation-output maintainability-attestation.md
197
+ ```
198
+
199
+ - **`--conformance <revspec>`** compares the diff against the paths the report
200
+ named, and answers two questions separately: did it **stay in scope**, and did
201
+ it **silence nothing**. They stay separate because a change can obey the work
202
+ order and still add a `# noqa` to a finding inside it. A test added for a fix
203
+ stays in scope even though the work order never named the test file.
204
+ - **`--fail-on-out-of-scope`** turns that into a CI failure.
205
+ - **`--fail-on-regression`** ratchets the _dimension_ scores against scan
206
+ history, catching a change that improves one dimension while silently
207
+ regressing another. It has three outcomes, not two — held, regressed, and
208
+ **not comparable**, because two scans taken under different calibration cannot
209
+ be differenced.
210
+ - **`--attestation-output`** writes the three into one per-change record: what
211
+ was measured, what the agent was told to change, whether it stayed inside the
212
+ work order, and what moved. It is reproducible and **not signed** — nothing
213
+ here holds a key, and the document says so in its own text. A check nobody ran
214
+ renders as _not asked_, never as passed.
215
+
216
+ The [roadmap](docs/roadmap.md#the-remediation-hole-closed-in-210-through-230)
217
+ has the history of why this was the hole under the product's central claim.
218
+
181
219
  ## What it analyzes
182
220
 
183
221
  The deterministic scanner reads code from your repo (no LLM calls) and produces
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "maintainability-agent"
7
- version = "2.4.0"
7
+ version = "2.4.1"
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.4.0
3
+ Version: 2.4.1
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.4.0**.
47
+ Version **2.4.1**.
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
@@ -124,9 +124,12 @@ the independent check on their own work, so a platform that generates code and
124
124
  grades it is producing a self-assessment — a property of the arrangement, not a
125
125
  criticism of any one of them. This writes nothing and runs no model, which is
126
126
  what lets its verdict be evidence ([the principle](docs/philosophy.md#principles)).
127
- The limit, stated in the same breath: step 3 bounds the agent by **instruction**,
128
- and nothing yet verifies the returned diff stayed inside the work order
129
- ([the three checks that would](docs/roadmap.md#the-remediation-hole-an-agent-can-satisfy-this-gate-without-doing-the-work)).
127
+ Since 2.1.0 the work order is also **checked**: `--conformance` compares the
128
+ returned diff against the paths the report named, `--fail-on-regression`
129
+ ratchets the dimension scores, and `--attestation-output` composes them into one
130
+ record ([how that hole was closed](docs/roadmap.md#the-remediation-hole-closed-in-210-through-230)).
131
+ The limit, stated in the same breath: those checks read the diff's **shape**,
132
+ never its correctness — whether the change works is not a claim this tool makes.
130
133
 
131
134
  One pre-registered experiment has tested the bounded prompt.
132
135
  Generic prompting made 2 of 6 repositories worse; bounded prompting made 1 of 6 worse and improved 5 of 6, under this tool's own finding count.
@@ -217,6 +220,41 @@ withheld estimate. For PR work, add `--changed-only main...HEAD` to audit the
217
220
  diff; on a change too small to support a rate, the estimate and grade are
218
221
  withheld and the scope is named as the reason.
219
222
 
223
+ ### Checking that the agent did the work
224
+
225
+ 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:
228
+
229
+ ```bash
230
+ maintainability-agent \
231
+ --config maintainability-agent.json \
232
+ --conformance main...HEAD \
233
+ --fail-on-out-of-scope \
234
+ --fail-on-regression \
235
+ --attestation-output maintainability-attestation.md
236
+ ```
237
+
238
+ - **`--conformance <revspec>`** compares the diff against the paths the report
239
+ named, and answers two questions separately: did it **stay in scope**, and did
240
+ it **silence nothing**. They stay separate because a change can obey the work
241
+ order and still add a `# noqa` to a finding inside it. A test added for a fix
242
+ stays in scope even though the work order never named the test file.
243
+ - **`--fail-on-out-of-scope`** turns that into a CI failure.
244
+ - **`--fail-on-regression`** ratchets the _dimension_ scores against scan
245
+ history, catching a change that improves one dimension while silently
246
+ regressing another. It has three outcomes, not two — held, regressed, and
247
+ **not comparable**, because two scans taken under different calibration cannot
248
+ be differenced.
249
+ - **`--attestation-output`** writes the three into one per-change record: what
250
+ was measured, what the agent was told to change, whether it stayed inside the
251
+ work order, and what moved. It is reproducible and **not signed** — nothing
252
+ here holds a key, and the document says so in its own text. A check nobody ran
253
+ renders as _not asked_, never as passed.
254
+
255
+ The [roadmap](docs/roadmap.md#the-remediation-hole-closed-in-210-through-230)
256
+ has the history of why this was the hole under the product's central claim.
257
+
220
258
  ## What it analyzes
221
259
 
222
260
  The deterministic scanner reads code from your repo (no LLM calls) and produces
@@ -290,6 +290,7 @@ tests/test_source_index.py
290
290
  tests/test_spotbugs_adapter.py
291
291
  tests/test_spotbugs_catalog.py
292
292
  tests/test_stage8_contract.py
293
+ tests/test_suite_isolation.py
293
294
  tests/test_swift_declarations.py
294
295
  tests/test_tdd_structure.py
295
296
  tests/test_test_execution_class.py
@@ -1,3 +1,3 @@
1
1
  """Maintainability Audit CI."""
2
2
 
3
- __version__ = "2.4.0"
3
+ __version__ = "2.4.1"
@@ -45,6 +45,7 @@ DEFAULT_CONFIG: dict[str, Any] = {
45
45
  ".py", ".java", ".c", ".h",
46
46
  ".cpp", ".hpp", ".cc", ".cxx", ".hh",
47
47
  ".cs",
48
+ ".swift",
48
49
  ".f90", ".f95", ".f03", ".f08",
49
50
  ".F90", ".F95", ".F03", ".F08", ".pf",
50
51
  ".f", ".for", ".ftn", ".F", ".FOR", ".FTN",
@@ -11,7 +11,7 @@ from ._config_defaults import DEFAULT_CONFIG, DEFAULT_IDIOM_GROUPS
11
11
  # still the door every caller comes through.
12
12
  __all__ = ["DEFAULT_CONFIG", "DEFAULT_IDIOM_GROUPS", "PROJECT_URL", "VERSION"]
13
13
 
14
- VERSION = "2.4.0"
14
+ VERSION = "2.4.1"
15
15
 
16
16
  PROJECT_URL = "https://github.com/marshallguillory86/maintainability-agent"
17
17
 
@@ -89,6 +89,24 @@ def test_every_scanned_source_suffix_can_be_read_by_something() -> None:
89
89
  "population would be a number nobody measured"
90
90
  )
91
91
 
92
+ # The other direction, which was missing and cost 2.4.0 its language.
93
+ # Swift shipped in `DECLARATION_SUFFIXES`, in `SCANNERS`, in the README
94
+ # table and in `language-support.md` — and not in the default
95
+ # `include_extensions`, so no `.swift` file was ever opened. The scanner
96
+ # was correct, tested, documented, and unreachable: an audit of a Swift
97
+ # repository found zero Swift files and withheld its rates, which is
98
+ # indistinguishable from not supporting the language at all.
99
+ #
100
+ # Caught by a corpus run reporting `vapor/vapor` as three files, not by
101
+ # any test, because every test that could have caught it exercised the
102
+ # scanner directly rather than through the configuration a user gets.
103
+ unopened = sorted(DECLARATION_SUFFIXES - included)
104
+ assert not unopened, (
105
+ f"{unopened} are parsed but absent from the default "
106
+ "include_extensions, so no such file is ever opened; the language "
107
+ "is claimed and unreachable"
108
+ )
109
+
92
110
 
93
111
  # One sample of real source per claimed language, by suffix. This was a
94
112
  # chain of nested conditionals until 1.4.0, when the fifth language took
@@ -4,7 +4,6 @@ from __future__ import annotations
4
4
 
5
5
  import asyncio
6
6
  import json
7
- import os
8
7
  import subprocess
9
8
  import sys
10
9
  from pathlib import Path
@@ -159,12 +158,15 @@ def test_a_client_sees_the_two_tools_and_can_call_one(tmp_path: Path) -> None:
159
158
  def _child_import_path() -> str:
160
159
  """This process's own import path, for the child to inherit.
161
160
 
162
- Derived from `sys.path` rather than assumed, so the subprocess
163
- imports exactly what the test process is exercising: the package
164
- under test (from `src/` in a checkout, site-packages when installed)
165
- *and* the `mcp` SDK it needs to answer at all.
161
+ The MCP SDK spawns with a scrubbed environment rather than an
162
+ inherited one, so this seam needs the value passed explicitly even
163
+ though `conftest` now puts it in `os.environ` for every other child.
164
+ It is the same value, from the same place, for the same reason —
165
+ `conftest.child_import_path` carries the full account.
166
166
  """
167
- return os.pathsep.join(entry for entry in sys.path if entry)
167
+ from conftest import child_import_path
168
+
169
+ return child_import_path()
168
170
 
169
171
 
170
172
  def test_real_stdio_process_initializes_and_reports_its_boundary(tmp_path: Path) -> None:
@@ -44,6 +44,36 @@ pytestmark = pytest.mark.usefixtures("real_population_floors")
44
44
  CORPUS = Path(__file__).resolve().parent.parent / "tools" / "calibration" / "corpus.json"
45
45
 
46
46
 
47
+ def test_the_shipped_floors_are_the_corpus_minima() -> None:
48
+ """The suite lifts the floors; this pins what it lifted.
49
+
50
+ Without it, a floor could be raised above a calibration member's
51
+ population and no test would notice, because every other test runs
52
+ with the floors disabled.
53
+
54
+ It lived in `conftest.py` and was therefore never collected — pytest
55
+ loads a conftest as a plugin, not as a test module — so for as long as
56
+ it existed it asserted nothing. It is compared against
57
+ `conftest.SHIPPED_FLOORS`, captured at import before any fixture
58
+ touches the table, rather than against the live module attribute this
59
+ file's own `real_population_floors` fixture restores.
60
+
61
+ Covers existing behaviour: the floors and the corpus it checks them
62
+ against are both older than this change, which only moves the
63
+ assertion somewhere pytest will run it. It cannot fail at the base
64
+ for the plainest possible reason — at the base it is not collected,
65
+ so there is nothing there to fail.
66
+ """
67
+ from conftest import SHIPPED_FLOORS
68
+
69
+ repos = json.loads(CORPUS.read_text(encoding="utf-8"))["repos"]
70
+ assert SHIPPED_FLOORS["files_scanned"] <= min(r["source_files"] for r in repos)
71
+ assert SHIPPED_FLOORS["declarations_scanned"] <= min(r["declarations"] for r in repos)
72
+ assert all(value > 0 for value in SHIPPED_FLOORS.values()), (
73
+ "a zero floor ships nothing; the hello-world A+ comes straight back"
74
+ )
75
+
76
+
47
77
  def _repo(tmp_path: Path, files: int, decls_per_file: int = 1) -> Path:
48
78
  root = tmp_path / "r"
49
79
  root.mkdir(parents=True)
@@ -0,0 +1,139 @@
1
+ """The suite's own isolation, tested where the tests actually run.
2
+
3
+ Every assertion here is about the harness rather than the product: that a
4
+ fixture repository cannot read the developer's git configuration, and that
5
+ a spawned subprocess imports the same package this process did. Both are
6
+ properties of `conftest.py`, and both were *written* in `conftest.py` —
7
+ where pytest never collected them, because a conftest is a plugin module
8
+ and not a test module. `python_files` defaults to `test_*.py` and
9
+ `*_test.py`; `conftest.py` matches neither.
10
+
11
+ So the guard for the git-isolation fixture, with its careful docstring
12
+ about how the first attempt at that fix had been too narrow, had never
13
+ run once. It is the failure mode this project keeps meeting in new
14
+ costumes — a check narrower than the promise, a guard that reads one
15
+ direction, an assertion nothing executes — and the cheapest of the three
16
+ to miss, because a test that is never collected cannot go red.
17
+
18
+ `test_the_isolation_guards_are_collected` below is the guard on the
19
+ guards: it fails if these move back somewhere pytest will not look.
20
+ """
21
+
22
+ from __future__ import annotations
23
+
24
+ import os
25
+ import subprocess
26
+ import sys
27
+ from pathlib import Path
28
+
29
+ DEVELOPER_HOME = Path(os.path.expanduser("~")).resolve()
30
+ """Captured at import, which is before the session fixture moves `HOME`.
31
+
32
+ Reading it later would return the fixture's temporary home and the leak
33
+ check below would compare against the wrong string — passing always, which
34
+ is the same defect as not being collected.
35
+ """
36
+
37
+
38
+ def test_no_git_in_this_suite_reads_developer_configuration(tmp_path: Path) -> None:
39
+ """The isolation holds, for any setting rather than a listed few.
40
+
41
+ Asserting on the *origin* of every setting is what makes this a guard
42
+ against the class. A test that only checked `commit.gpgsign` would pass
43
+ while `init.templateDir` was still installing hooks — which is precisely
44
+ how the first attempt at that fix was wrong.
45
+ """
46
+ repo = tmp_path / "probe"
47
+ repo.mkdir()
48
+ subprocess.run(["git", "init", "-q"], cwd=repo, check=True)
49
+
50
+ origins = subprocess.run(
51
+ ["git", "config", "--list", "--show-origin"],
52
+ cwd=repo, text=True, capture_output=True, check=True,
53
+ ).stdout
54
+ leaked = [line for line in origins.splitlines() if str(DEVELOPER_HOME) in line]
55
+ assert not leaked, f"developer configuration reached a fixture git: {leaked}"
56
+
57
+ hooks = repo / ".git" / "hooks"
58
+ installed = [entry.name for entry in hooks.iterdir() if entry.suffix != ".sample"]
59
+ assert not installed, (
60
+ f"init.templateDir installed hooks into a fixture repository: {installed}"
61
+ )
62
+
63
+ # Not "unset": `_git_never_maintains_the_fixtures` sets these to false
64
+ # unconditionally. The requirement is that a fixture never *tries* to
65
+ # sign, whichever layer delivers that.
66
+ for setting in ("commit.gpgsign", "tag.gpgsign"):
67
+ value = subprocess.run(
68
+ ["git", "config", "--get", setting],
69
+ cwd=repo, text=True, capture_output=True, check=False,
70
+ ).stdout.strip()
71
+ assert value in ("", "false"), (
72
+ f"a fixture repository would attempt to sign: {setting}={value}"
73
+ )
74
+
75
+
76
+ def test_a_spawned_child_imports_the_same_package_this_process_did() -> None:
77
+ """Parent and child agree on which copy is under test.
78
+
79
+ The suite makes assertions about CLI behaviour by spawning
80
+ `python -m maintainability_audit`. Those assertions are only about this
81
+ working tree if the child resolves the same package the test process
82
+ imported, and for a while nothing checked that:
83
+
84
+ - Where the package is installed with `pip install --user`, the `HOME`
85
+ move in `conftest` deleted the child's route to it entirely. Tests
86
+ failed with `No module named maintainability_audit` — a message that
87
+ names imports, in tests whose subject is not imports, on a laptop
88
+ while CI stayed green because a virtualenv's site-packages is not
89
+ `HOME`-derived.
90
+ - The quieter half is that a child could instead have found a
91
+ *different* copy — a stale wheel, an older `pip install` — and
92
+ passed. Every subprocess assertion would then have described a build
93
+ the rest of the suite never measured.
94
+
95
+ Comparing the resolved file rather than the version catches both: two
96
+ copies of the same version are still two copies.
97
+ """
98
+ child = subprocess.run(
99
+ [sys.executable, "-c",
100
+ "import maintainability_audit as m; print(m.__file__)"],
101
+ text=True, capture_output=True, check=False,
102
+ )
103
+
104
+ assert child.returncode == 0, (
105
+ "a spawned child could not import the package under test:\n"
106
+ f"{child.stderr}"
107
+ )
108
+
109
+ import maintainability_audit
110
+
111
+ assert Path(child.stdout.strip()) == Path(maintainability_audit.__file__), (
112
+ "a spawned subprocess imported a different copy of the package than "
113
+ f"this test process: child {child.stdout.strip()!r}, parent "
114
+ f"{maintainability_audit.__file__!r}"
115
+ )
116
+
117
+
118
+ def test_the_isolation_guards_are_collected() -> None:
119
+ """No isolation guard may live where pytest does not collect it.
120
+
121
+ The guard on the guards, and the reason this file exists. Both tests
122
+ above sat in `conftest.py` and never ran; the suite was green for
123
+ months with its own harness unverified. Asserting that `conftest.py`
124
+ defines no `test_`-prefixed function encodes the rule rather than the
125
+ instance, so the next one written in the convenient place fails loudly
126
+ instead of silently never running.
127
+ """
128
+ conftest = Path(__file__).with_name("conftest.py").read_text()
129
+ stranded = [
130
+ line.split("(")[0].removeprefix("def ").strip()
131
+ for line in conftest.splitlines()
132
+ if line.startswith("def test_")
133
+ ]
134
+
135
+ assert not stranded, (
136
+ f"{stranded} are defined in conftest.py, which pytest loads as a "
137
+ "plugin and never collects as a test module, so they cannot fail. "
138
+ "Move them into a test_*.py file."
139
+ )