maintainability-agent 2.2.0__tar.gz → 2.3.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 (312) hide show
  1. {maintainability_agent-2.2.0/src/maintainability_agent.egg-info → maintainability_agent-2.3.0}/PKG-INFO +2 -2
  2. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/README.md +1 -1
  3. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/pyproject.toml +1 -1
  4. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0/src/maintainability_agent.egg-info}/PKG-INFO +2 -2
  5. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_agent.egg-info/SOURCES.txt +2 -0
  6. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/__init__.py +1 -1
  7. maintainability_agent-2.3.0/src/maintainability_audit/_attestation.py +166 -0
  8. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/cli.py +12 -0
  9. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/config.py +1 -1
  10. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/prompts.py +1 -0
  11. maintainability_agent-2.3.0/tests/test_attestation.py +151 -0
  12. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/LICENSE +0 -0
  13. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/setup.cfg +0 -0
  14. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_agent.egg-info/dependency_links.txt +0 -0
  15. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_agent.egg-info/entry_points.txt +0 -0
  16. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_agent.egg-info/requires.txt +0 -0
  17. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_agent.egg-info/top_level.txt +0 -0
  18. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/__main__.py +0 -0
  19. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/_adapters.py +0 -0
  20. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/_analysis.py +0 -0
  21. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/_aspects.py +0 -0
  22. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/_assets/analyzer-catalog.json +0 -0
  23. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/_assets/standard.md +0 -0
  24. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/_backfill.py +0 -0
  25. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/_bands.py +0 -0
  26. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/_built_ins.py +0 -0
  27. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/_calibration.py +0 -0
  28. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/_catalog.py +0 -0
  29. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/_charts.py +0 -0
  30. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/_cognitive.py +0 -0
  31. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/_config_defaults.py +0 -0
  32. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/_conformance.py +0 -0
  33. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/_corroborate.py +0 -0
  34. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/_coverage_notes.py +0 -0
  35. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/_derive.py +0 -0
  36. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/_discovery.py +0 -0
  37. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/_documents.py +0 -0
  38. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/_economics.py +0 -0
  39. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/_economics_view.py +0 -0
  40. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/_environment.py +0 -0
  41. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/_evidence_view.py +0 -0
  42. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/_finding_match.py +0 -0
  43. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/_first_run.py +0 -0
  44. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/_formula.py +0 -0
  45. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/_gates.py +0 -0
  46. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/_generic.py +0 -0
  47. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/_grant_ledger.py +0 -0
  48. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/_history_view.py +0 -0
  49. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/_hostile_prompt.py +0 -0
  50. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/_hotspots.py +0 -0
  51. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/_html_report_sections.py +0 -0
  52. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/_html_view.py +0 -0
  53. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/_identity.py +0 -0
  54. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/_jvm_adapters.py +0 -0
  55. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/_markdown_sections.py +0 -0
  56. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/_masking.py +0 -0
  57. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/_mcp_audit.py +0 -0
  58. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/_mcp_gate.py +0 -0
  59. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/_mcp_grants.py +0 -0
  60. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/_mcp_refusals.py +0 -0
  61. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/_mcp_resources.py +0 -0
  62. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/_mcp_setup.py +0 -0
  63. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/_metric_adapters.py +0 -0
  64. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/_metrics_types.py +0 -0
  65. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/_pillars.py +0 -0
  66. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/_practice.py +0 -0
  67. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/_pressures.py +0 -0
  68. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/_ranges_c.py +0 -0
  69. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/_ranges_core.py +0 -0
  70. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/_ranges_cpp.py +0 -0
  71. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/_ranges_csharp.py +0 -0
  72. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/_ranges_fortran.py +0 -0
  73. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/_ranges_java.py +0 -0
  74. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/_ranges_js.py +0 -0
  75. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/_ratchet.py +0 -0
  76. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/_recurrence.py +0 -0
  77. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/_runner.py +0 -0
  78. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/_safe_write.py +0 -0
  79. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/_scan_history.py +0 -0
  80. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/_scan_view.py +0 -0
  81. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/_second_source.py +0 -0
  82. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/_selection.py +0 -0
  83. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/_semantic.py +0 -0
  84. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/_semantic_policy.py +0 -0
  85. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/_semantic_ts.py +0 -0
  86. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/_semantic_view.py +0 -0
  87. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/_setup_errors.py +0 -0
  88. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/_setup_persist.py +0 -0
  89. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/_skill_data/SKILL.md +0 -0
  90. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/_skill_data/agents/anthropic.yaml +0 -0
  91. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/_skill_data/agents/copilot.yaml +0 -0
  92. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/_skill_data/agents/openai.yaml +0 -0
  93. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/_skill_data/copilot/maintainability-agent.prompt.md +0 -0
  94. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/_skill_data/references/finding-taxonomy.md +0 -0
  95. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/_skill_install.py +0 -0
  96. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/_stored_grants.py +0 -0
  97. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/_tdd_view.py +0 -0
  98. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/_test_execution.py +0 -0
  99. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/_test_pairing.py +0 -0
  100. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/_tokens.py +0 -0
  101. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/_tool_adapters.py +0 -0
  102. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/_trends.py +0 -0
  103. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/_user_config.py +0 -0
  104. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/_verdict_adapters.py +0 -0
  105. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/_verification.py +0 -0
  106. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/_work_order.py +0 -0
  107. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/_work_order_view.py +0 -0
  108. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/_work_order_weights.py +0 -0
  109. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/_xml.py +0 -0
  110. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/baseline.py +0 -0
  111. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/deadcode.py +0 -0
  112. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/declarations.py +0 -0
  113. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/duplication.py +0 -0
  114. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/evidence.py +0 -0
  115. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/git_tools.py +0 -0
  116. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/history.py +0 -0
  117. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/idioms.py +0 -0
  118. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/instructions.py +0 -0
  119. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/mcp_server.py +0 -0
  120. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/metrics.py +0 -0
  121. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/renderers.py +0 -0
  122. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/report.py +0 -0
  123. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/sarif.py +0 -0
  124. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/scoring.py +0 -0
  125. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/similarity.py +0 -0
  126. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/src/maintainability_audit/source.py +0 -0
  127. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_acquisition_trust.py +0 -0
  128. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_adapter_docs.py +0 -0
  129. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_adapter_recordings.py +0 -0
  130. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_adapters.py +0 -0
  131. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_added_lines.py +0 -0
  132. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_analysis_coverage.py +0 -0
  133. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_analysis_execution.py +0 -0
  134. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_analyzer_bridge.py +0 -0
  135. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_analyzer_config_isolation.py +0 -0
  136. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_analyzer_estimate_claims.py +0 -0
  137. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_analyzer_pinning.py +0 -0
  138. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_analyzer_primary_estimate.py +0 -0
  139. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_analyzer_provenance.py +0 -0
  140. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_analyzer_provenance_exclusions.py +0 -0
  141. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_analyzer_scoring_path.py +0 -0
  142. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_analyzer_spread_range.py +0 -0
  143. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_analyzer_xml_bounds.py +0 -0
  144. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_annotations_match_behaviour.py +0 -0
  145. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_anticipated_refusals.py +0 -0
  146. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_architecture.py +0 -0
  147. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_artifact_write_route_class.py +0 -0
  148. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_aspect_coverage.py +0 -0
  149. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_asset_snapshot_class.py +0 -0
  150. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_ast_reading_resolves_spellings.py +0 -0
  151. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_audit_components.py +0 -0
  152. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_authorization_freshness.py +0 -0
  153. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_authorship_gates.py +0 -0
  154. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_backfill.py +0 -0
  155. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_band_concealment_class.py +0 -0
  156. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_band_concealment_p3.py +0 -0
  157. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_band_pressures.py +0 -0
  158. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_bands.py +0 -0
  159. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_body_or_signature_class.py +0 -0
  160. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_c_declarations.py +0 -0
  161. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_calibration_corpus.py +0 -0
  162. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_calibration_drift.py +0 -0
  163. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_calibration_tooling.py +0 -0
  164. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_catalog_selection.py +0 -0
  165. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_catalog_tier_promise.py +0 -0
  166. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_chat_primary_docs.py +0 -0
  167. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_checkstyle_adapter.py +0 -0
  168. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_checkstyle_catalog.py +0 -0
  169. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_ci_history_recipe.py +0 -0
  170. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_ci_installs_the_analyzer_pool.py +0 -0
  171. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_claimed_languages.py +0 -0
  172. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_cli.py +0 -0
  173. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_clone_group_class.py +0 -0
  174. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_cognitive_complexity.py +0 -0
  175. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_cohort_statistics.py +0 -0
  176. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_concealment_properties.py +0 -0
  177. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_config_shape.py +0 -0
  178. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_consent_and_grant.py +0 -0
  179. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_consumer_migration.py +0 -0
  180. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_contract_claims.py +0 -0
  181. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_corroborate.py +0 -0
  182. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_coverage_by_language.py +0 -0
  183. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_cpp_declarations.py +0 -0
  184. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_csharp_declarations.py +0 -0
  185. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_d15_composition.py +0 -0
  186. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_d15_goal_directed.py +0 -0
  187. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_dead_code.py +0 -0
  188. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_declaration_edge_cases.py +0 -0
  189. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_declaration_grading.py +0 -0
  190. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_declaration_ranges.py +0 -0
  191. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_declaration_source.py +0 -0
  192. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_declared_authorship.py +0 -0
  193. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_declared_imports.py +0 -0
  194. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_derivation_mix.py +0 -0
  195. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_determinism.py +0 -0
  196. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_dimension_ratchet.py +0 -0
  197. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_direct_runner_availability_class.py +0 -0
  198. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_discovery.py +0 -0
  199. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_doc_claims.py +0 -0
  200. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_docs_links.py +0 -0
  201. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_economic_context.py +0 -0
  202. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_empty_output_not_clean.py +0 -0
  203. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_empty_output_not_clean_adapters.py +0 -0
  204. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_environment_work_order.py +0 -0
  205. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_evidence_invariants.py +0 -0
  206. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_evidence_normalization.py +0 -0
  207. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_evidence_properties.py +0 -0
  208. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_exclusion_dialects.py +0 -0
  209. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_falsifier_standard.py +0 -0
  210. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_file_list_cap_class.py +0 -0
  211. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_finding_identity.py +0 -0
  212. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_first_run_elicitation.py +0 -0
  213. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_first_run_prompt.py +0 -0
  214. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_first_run_reelicitation.py +0 -0
  215. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_fix_breadth_window.py +0 -0
  216. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_fixed_form_fortran.py +0 -0
  217. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_format_ask.py +0 -0
  218. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_fortran_declarations.py +0 -0
  219. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_fortran_metrics.py +0 -0
  220. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_fortran_practice.py +0 -0
  221. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_git_argv.py +0 -0
  222. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_git_read_only.py +0 -0
  223. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_git_readonly_class.py +0 -0
  224. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_grant_only_user_tier.py +0 -0
  225. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_history.py +0 -0
  226. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_history_boundary.py +0 -0
  227. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_history_manifest.py +0 -0
  228. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_history_schema2.py +0 -0
  229. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_history_window.py +0 -0
  230. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_hostile_prompt.py +0 -0
  231. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_html_executive.py +0 -0
  232. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_html_section_parity_class.py +0 -0
  233. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_identity_docs.py +0 -0
  234. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_identity_resolution.py +0 -0
  235. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_idiom_divergence.py +0 -0
  236. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_installed_wheel_runtime.py +0 -0
  237. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_instruction_targets.py +0 -0
  238. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_java_range_guard.py +0 -0
  239. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_java_ranges.py +0 -0
  240. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_java_scored.py +0 -0
  241. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_java_wiring.py +0 -0
  242. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_js_complexity_operators.py +0 -0
  243. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_js_declarations.py +0 -0
  244. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_language_coverage.py +0 -0
  245. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_mcp_baseline_payload.py +0 -0
  246. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_mcp_history.py +0 -0
  247. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_mcp_server.py +0 -0
  248. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_migration_1_0.py +0 -0
  249. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_near_duplicates.py +0 -0
  250. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_network_disclosure.py +0 -0
  251. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_one_setup_across_surfaces_class.py +0 -0
  252. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_pattern_budget.py +0 -0
  253. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_phase6_claims.py +0 -0
  254. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_pillars_and_practice.py +0 -0
  255. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_platform_claim.py +0 -0
  256. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_pmd_adapter.py +0 -0
  257. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_pmd_audit_closures.py +0 -0
  258. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_pool_runs_by_config.py +0 -0
  259. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_population_floors.py +0 -0
  260. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_practice_nested_gates_class.py +0 -0
  261. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_presentation_refusals.py +0 -0
  262. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_promises.py +0 -0
  263. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_prompt_escalation_once.py +0 -0
  264. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_prompt_honesty.py +0 -0
  265. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_prompt_location_escalation_class.py +0 -0
  266. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_prove_falsifiers.py +0 -0
  267. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_python_declarations.py +0 -0
  268. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_read_boundary.py +0 -0
  269. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_readme_claims.py +0 -0
  270. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_recurrence.py +0 -0
  271. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_release_plan.py +0 -0
  272. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_release_plan_status.py +0 -0
  273. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_report_remedy_copy.py +0 -0
  274. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_roles_recorded.py +0 -0
  275. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_root_grants.py +0 -0
  276. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_rubric_ignores_project_lint_config.py +0 -0
  277. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_runner.py +0 -0
  278. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_sarif.py +0 -0
  279. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_scan_history.py +0 -0
  280. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_scan_scope.py +0 -0
  281. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_scanning.py +0 -0
  282. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_schema_fidelity.py +0 -0
  283. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_scope_conformance.py +0 -0
  284. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_scoring_calibration.py +0 -0
  285. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_semantic_policy.py +0 -0
  286. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_setup_gate_completeness.py +0 -0
  287. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_setup_gate_independent_contract.py +0 -0
  288. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_setup_precondition.py +0 -0
  289. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_skill_install.py +0 -0
  290. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_source_index.py +0 -0
  291. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_spotbugs_adapter.py +0 -0
  292. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_spotbugs_catalog.py +0 -0
  293. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_stage8_contract.py +0 -0
  294. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_tdd_structure.py +0 -0
  295. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_test_execution_class.py +0 -0
  296. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_three_presentations.py +0 -0
  297. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_trends.py +0 -0
  298. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_type_fields_not_functions_class.py +0 -0
  299. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_uat_falsifiers.py +0 -0
  300. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_unread_code.py +0 -0
  301. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_user_config_tier.py +0 -0
  302. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_verification_audit_closures.py +0 -0
  303. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_verified_grade.py +0 -0
  304. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_version_claim.py +0 -0
  305. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_wheel_contents.py +0 -0
  306. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_work_order.py +0 -0
  307. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_work_order_items.py +0 -0
  308. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_work_order_selection.py +0 -0
  309. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_workflow_supply_chain.py +0 -0
  310. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_write_boundary.py +0 -0
  311. {maintainability_agent-2.2.0 → maintainability_agent-2.3.0}/tests/test_write_route_class.py +0 -0
  312. {maintainability_agent-2.2.0 → maintainability_agent-2.3.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.2.0
3
+ Version: 2.3.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.2.0**.
47
+ Version **2.3.0**.
48
48
 
49
49
  **Languages parsed:** Python, Java, C, C++, C#, Fortran (free-form *and*
50
50
  fixed-form), and the JS/TS family — each by a scanner written for it, and
@@ -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.2.0**.
8
+ Version **2.3.0**.
9
9
 
10
10
  **Languages parsed:** Python, Java, C, C++, C#, Fortran (free-form *and*
11
11
  fixed-form), and the JS/TS family — each by a scanner written for it, and
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "maintainability-agent"
7
- version = "2.2.0"
7
+ version = "2.3.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.2.0
3
+ Version: 2.3.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.2.0**.
47
+ Version **2.3.0**.
48
48
 
49
49
  **Languages parsed:** Python, Java, C, C++, C#, Fortran (free-form *and*
50
50
  fixed-form), and the JS/TS family — each by a scanner written for it, and
@@ -12,6 +12,7 @@ src/maintainability_audit/__main__.py
12
12
  src/maintainability_audit/_adapters.py
13
13
  src/maintainability_audit/_analysis.py
14
14
  src/maintainability_audit/_aspects.py
15
+ src/maintainability_audit/_attestation.py
15
16
  src/maintainability_audit/_backfill.py
16
17
  src/maintainability_audit/_bands.py
17
18
  src/maintainability_audit/_built_ins.py
@@ -144,6 +145,7 @@ tests/test_artifact_write_route_class.py
144
145
  tests/test_aspect_coverage.py
145
146
  tests/test_asset_snapshot_class.py
146
147
  tests/test_ast_reading_resolves_spellings.py
148
+ tests/test_attestation.py
147
149
  tests/test_audit_components.py
148
150
  tests/test_authorization_freshness.py
149
151
  tests/test_authorship_gates.py
@@ -1,3 +1,3 @@
1
1
  """Maintainability Audit CI."""
2
2
 
3
- __version__ = "2.2.0"
3
+ __version__ = "2.3.0"
@@ -0,0 +1,166 @@
1
+ """The record a generator cannot produce about its own output.
2
+
3
+ The three mechanisms — scope conformance, suppression detection, the
4
+ dimension ratchet — each answer one question about a change. This composes
5
+ them into the artifact they were built for: a per-change record of what was
6
+ measured, what the agent was told to change, what it actually changed, and
7
+ what moved.
8
+
9
+ **Why an independent process has to emit it.** A platform that generates
10
+ code and then reports on its quality is producing a self-assessment. That
11
+ is a property of the arrangement, not a criticism of any particular one,
12
+ and no amount of engineering removes it. The question a reviewer asks is
13
+ *who checked this, and can they re-derive the check months from now* — and
14
+ an author cannot be the answer. This tool writes nothing, runs no model,
15
+ and returns the same verdict from the same inputs, which is the only reason
16
+ its answer can be evidence rather than an opinion.
17
+
18
+ **It is reproducible, not signed.** Every field is derived from the report
19
+ and the pinned inputs, and the digest at the end is over the record's own
20
+ content, so two runs on the same commit with the same analyzer versions
21
+ produce the same digest. That makes it *verifiable* — anyone can re-run and
22
+ compare. It is deliberately not called a signature: nothing here holds a
23
+ key, and claiming a cryptographic guarantee this does not provide would be
24
+ exactly the kind of overclaim the rest of the project spends its time
25
+ removing. Signing the artifact, if a caller wants that, is a step they take
26
+ with their own key on a file whose bytes are stable.
27
+
28
+ **What it does not establish.** The record says which files the work order
29
+ named and whether a checker was switched off — not whether the edits were
30
+ correct. It never opens the diff to judge it, and it never touches a score.
31
+ Review is still review.
32
+ """
33
+
34
+ from __future__ import annotations
35
+
36
+ import hashlib
37
+ import json
38
+ from typing import Any
39
+
40
+ ARTIFACT_VERSION = 1
41
+
42
+
43
+ def _verdicts(report: dict[str, Any]) -> list[str]:
44
+ """One line per question that was actually asked."""
45
+ lines: list[str] = []
46
+ conformance = report.get("scope_conformance")
47
+ if conformance:
48
+ out = len(conformance["out_of_scope"])
49
+ silenced = conformance["suppressions_on_named_paths"]
50
+ lines.append(
51
+ f"- **Stayed inside the work order:** "
52
+ f"{'yes' if conformance['conformant'] else f'no — {out} file(s) outside it'}"
53
+ )
54
+ lines.append(
55
+ f"- **Without silencing a finding:** "
56
+ f"{'yes' if not silenced else f'no — {silenced} suppression(s) on flagged files'}"
57
+ )
58
+ ratchet = report.get("dimension_ratchet")
59
+ if ratchet:
60
+ if not ratchet["comparable"]:
61
+ lines.append(
62
+ f"- **No dimension regressed:** not established — {ratchet['reason']}"
63
+ )
64
+ elif ratchet["regressed"]:
65
+ names = ", ".join(item["name"] for item in ratchet["regressed"])
66
+ lines.append(f"- **No dimension regressed:** no — {names}")
67
+ else:
68
+ lines.append("- **No dimension regressed:** yes")
69
+ return lines
70
+
71
+
72
+ def _measured(report: dict[str, Any]) -> list[str]:
73
+ score = report.get("score") or {}
74
+ coverage = report.get("analyzer_coverage") or {}
75
+ status = score.get("evidence_status")
76
+ if isinstance(status, dict):
77
+ status = status.get("status")
78
+ ran = (coverage.get("by_outcome") or {}).get("ran") or []
79
+ return [
80
+ f"- Estimate: {score.get('maintainability_estimate', 'withheld')}",
81
+ f"- Verified grade: {score.get('verified_grade') or 'withheld'}",
82
+ f"- Evidence: {status or 'unstated'}",
83
+ f"- Analyzers that ran: {len(ran)}",
84
+ f"- Hard gate failures: {len(report.get('hard_gate_failures') or [])}",
85
+ ]
86
+
87
+
88
+ def attestation_record(report: dict[str, Any]) -> dict[str, Any]:
89
+ """The structured record, before rendering."""
90
+ conformance = report.get("scope_conformance") or {}
91
+ ratchet = report.get("dimension_ratchet") or {}
92
+ score = report.get("score") or {}
93
+ record = {
94
+ "artifact_version": ARTIFACT_VERSION,
95
+ "tool_version": report.get("tool_version"),
96
+ "commit": report.get("git_commit"),
97
+ "branch": report.get("git_branch"),
98
+ # A finding reported against "the commit" that actually depends on
99
+ # uncommitted work is unreproducible, so the state of the tree is
100
+ # part of what is attested rather than a footnote.
101
+ "tree_dirty": bool(report.get("git_status_short")),
102
+ "revspec": conformance.get("revspec"),
103
+ "estimate": score.get("maintainability_estimate"),
104
+ "verified_grade": score.get("verified_grade"),
105
+ "stayed_in_scope": conformance.get("conformant"),
106
+ "no_finding_silenced": (
107
+ None if not conformance else conformance["suppressions_on_named_paths"] == 0
108
+ ),
109
+ "no_dimension_regressed": (
110
+ None if not ratchet or not ratchet.get("comparable")
111
+ else not ratchet["regressed"]
112
+ ),
113
+ "scope_conformance": conformance or None,
114
+ "dimension_ratchet": ratchet or None,
115
+ }
116
+ # The digest is over the record without it, so it is reproducible: the
117
+ # same commit measured with the same analyzer versions yields the same
118
+ # value, and anyone can recompute it rather than trust it.
119
+ record["digest"] = hashlib.sha256(
120
+ json.dumps(record, sort_keys=True, default=str).encode("utf-8")
121
+ ).hexdigest()[:16]
122
+ return record
123
+
124
+
125
+ def render_attestation(report: dict[str, Any]) -> str:
126
+ """The record as text, for a reviewer or an audit trail."""
127
+ record = attestation_record(report)
128
+ dirty = " (uncommitted changes present)" if record["tree_dirty"] else ""
129
+ lines = [
130
+ "# Maintainability attestation",
131
+ "",
132
+ "An independent, deterministic check on a change. Produced by a "
133
+ "process that generated none of the code it examined.",
134
+ "",
135
+ f"- Commit: `{record['commit'] or 'unknown'}`{dirty}",
136
+ f"- Branch: `{record['branch'] or 'unknown'}`",
137
+ f"- Tool version: {record['tool_version'] or 'unknown'}",
138
+ f"- Compared: `{record['revspec'] or 'not asked'}`",
139
+ "",
140
+ "## What was measured",
141
+ "",
142
+ *_measured(report),
143
+ "",
144
+ "## What the change did",
145
+ "",
146
+ ]
147
+ verdicts = _verdicts(report)
148
+ lines += verdicts or ["- Nothing was asked: run with `--conformance` and "
149
+ "`--fail-on-regression` to populate this section."]
150
+ lines += [
151
+ "",
152
+ "## What this does not establish",
153
+ "",
154
+ "- It compares paths and reads added lines. A file in scope means the "
155
+ "work order named it, **not** that the change to it was correct — this "
156
+ "never opens the diff to judge it.",
157
+ "- It touches no score. Whether a change obeyed its instructions is a "
158
+ "fact about behaviour, not evidence about the code's condition.",
159
+ "- It is reproducible, **not signed**. The digest is over this "
160
+ "record's own content, so the same inputs reproduce it and anyone can "
161
+ "recompute it. Nothing here holds a key.",
162
+ "",
163
+ f"Digest: `{record['digest']}`",
164
+ "",
165
+ ]
166
+ return "\n".join(lines)
@@ -97,6 +97,14 @@ def add_arguments(parser: argparse.ArgumentParser) -> None:
97
97
  parser.add_argument("--prompt-output", help="Optional Markdown prompt for AI-assisted remediation.")
98
98
  parser.add_argument("--comment-output", help="Optional Markdown body suitable for a PR comment.")
99
99
  parser.add_argument("--agent-instructions-output", help="Optional reusable instructions for AI coding agents.")
100
+ parser.add_argument(
101
+ "--attestation-output",
102
+ help="Write the attestation: an independent, reproducible record of "
103
+ "what was measured, what the change was told to do, what it did, "
104
+ "and what moved. Populated by --conformance and "
105
+ "--fail-on-regression; a generator cannot produce this about its "
106
+ "own output.",
107
+ )
100
108
  parser.add_argument("--hostile-prompt-output",
101
109
  help="Optional adversarial audit brief seeded from this run (ADR 013). "
102
110
  "Text only: it does not gate, score, or send anything.")
@@ -227,6 +235,10 @@ def write_outputs(args: argparse.Namespace, report: dict, rendered: str) -> None
227
235
  write_artifact(root, Path(args.comment_output), render_pr_comment(report) + "\n")
228
236
  if args.agent_instructions_output:
229
237
  write_artifact(root, Path(args.agent_instructions_output), render_agent_instructions(report) + "\n")
238
+ if args.attestation_output:
239
+ from ._attestation import render_attestation
240
+
241
+ write_artifact(root, Path(args.attestation_output), render_attestation(report))
230
242
  if args.hostile_prompt_output:
231
243
  write_artifact(root, Path(args.hostile_prompt_output),
232
244
  render_hostile_audit_prompt(report) + "\n")
@@ -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.2.0"
14
+ VERSION = "2.3.0"
15
15
 
16
16
  PROJECT_URL = "https://github.com/marshallguillory86/maintainability-agent"
17
17
 
@@ -11,6 +11,7 @@ from __future__ import annotations
11
11
  from typing import Any
12
12
 
13
13
  from . import _evidence_view as view
14
+ from ._attestation import render_attestation # noqa: F401
14
15
  from ._hostile_prompt import render_hostile_audit_prompt # noqa: F401
15
16
  from ._hotspots import hotspot_measure, hotspot_name
16
17
  from ._tdd_view import tdd_sentences
@@ -0,0 +1,151 @@
1
+ """The record an author cannot produce about their own work.
2
+
3
+ The three mechanisms each answer one question about a change. This composes
4
+ them into the artifact they were built for — and the value of that artifact
5
+ is entirely in what it refuses to overstate, so that is what is tested here.
6
+
7
+ Three properties, and all three are about honesty rather than plumbing:
8
+
9
+ - **A mixed result reads as mixed.** A change that stayed in scope while
10
+ silencing a finding must not produce a document anyone could wave as a
11
+ pass.
12
+ - **Not asked is not the same as passed.** A question nobody ran must not
13
+ render as a verdict.
14
+ - **It claims reproducible, never signed.** Nothing here holds a key, and a
15
+ document that implied otherwise would be the exact overclaim the rest of
16
+ this project spends its time removing.
17
+ """
18
+
19
+ from __future__ import annotations
20
+
21
+ from maintainability_audit._attestation import attestation_record, render_attestation
22
+
23
+ CLEAN = {
24
+ "tool_version": "2.3.0",
25
+ "git_commit": "a" * 40,
26
+ "git_branch": "main",
27
+ "git_status_short": "",
28
+ "score": {
29
+ "maintainability_estimate": 4.2,
30
+ "verified_grade": "B",
31
+ "evidence_status": {"status": "complete"},
32
+ },
33
+ "analyzer_coverage": {"by_outcome": {"ran": [{"tool": "lizard"}]}},
34
+ "hard_gate_failures": [],
35
+ "scope_conformance": {
36
+ "revspec": "main...HEAD", "conformant": True, "out_of_scope": [],
37
+ "suppressions_on_named_paths": 0, "clean": True,
38
+ },
39
+ "dimension_ratchet": {"comparable": True, "regressed": []},
40
+ }
41
+
42
+
43
+ def _with(**changes: object) -> dict:
44
+ report = {key: dict(value) if isinstance(value, dict) else value
45
+ for key, value in CLEAN.items()}
46
+ report.update(changes)
47
+ return report
48
+
49
+
50
+ def test_a_clean_change_says_so_on_every_question() -> None:
51
+ text = render_attestation(CLEAN)
52
+
53
+ assert "**Stayed inside the work order:** yes" in text
54
+ assert "**Without silencing a finding:** yes" in text
55
+ assert "**No dimension regressed:** yes" in text
56
+
57
+
58
+ def test_a_silenced_finding_is_not_hidden_by_staying_in_scope() -> None:
59
+ """The mixed verdict the artifact exists to make unmissable.
60
+
61
+ Scope and silence are separate questions, so a change that obeyed the
62
+ first and failed the second must not produce a document that reads as a
63
+ pass on either.
64
+ """
65
+ report = _with(scope_conformance={
66
+ "revspec": "main...HEAD", "conformant": True, "out_of_scope": [],
67
+ "suppressions_on_named_paths": 2, "clean": False,
68
+ })
69
+
70
+ text = render_attestation(report)
71
+
72
+ assert "**Stayed inside the work order:** yes" in text
73
+ assert "**Without silencing a finding:** no" in text
74
+ assert attestation_record(report)["no_finding_silenced"] is False
75
+
76
+
77
+ def test_a_question_nobody_asked_is_not_reported_as_passed() -> None:
78
+ """`None`, not `True`. An unrun check is not a clean result."""
79
+ report = _with(scope_conformance=None, dimension_ratchet=None)
80
+
81
+ record = attestation_record(report)
82
+
83
+ assert record["stayed_in_scope"] is None
84
+ assert record["no_finding_silenced"] is None
85
+ assert record["no_dimension_regressed"] is None
86
+ assert "Nothing was asked" in render_attestation(report)
87
+
88
+
89
+ def test_an_incomparable_ratchet_is_not_reported_as_no_regression() -> None:
90
+ """Two scans under different calibration cannot be differenced.
91
+
92
+ "Not established" is the honest rendering; "yes" would be a claim the
93
+ evidence cannot support.
94
+ """
95
+ report = _with(dimension_ratchet={
96
+ "comparable": False, "regressed": [],
97
+ "reason": "calibration changed, so scans cannot be joined",
98
+ })
99
+
100
+ text = render_attestation(report)
101
+
102
+ assert "not established" in text
103
+ assert attestation_record(report)["no_dimension_regressed"] is None
104
+
105
+
106
+ def test_an_uncommitted_tree_is_disclosed() -> None:
107
+ """A verdict about "the commit" that depends on unstaged work is a lie."""
108
+ report = _with(git_status_short=" M src/thing.py")
109
+
110
+ assert attestation_record(report)["tree_dirty"] is True
111
+ assert "uncommitted changes present" in render_attestation(report)
112
+
113
+
114
+ def test_the_document_claims_reproducible_and_refuses_to_claim_signed() -> None:
115
+ """Nothing here holds a key, and the artifact must not imply one.
116
+
117
+ "Signed" is the word a reader reaches for with an attestation, which is
118
+ exactly why the document has to say the opposite in its own text.
119
+ """
120
+ text = render_attestation(CLEAN)
121
+
122
+ assert "not signed" in text.lower()
123
+ assert "Digest:" in text
124
+
125
+
126
+ def test_the_digest_is_reproducible_and_content_bound() -> None:
127
+ first = attestation_record(CLEAN)["digest"]
128
+ second = attestation_record(CLEAN)["digest"]
129
+ moved = attestation_record(_with(score={
130
+ "maintainability_estimate": 3.1, "verified_grade": "C",
131
+ "evidence_status": {"status": "complete"},
132
+ }))["digest"]
133
+
134
+ assert first == second, "the same inputs produced two different digests"
135
+ assert first != moved, "the digest did not follow the record's content"
136
+
137
+
138
+ def test_the_record_carries_no_score_verdict_of_its_own() -> None:
139
+ """It reports the estimate the audit produced; it never computes one."""
140
+ record = attestation_record(CLEAN)
141
+
142
+ assert record["estimate"] == 4.2
143
+ assert "categories" not in record
144
+ assert "dimensions" not in record
145
+
146
+
147
+ def test_the_document_states_that_it_never_opened_the_diff() -> None:
148
+ text = render_attestation(CLEAN)
149
+
150
+ assert "not** that the change to it was correct" in text
151
+ assert "touches no score" in text