maintainability-agent 3.6.2__tar.gz → 3.7.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 (387) hide show
  1. {maintainability_agent-3.6.2/src/maintainability_agent.egg-info → maintainability_agent-3.7.0}/PKG-INFO +3 -2
  2. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/README.md +1 -1
  3. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/pyproject.toml +9 -1
  4. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0/src/maintainability_agent.egg-info}/PKG-INFO +3 -2
  5. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_agent.egg-info/SOURCES.txt +3 -0
  6. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_agent.egg-info/requires.txt +1 -0
  7. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/__init__.py +1 -1
  8. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_delegated_pillar.py +19 -0
  9. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_discovery.py +37 -2
  10. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_pillars.py +9 -3
  11. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_prompt_sections.py +24 -0
  12. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_scan_view.py +7 -0
  13. maintainability_agent-3.7.0/src/maintainability_audit/_security_delegate.py +121 -0
  14. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/config.py +1 -1
  15. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/git_tools.py +30 -0
  16. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/mcp_server.py +15 -9
  17. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/prompts.py +2 -0
  18. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/renderers.py +6 -0
  19. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/report.py +29 -13
  20. maintainability_agent-3.7.0/tests/test_build_output_is_not_the_repositorys_code.py +165 -0
  21. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_consent_and_grant.py +8 -3
  22. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_first_run_elicitation.py +1 -1
  23. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_mcp_baseline_payload.py +1 -1
  24. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_mcp_history.py +7 -3
  25. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_mcp_server.py +1 -1
  26. maintainability_agent-3.7.0/tests/test_security_pillar_runs_and_shows.py +207 -0
  27. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/LICENSE +0 -0
  28. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/setup.cfg +0 -0
  29. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_agent.egg-info/dependency_links.txt +0 -0
  30. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_agent.egg-info/entry_points.txt +0 -0
  31. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_agent.egg-info/top_level.txt +0 -0
  32. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/__main__.py +0 -0
  33. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_adapters.py +0 -0
  34. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_analysis.py +0 -0
  35. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_analyzer_sections.py +0 -0
  36. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_anchor.py +0 -0
  37. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_arguments.py +0 -0
  38. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_aspects.py +0 -0
  39. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_assets/analyzer-catalog.json +0 -0
  40. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_assets/standard.md +0 -0
  41. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_attestation.py +0 -0
  42. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_backfill.py +0 -0
  43. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_bands.py +0 -0
  44. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_banner.py +0 -0
  45. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_built_ins.py +0 -0
  46. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_calibration.py +0 -0
  47. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_catalog.py +0 -0
  48. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_charts.py +0 -0
  49. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_cognitive.py +0 -0
  50. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_config_defaults.py +0 -0
  51. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_conformance.py +0 -0
  52. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_corroborate.py +0 -0
  53. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_coverage_notes.py +0 -0
  54. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_criteria_scope.py +0 -0
  55. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_derive.py +0 -0
  56. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_documents.py +0 -0
  57. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_economics.py +0 -0
  58. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_economics_view.py +0 -0
  59. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_environment.py +0 -0
  60. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_evidence_reader.py +0 -0
  61. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_evidence_view.py +0 -0
  62. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_finding_match.py +0 -0
  63. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_first_run.py +0 -0
  64. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_formula.py +0 -0
  65. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_gates.py +0 -0
  66. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_generic.py +0 -0
  67. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_grammar.py +0 -0
  68. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_grant_ledger.py +0 -0
  69. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_history_view.py +0 -0
  70. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_hostile_prompt.py +0 -0
  71. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_hotspots.py +0 -0
  72. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_html_report_sections.py +0 -0
  73. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_html_view.py +0 -0
  74. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_identity.py +0 -0
  75. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_in_loop.py +0 -0
  76. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_in_loop_view.py +0 -0
  77. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_jvm_adapters.py +0 -0
  78. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_markdown_sections.py +0 -0
  79. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_masking.py +0 -0
  80. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_mcp_audit.py +0 -0
  81. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_mcp_gate.py +0 -0
  82. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_mcp_grants.py +0 -0
  83. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_mcp_refusals.py +0 -0
  84. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_mcp_resources.py +0 -0
  85. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_mcp_setup.py +0 -0
  86. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_metric_adapters.py +0 -0
  87. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_metrics_types.py +0 -0
  88. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_operator_reads.py +0 -0
  89. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_practice.py +0 -0
  90. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_precommit.py +0 -0
  91. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_precommit_install.py +0 -0
  92. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_precommit_view.py +0 -0
  93. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_pressures.py +0 -0
  94. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_ranges_c.py +0 -0
  95. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_ranges_cobol.py +0 -0
  96. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_ranges_core.py +0 -0
  97. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_ranges_cpp.py +0 -0
  98. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_ranges_csharp.py +0 -0
  99. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_ranges_fortran.py +0 -0
  100. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_ranges_go.py +0 -0
  101. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_ranges_java.py +0 -0
  102. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_ranges_js.py +0 -0
  103. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_ranges_php.py +0 -0
  104. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_ranges_ruby.py +0 -0
  105. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_ranges_rust.py +0 -0
  106. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_ranges_swift.py +0 -0
  107. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_ratchet.py +0 -0
  108. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_ratio_adapters.py +0 -0
  109. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_recurrence.py +0 -0
  110. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_run_comparison.py +0 -0
  111. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_runner.py +0 -0
  112. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_safe_write.py +0 -0
  113. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_scan_history.py +0 -0
  114. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_second_source.py +0 -0
  115. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_selection.py +0 -0
  116. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_semantic.py +0 -0
  117. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_semantic_policy.py +0 -0
  118. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_semantic_ts.py +0 -0
  119. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_semantic_view.py +0 -0
  120. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_setup_errors.py +0 -0
  121. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_setup_persist.py +0 -0
  122. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_skill_data/SKILL.md +0 -0
  123. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_skill_data/agents/anthropic.yaml +0 -0
  124. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_skill_data/agents/copilot.yaml +0 -0
  125. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_skill_data/agents/openai.yaml +0 -0
  126. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_skill_data/copilot/maintainability-agent.prompt.md +0 -0
  127. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_skill_data/references/finding-taxonomy.md +0 -0
  128. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_skill_install.py +0 -0
  129. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_stored_grants.py +0 -0
  130. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_tdd_view.py +0 -0
  131. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_test_commands.py +0 -0
  132. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_test_execution.py +0 -0
  133. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_test_pairing.py +0 -0
  134. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_tokens.py +0 -0
  135. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_tool_adapters.py +0 -0
  136. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_trends.py +0 -0
  137. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_user_config.py +0 -0
  138. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_verdict_adapters.py +0 -0
  139. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_verification.py +0 -0
  140. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_work_order.py +0 -0
  141. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_work_order_view.py +0 -0
  142. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_work_order_weights.py +0 -0
  143. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/_xml.py +0 -0
  144. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/baseline.py +0 -0
  145. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/cli.py +0 -0
  146. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/deadcode.py +0 -0
  147. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/declarations.py +0 -0
  148. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/duplication.py +0 -0
  149. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/evidence.py +0 -0
  150. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/history.py +0 -0
  151. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/idioms.py +0 -0
  152. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/instructions.py +0 -0
  153. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/metrics.py +0 -0
  154. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/sarif.py +0 -0
  155. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/scoring.py +0 -0
  156. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/similarity.py +0 -0
  157. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/src/maintainability_audit/source.py +0 -0
  158. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_acquisition_trust.py +0 -0
  159. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_adapter_docs.py +0 -0
  160. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_adapter_recordings.py +0 -0
  161. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_adapters.py +0 -0
  162. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_added_lines.py +0 -0
  163. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_analysis_coverage.py +0 -0
  164. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_analysis_execution.py +0 -0
  165. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_analyzer_bridge.py +0 -0
  166. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_analyzer_config_isolation.py +0 -0
  167. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_analyzer_estimate_claims.py +0 -0
  168. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_analyzer_pinning.py +0 -0
  169. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_analyzer_primary_estimate.py +0 -0
  170. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_analyzer_provenance.py +0 -0
  171. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_analyzer_provenance_exclusions.py +0 -0
  172. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_analyzer_scoring_path.py +0 -0
  173. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_analyzer_spread_range.py +0 -0
  174. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_analyzer_xml_bounds.py +0 -0
  175. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_anchor_and_mode.py +0 -0
  176. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_anchor_caveat_and_counts_follow_the_run.py +0 -0
  177. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_anchor_disclosure.py +0 -0
  178. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_annotations_match_behaviour.py +0 -0
  179. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_anticipated_refusals.py +0 -0
  180. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_architecture.py +0 -0
  181. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_artifact_write_route_class.py +0 -0
  182. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_aspect_coverage.py +0 -0
  183. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_asset_snapshot_class.py +0 -0
  184. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_ast_reading_resolves_spellings.py +0 -0
  185. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_attestation.py +0 -0
  186. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_audit_components.py +0 -0
  187. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_authorization_freshness.py +0 -0
  188. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_authorship_gates.py +0 -0
  189. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_backfill.py +0 -0
  190. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_band_concealment_class.py +0 -0
  191. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_band_concealment_p3.py +0 -0
  192. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_band_pressures.py +0 -0
  193. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_bands.py +0 -0
  194. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_body_or_signature_class.py +0 -0
  195. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_c_declarations.py +0 -0
  196. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_calibration_corpus.py +0 -0
  197. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_calibration_drift.py +0 -0
  198. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_calibration_tooling.py +0 -0
  199. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_catalog_selection.py +0 -0
  200. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_catalog_tier_promise.py +0 -0
  201. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_chat_leads_with_the_work_order.py +0 -0
  202. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_chat_primary_docs.py +0 -0
  203. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_check_refuses_plus_only_fragments.py +0 -0
  204. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_checkstyle_adapter.py +0 -0
  205. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_checkstyle_catalog.py +0 -0
  206. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_child_sandbox.py +0 -0
  207. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_ci_history_recipe.py +0 -0
  208. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_ci_installs_the_analyzer_pool.py +0 -0
  209. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_claimed_languages.py +0 -0
  210. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_cli.py +0 -0
  211. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_clone_group_class.py +0 -0
  212. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_cobol_declarations.py +0 -0
  213. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_cognitive_complexity.py +0 -0
  214. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_cohort_statistics.py +0 -0
  215. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_concealment_properties.py +0 -0
  216. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_config_shape.py +0 -0
  217. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_consumer_migration.py +0 -0
  218. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_contract_claims.py +0 -0
  219. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_corroborate.py +0 -0
  220. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_coverage_by_language.py +0 -0
  221. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_cpp_declarations.py +0 -0
  222. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_criteria_completion.py +0 -0
  223. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_csharp_declarations.py +0 -0
  224. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_d15_composition.py +0 -0
  225. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_d15_goal_directed.py +0 -0
  226. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_dead_code.py +0 -0
  227. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_declaration_criteria_scope.py +0 -0
  228. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_declaration_edge_cases.py +0 -0
  229. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_declaration_grading.py +0 -0
  230. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_declaration_ranges.py +0 -0
  231. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_declaration_source.py +0 -0
  232. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_declarative_parsers.py +0 -0
  233. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_declared_authorship.py +0 -0
  234. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_declared_imports.py +0 -0
  235. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_delegated_security_pillar.py +0 -0
  236. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_demo_tree.py +0 -0
  237. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_derivation_mix.py +0 -0
  238. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_determinism.py +0 -0
  239. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_dimension_ratchet.py +0 -0
  240. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_direct_runner_availability_class.py +0 -0
  241. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_discovery.py +0 -0
  242. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_doc_claims.py +0 -0
  243. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_docs_links.py +0 -0
  244. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_economic_context.py +0 -0
  245. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_empty_output_not_clean.py +0 -0
  246. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_empty_output_not_clean_adapters.py +0 -0
  247. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_environment_work_order.py +0 -0
  248. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_every_surface_says_what_the_run_found.py +0 -0
  249. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_evidence_invariants.py +0 -0
  250. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_evidence_normalization.py +0 -0
  251. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_evidence_properties.py +0 -0
  252. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_example_config_opens_claimed_languages.py +0 -0
  253. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_exclusion_dialects.py +0 -0
  254. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_exposure_never_outranks_band.py +0 -0
  255. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_falsifier_standard.py +0 -0
  256. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_file_list_cap_class.py +0 -0
  257. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_finding_identity.py +0 -0
  258. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_first_run_prompt.py +0 -0
  259. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_first_run_reelicitation.py +0 -0
  260. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_fix_breadth_window.py +0 -0
  261. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_fixed_form_fortran.py +0 -0
  262. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_format_ask.py +0 -0
  263. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_fortran_declarations.py +0 -0
  264. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_fortran_metrics.py +0 -0
  265. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_fortran_practice.py +0 -0
  266. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_git_argv.py +0 -0
  267. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_git_read_only.py +0 -0
  268. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_git_readonly_class.py +0 -0
  269. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_go_declarations.py +0 -0
  270. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_grammar_constructs.py +0 -0
  271. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_grammar_token_coverage.py +0 -0
  272. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_grant_only_user_tier.py +0 -0
  273. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_history.py +0 -0
  274. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_history_boundary.py +0 -0
  275. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_history_manifest.py +0 -0
  276. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_history_schema2.py +0 -0
  277. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_history_window.py +0 -0
  278. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_hostile_prompt.py +0 -0
  279. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_html_executive.py +0 -0
  280. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_html_section_parity_class.py +0 -0
  281. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_identity_docs.py +0 -0
  282. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_identity_resolution.py +0 -0
  283. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_idiom_divergence.py +0 -0
  284. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_in_loop_budgets.py +0 -0
  285. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_in_loop_check.py +0 -0
  286. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_installed_wheel_runtime.py +0 -0
  287. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_instruction_targets.py +0 -0
  288. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_java_range_guard.py +0 -0
  289. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_java_ranges.py +0 -0
  290. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_java_scored.py +0 -0
  291. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_java_wiring.py +0 -0
  292. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_js_complexity_operators.py +0 -0
  293. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_js_declarations.py +0 -0
  294. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_language_coverage.py +0 -0
  295. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_language_support_honesty.py +0 -0
  296. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_mcp_format_contract.py +0 -0
  297. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_migration_1_0.py +0 -0
  298. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_near_duplicates.py +0 -0
  299. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_network_disclosure.py +0 -0
  300. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_one_setup_across_surfaces_class.py +0 -0
  301. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_operator_named_paths.py +0 -0
  302. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_operator_named_reads.py +0 -0
  303. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_pairing_reads_imports.py +0 -0
  304. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_pattern_budget.py +0 -0
  305. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_phase6_claims.py +0 -0
  306. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_php_declarations.py +0 -0
  307. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_pillars_and_practice.py +0 -0
  308. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_platform_claim.py +0 -0
  309. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_pmd_adapter.py +0 -0
  310. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_pmd_audit_closures.py +0 -0
  311. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_policy_claims.py +0 -0
  312. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_pool_runs_by_config.py +0 -0
  313. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_population_floors.py +0 -0
  314. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_practice_nested_gates_class.py +0 -0
  315. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_precommit_staged.py +0 -0
  316. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_presentation_refusals.py +0 -0
  317. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_promises.py +0 -0
  318. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_prompt_does_not_issue_rates_when_unscored.py +0 -0
  319. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_prompt_escalation_once.py +0 -0
  320. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_prompt_honesty.py +0 -0
  321. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_prompt_location_escalation_class.py +0 -0
  322. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_prove_falsifiers.py +0 -0
  323. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_python_complexity.py +0 -0
  324. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_python_declarations.py +0 -0
  325. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_read_boundary.py +0 -0
  326. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_readme_claims.py +0 -0
  327. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_recurrence.py +0 -0
  328. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_release_needs_an_empty_ledger.py +0 -0
  329. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_release_plan.py +0 -0
  330. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_release_plan_status.py +0 -0
  331. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_report_remedy_copy.py +0 -0
  332. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_roles_recorded.py +0 -0
  333. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_root_grants.py +0 -0
  334. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_rubric_ignores_project_lint_config.py +0 -0
  335. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_ruby_declarations.py +0 -0
  336. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_run_comparison.py +0 -0
  337. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_runner.py +0 -0
  338. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_rust_declarations.py +0 -0
  339. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_sarif.py +0 -0
  340. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_scan_history.py +0 -0
  341. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_scan_scope.py +0 -0
  342. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_scanner_unsafe_direction.py +0 -0
  343. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_scanning.py +0 -0
  344. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_schema_fidelity.py +0 -0
  345. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_scope_conformance.py +0 -0
  346. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_scoring_calibration.py +0 -0
  347. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_semantic_policy.py +0 -0
  348. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_setup_gate_completeness.py +0 -0
  349. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_setup_gate_independent_contract.py +0 -0
  350. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_setup_precondition.py +0 -0
  351. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_skill_install.py +0 -0
  352. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_sonar_resolve.py +0 -0
  353. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_source_index.py +0 -0
  354. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_spotbugs_adapter.py +0 -0
  355. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_spotbugs_catalog.py +0 -0
  356. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_stage8_contract.py +0 -0
  357. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_stdout_outputs.py +0 -0
  358. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_suite_isolation.py +0 -0
  359. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_swift_declarations.py +0 -0
  360. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_tdd_structure.py +0 -0
  361. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_terminal_asks_the_same_questions.py +0 -0
  362. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_test_commands.py +0 -0
  363. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_test_execution_class.py +0 -0
  364. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_three_presentations.py +0 -0
  365. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_tool_resolution.py +0 -0
  366. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_tree_cannot_opt_the_host_in.py +0 -0
  367. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_tree_chosen_spawn.py +0 -0
  368. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_tree_reads_use_the_primitive.py +0 -0
  369. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_trends.py +0 -0
  370. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_type_fields_not_functions_class.py +0 -0
  371. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_uat_falsifiers.py +0 -0
  372. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_unanchored_set_matches_corpus.py +0 -0
  373. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_unread_code.py +0 -0
  374. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_user_config_tier.py +0 -0
  375. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_verification_audit_closures.py +0 -0
  376. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_verified_grade.py +0 -0
  377. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_version_claim.py +0 -0
  378. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_wheel_contents.py +0 -0
  379. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_work_items_state_their_own_finding.py +0 -0
  380. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_work_order.py +0 -0
  381. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_work_order_binds_to_this_interpreter.py +0 -0
  382. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_work_order_items.py +0 -0
  383. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_work_order_selection.py +0 -0
  384. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_workflow_supply_chain.py +0 -0
  385. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_write_boundary.py +0 -0
  386. {maintainability_agent-3.6.2 → maintainability_agent-3.7.0}/tests/test_write_route_class.py +0 -0
  387. {maintainability_agent-3.6.2 → maintainability_agent-3.7.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: 3.6.2
3
+ Version: 3.7.0
4
4
  Summary: Maintainability gate and AI remediation prompt generator for CI.
5
5
  Author: Marshall Guillory
6
6
  License: MIT
@@ -19,6 +19,7 @@ Classifier: Topic :: Software Development :: Quality Assurance
19
19
  Requires-Python: >=3.11
20
20
  Description-Content-Type: text/markdown
21
21
  License-File: LICENSE
22
+ Requires-Dist: secure-code-agent<0.11,>=0.10
22
23
  Provides-Extra: test
23
24
  Requires-Dist: pytest>=8; extra == "test"
24
25
  Requires-Dist: pytest-cov>=5; extra == "test"
@@ -46,7 +47,7 @@ Dynamic: license-file
46
47
  **A deterministic, offline maintainability audit whose output is a _bounded
47
48
  work order_ for an AI coding agent** — a copy-paste prompt, per finding, that
48
49
  says *fix exactly these and refactor nothing else*. Chat-primary; CLI for CI.
49
- Version **3.6.2**.
50
+ Version **3.7.0**.
50
51
 
51
52
  **Languages parsed:** Python, Java, C, C++, C#, Go, Rust, PHP, Ruby, Swift,
52
53
  COBOL, Fortran (free-form *and* fixed-form), and the JS/TS/HTML family — each
@@ -5,7 +5,7 @@
5
5
  **A deterministic, offline maintainability audit whose output is a _bounded
6
6
  work order_ for an AI coding agent** — a copy-paste prompt, per finding, that
7
7
  says *fix exactly these and refactor nothing else*. Chat-primary; CLI for CI.
8
- Version **3.6.2**.
8
+ Version **3.7.0**.
9
9
 
10
10
  **Languages parsed:** Python, Java, C, C++, C#, Go, Rust, PHP, Ruby, Swift,
11
11
  COBOL, Fortran (free-form *and* fixed-form), and the JS/TS/HTML family — each
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "maintainability-agent"
7
- version = "3.6.2"
7
+ version = "3.7.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
@@ -13,6 +13,14 @@ readme = "README.md"
13
13
  # metadata said a user could stand: the suite runs 3.12 and the
14
14
  # composite action pins 3.11 (D42).
15
15
  requires-python = ">=3.11"
16
+ # The security pillar is complete (D177): every audit runs secure-code-agent,
17
+ # so it installs with this package rather than being left to the operator.
18
+ # Its own dependency is PyYAML; this package still imports no YAML
19
+ # (`test_the_shipped_package_does_not_import_yaml`) — it runs the tool as a
20
+ # child and reads the JSON document it writes.
21
+ dependencies = [
22
+ "secure-code-agent>=0.10,<0.11",
23
+ ]
16
24
  license = { text = "MIT" }
17
25
  authors = [
18
26
  { name = "Marshall Guillory" }
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: maintainability-agent
3
- Version: 3.6.2
3
+ Version: 3.7.0
4
4
  Summary: Maintainability gate and AI remediation prompt generator for CI.
5
5
  Author: Marshall Guillory
6
6
  License: MIT
@@ -19,6 +19,7 @@ Classifier: Topic :: Software Development :: Quality Assurance
19
19
  Requires-Python: >=3.11
20
20
  Description-Content-Type: text/markdown
21
21
  License-File: LICENSE
22
+ Requires-Dist: secure-code-agent<0.11,>=0.10
22
23
  Provides-Extra: test
23
24
  Requires-Dist: pytest>=8; extra == "test"
24
25
  Requires-Dist: pytest-cov>=5; extra == "test"
@@ -46,7 +47,7 @@ Dynamic: license-file
46
47
  **A deterministic, offline maintainability audit whose output is a _bounded
47
48
  work order_ for an AI coding agent** — a copy-paste prompt, per finding, that
48
49
  says *fix exactly these and refactor nothing else*. Chat-primary; CLI for CI.
49
- Version **3.6.2**.
50
+ Version **3.7.0**.
50
51
 
51
52
  **Languages parsed:** Python, Java, C, C++, C#, Go, Rust, PHP, Ruby, Swift,
52
53
  COBOL, Fortran (free-form *and* fixed-form), and the JS/TS/HTML family — each
@@ -94,6 +94,7 @@ src/maintainability_audit/_safe_write.py
94
94
  src/maintainability_audit/_scan_history.py
95
95
  src/maintainability_audit/_scan_view.py
96
96
  src/maintainability_audit/_second_source.py
97
+ src/maintainability_audit/_security_delegate.py
97
98
  src/maintainability_audit/_selection.py
98
99
  src/maintainability_audit/_semantic.py
99
100
  src/maintainability_audit/_semantic_policy.py
@@ -182,6 +183,7 @@ tests/test_band_concealment_p3.py
182
183
  tests/test_band_pressures.py
183
184
  tests/test_bands.py
184
185
  tests/test_body_or_signature_class.py
186
+ tests/test_build_output_is_not_the_repositorys_code.py
185
187
  tests/test_c_declarations.py
186
188
  tests/test_calibration_corpus.py
187
189
  tests/test_calibration_drift.py
@@ -339,6 +341,7 @@ tests/test_scanning.py
339
341
  tests/test_schema_fidelity.py
340
342
  tests/test_scope_conformance.py
341
343
  tests/test_scoring_calibration.py
344
+ tests/test_security_pillar_runs_and_shows.py
342
345
  tests/test_semantic_policy.py
343
346
  tests/test_setup_gate_completeness.py
344
347
  tests/test_setup_gate_independent_contract.py
@@ -1,3 +1,4 @@
1
+ secure-code-agent<0.11,>=0.10
1
2
 
2
3
  [dev]
3
4
  pytest>=8
@@ -1,3 +1,3 @@
1
1
  """Maintainability Audit CI."""
2
2
 
3
- __version__ = "3.6.2"
3
+ __version__ = "3.7.0"
@@ -123,6 +123,25 @@ def read_delegated(root: Path, relative: str = DEFAULT_PILLAR_PATH) -> dict[str,
123
123
  if isinstance(error, PathNotAllowed):
124
124
  raise
125
125
  return None
126
+ return trusted(payload)
127
+
128
+
129
+ def read_produced(path: Path) -> dict[str, Any] | None:
130
+ """The document this tool's own run of secure-code-agent just wrote (D177).
131
+
132
+ The file sits in a temporary directory this process created, not in the
133
+ audited tree, so it is read directly; every check a handed-over document
134
+ passes still applies, because the producer is the same tool either way.
135
+ """
136
+ try:
137
+ payload = json.loads(Path(path).read_text(encoding="utf-8"))
138
+ except (OSError, ValueError):
139
+ return None
140
+ return trusted(payload)
141
+
142
+
143
+ def trusted(payload: Any) -> dict[str, Any] | None:
144
+ """The payload when it is a document this module understands, else `None`."""
126
145
  if not isinstance(payload, dict):
127
146
  return None
128
147
  if payload.get("schema") != SCHEMA:
@@ -222,8 +222,31 @@ def _text_of(path: Path) -> str:
222
222
  return "\n".join(read_source_file(path))
223
223
 
224
224
 
225
+ #: The evidence recorded for a path the repository ignores and git does not
226
+ #: track (D175), so a reader can see why it left the scored population.
227
+ IGNORED_BUILD_OUTPUT_EVIDENCE = (
228
+ "untracked, and excluded by this repository's .gitignore "
229
+ "(git ls-files --others --ignored)"
230
+ )
231
+
232
+
233
+ def _ignored_build_output(root: Path) -> dict[str, str]:
234
+ """Untracked paths the repository's `.gitignore` excludes (D175).
235
+
236
+ A Maven build copied jsoup's test resources into `target/test-classes`,
237
+ and the next audit scored 29 more files — one a failing file — as the
238
+ team's own. The same commit scored one way before a build and another
239
+ after it. `target/` is not added to a list of names: ADR 010 §1 forbids
240
+ that, and the next build tool will choose another word. The repository
241
+ already says which paths are not its source.
242
+ """
243
+ from .git_tools import ignored_untracked_paths
244
+
245
+ return dict.fromkeys(ignored_untracked_paths(root), IGNORED_BUILD_OUTPUT_EVIDENCE)
246
+
247
+
225
248
  def _generated_directories(root: Path, excludes: tuple[str, ...]) -> dict[str, str]:
226
- """Directories a `package.json` script deletes and rebuilds."""
249
+ """Directories a `package.json` script deletes and rebuilds, then ignored build output."""
227
250
  found: dict[str, str] = {}
228
251
  for manifest in root.rglob("package.json"):
229
252
  relative = manifest.relative_to(root).as_posix()
@@ -237,6 +260,10 @@ def _generated_directories(root: Path, excludes: tuple[str, ...]) -> dict[str, s
237
260
  f"deleted and rebuilt by `{name}` in {relative}: "
238
261
  f"`{str(command)[:60]}`",
239
262
  )
263
+ # A manifest's own statement about a directory is the more specific
264
+ # evidence, so it wins where both apply.
265
+ for path, evidence in _ignored_build_output(root).items():
266
+ found.setdefault(path, evidence)
240
267
  return found
241
268
 
242
269
 
@@ -458,10 +485,18 @@ def discover(root: Path, config: dict[str, Any]) -> Inventory:
458
485
  inventory.directories = _directory_provenance(
459
486
  vendored_dirs, generated_dirs, asset_dirs)
460
487
  seen_directories: set[tuple[str, str]] = set()
488
+ # What the scanner reads, beyond source code: a generated or vendored
489
+ # tree's HTML, XML and JSON are scored too unless classified here (D175).
490
+ read = set((config.get("paths") or {}).get("include_extensions", ()))
491
+ not_ours_dirs = (*generated_dirs, *vendored_dirs)
461
492
  for path in sorted(root.rglob("*")):
462
- if not path.is_file() or path.suffix not in KNOWN_SOURCE_SUFFIXES:
493
+ if not path.is_file():
463
494
  continue
464
495
  relative = path.relative_to(root).as_posix()
496
+ if path.suffix not in KNOWN_SOURCE_SUFFIXES and not (
497
+ path.suffix in read and any(_under(relative, owner) for owner in not_ours_dirs)
498
+ ):
499
+ continue
465
500
  if is_excluded(relative, list(excludes)):
466
501
  continue
467
502
  verdict, evidence, owner = _classify(
@@ -87,8 +87,9 @@ PILLARS: tuple[Pillar, ...] = (
87
87
  name="security",
88
88
  scope=Scope.DELEGATED,
89
89
  reason=(
90
- "delegated to secure-code-agent; this tool catalogues security "
91
- "analyzers and never runs them, so silence here is not safety"
90
+ "delegated to secure-code-agent, which this audit runs for the pillar; "
91
+ "when no measurement comes back the reason is given here, because "
92
+ "silence is not safety"
92
93
  ),
93
94
  ),
94
95
  Pillar(
@@ -213,9 +214,14 @@ def pillar_report(
213
214
  score: dict[str, Any],
214
215
  practice: dict[str, Any],
215
216
  delegated: dict[str, dict[str, Any]] | None = None,
217
+ unmeasured: dict[str, str] | None = None,
216
218
  ) -> list[dict[str, Any]]:
217
219
  """The pillar block exactly as it ships.
218
220
 
221
+ `unmeasured` names, per delegated pillar, why no measurement came back
222
+ from a run of the tool that owns it (D177), and replaces the generic
223
+ reason so the reader learns what actually happened.
224
+
219
225
  Practice arrives as an argument rather than being computed here.
220
226
  `_practice` reads the repository's configuration off disk, which
221
227
  makes it a scanner, and the scoring layer may not reach upward into
@@ -251,7 +257,7 @@ def pillar_report(
251
257
  report.append({
252
258
  "pillar": pillar.name,
253
259
  "scope": pillar.scope.value,
254
- "reason": pillar.reason,
260
+ "reason": (unmeasured or {}).get(pillar.name) or pillar.reason,
255
261
  # Both axes, side by side, never merged. A consumer reads
256
262
  # either one; nothing in the document offers their mean.
257
263
  "practice": resolved["level"],
@@ -118,6 +118,30 @@ def prompt_analyzer_caveat(report: dict[str, Any]) -> list[str]:
118
118
  ]
119
119
 
120
120
 
121
+ def prompt_security_pillar(report: dict[str, Any]) -> list[str]:
122
+ """What the security pillar reported, stated where an agent reads the run (D176).
123
+
124
+ Evidence, never a task: security remediation is secure-code-agent's own
125
+ work order, not this prompt's. But a prompt that says nothing about
126
+ security lets an agent read silence as a clean bill, which is the one
127
+ reading ADR 007 exists to prevent.
128
+ """
129
+ entry = next((p for p in report.get("pillars") or [] if p.get("pillar") == "security"), None)
130
+ if entry is None:
131
+ return []
132
+ if not entry.get("delegated_to"):
133
+ return [f"**Security pillar: not measured.** {entry.get('reason')}.", ""]
134
+ producer = entry.get("delegated_to") or "the delegated tool"
135
+ version = f" {entry['producer_version']}" if entry.get("producer_version") else ""
136
+ condition = "not graded" if entry.get("condition") is None else f"{entry['condition']:.1f}"
137
+ return [
138
+ f"**Security pillar (measured by {producer}{version}):** posture "
139
+ f"{entry.get('posture')}, practice level {entry.get('practice')}, condition "
140
+ f"{condition}. Its findings are that tool's work order, not this one.",
141
+ "",
142
+ ]
143
+
144
+
121
145
  def prompt_escalation_note(report: dict[str, Any]) -> list[str]:
122
146
  """Tell the agent what is deliberately absent, and why.
123
147
 
@@ -364,6 +364,13 @@ def pillar_cells(entry: dict[str, Any]) -> tuple[str, str]:
364
364
  condition = "—" if entry["condition"] is None else f"{entry['condition']:.1f}"
365
365
  if entry["posture"] is None:
366
366
  return condition, "not measured — see below"
367
+ if entry["condition"] is None:
368
+ # An ungraded pillar is `unverified` because nothing could be graded,
369
+ # not because a clean scan lacks enforcement — the note for that cell
370
+ # told a reader of secure-code-agent's partial-coverage pillar that
371
+ # its scan was clean (D176). Say why no grade was issued instead.
372
+ why = (entry.get("evidence_reasons") or [None])[0] or "the evidence could not support a grade"
373
+ return condition, f"{entry['posture']}: not graded — {why}"
367
374
  note = POSTURE_NOTE.get(entry["posture"], entry["posture"])
368
375
  return condition, f"{entry['posture']}: {note}"
369
376
 
@@ -0,0 +1,121 @@
1
+ """This tool runs secure-code-agent for the security pillar (D177).
2
+
3
+ [ADR 007](adr-007-pillars-and-practice.md) delegates the security pillar to
4
+ `secure-code-agent`. Until 3.7.0 the delegation was a handoff: the other
5
+ tool wrote `security-pillar.json` and this one read it if it happened to be
6
+ there. Nothing ran it, so every audit that did not follow a manual or CI run
7
+ of the other tool reported the pillar as unmeasured — including every audit
8
+ through the chat door, which cannot run it at all. Decided 2026-09-13 with
9
+ Marshall: the pillar is complete, so the audit runs it.
10
+
11
+ **What the child writes.** Every report `secure-code-agent` can produce is
12
+ redirected into a temporary directory this process owns: the Markdown and
13
+ JSON reports, SARIF, the PR comment, the remediation prompt and the pillar
14
+ document itself. The one write that cannot be redirected is its append-only
15
+ trend, `.secure-code/history.jsonl` in the audited tree, which it writes on
16
+ every run from its own configuration. Turning that off would mean handing
17
+ it a configuration from outside the tree, and `secure-code-agent` trusts an
18
+ outside configuration to name executables in the tree — so the override
19
+ would launder repository content past the other tool's own boundary. The
20
+ history is therefore declared, not suppressed.
21
+
22
+ **How the child is started.** Through `_runner.run`, like every analyzer and
23
+ the opted-in test command, so architecture rule 7 still holds: the tree can
24
+ reach one execution path, not a new one per feature. The command is the
25
+ interpreter doing the auditing, the way D144 and D166 bound theirs, so the
26
+ pillar is measured by the `secure-code-agent` installed beside this package
27
+ rather than whichever one `PATH` finds. It gets the runner's stripped
28
+ environment and a neutral working directory: not a sandbox, and not claimed
29
+ as one.
30
+
31
+ A run that produces no trustworthy document says why. Absence is never
32
+ silent, because silence is exactly what ADR 007 says must not read as safety.
33
+ """
34
+ from __future__ import annotations
35
+
36
+ import importlib.util
37
+ import shlex
38
+ import sys
39
+ import tempfile
40
+ from dataclasses import dataclass, field
41
+ from pathlib import Path
42
+ from typing import Any
43
+
44
+ from ._delegated_pillar import read_produced
45
+ from ._runner import Invocation, Outcome, run
46
+
47
+ #: The distribution the pillar requires, and the range this tool reads.
48
+ REQUIREMENT = "secure-code-agent>=0.10,<0.11"
49
+
50
+ #: How long the child may run before the pillar is reported as unmeasured.
51
+ DEFAULT_TIMEOUT_SECONDS = 300
52
+
53
+ _ENTRY = "import sys; from secure_code_audit.cli import main; sys.exit(main())"
54
+
55
+
56
+ @dataclass(frozen=True)
57
+ class DelegateRun:
58
+ """What one run of the delegate produced, and why when it produced nothing."""
59
+
60
+ document: dict[str, Any] | None
61
+ reason: str | None = None
62
+ environment: list[dict[str, str]] = field(default_factory=list)
63
+
64
+
65
+ def _install_remedy(reason: str) -> dict[str, str]:
66
+ """An environment work-order entry, bound to the auditing interpreter (D144)."""
67
+ python = shlex.quote(sys.executable)
68
+ return {
69
+ "tool": "secure-code-agent",
70
+ "reason": reason,
71
+ "install": f"{python} -m pip install '{REQUIREMENT}'",
72
+ "verify": f"{python} -m pip show secure-code-agent",
73
+ "concepts": "security",
74
+ }
75
+
76
+
77
+ def run_security_delegate(
78
+ root: Path, *, changed_revspec: str | None = None,
79
+ timeout_seconds: int = DEFAULT_TIMEOUT_SECONDS,
80
+ ) -> DelegateRun:
81
+ """Run `secure-code-agent` over `root` and return its pillar document."""
82
+ if importlib.util.find_spec("secure_code_audit") is None:
83
+ reason = "secure-code-agent is not installed for the interpreter running this audit"
84
+ return DelegateRun(None, reason, [_install_remedy(reason)])
85
+ with tempfile.TemporaryDirectory(prefix="ma-security-") as scratch:
86
+ out = Path(scratch)
87
+ pillar = out / "security-pillar.json"
88
+ argv = [
89
+ sys.executable, "-c", _ENTRY, str(root),
90
+ "--security-pillar", str(pillar),
91
+ "--output", str(out / "report.md"),
92
+ "--json-output", str(out / "report.json"),
93
+ "--sarif-output", str(out / "report.sarif"),
94
+ "--comment-output", str(out / "comment.md"),
95
+ "--prompt-output", str(out / "prompt.md"),
96
+ ]
97
+ if changed_revspec:
98
+ argv += ["--changed-only", changed_revspec]
99
+ # Exit 1 is the tool's gate verdict, not a failure to measure: the
100
+ # pillar document is still written, and the pillar reports the gate.
101
+ result = run("secure-code-agent", Invocation(
102
+ argv=tuple(argv), findings_exit_codes=(0, 1), cwd=out,
103
+ ), timeout_seconds=timeout_seconds)
104
+ document = read_produced(pillar)
105
+ if document is not None:
106
+ return DelegateRun(document)
107
+ if result.outcome is Outcome.TIMED_OUT:
108
+ return DelegateRun(None, f"secure-code-agent did not finish within {timeout_seconds}s")
109
+ detail = _last_line(result.stderr) or _last_line(result.stdout) or result.detail
110
+ # No install remedy here: the tool is installed and ran. A rejected
111
+ # configuration or a crash is fixed in the repository or reported
112
+ # upstream, and an install command would send the reader to the
113
+ # wrong place.
114
+ reason = (f"secure-code-agent exited {result.exit_code} without a pillar document"
115
+ + (f": {detail}" if detail else ""))
116
+ return DelegateRun(None, reason)
117
+
118
+
119
+ def _last_line(text: str | None) -> str:
120
+ lines = [line.strip() for line in (text or "").splitlines() if line.strip()]
121
+ return lines[-1][:200] if lines else ""
@@ -20,7 +20,7 @@ from ._operator_reads import (
20
20
  # still the door every caller comes through.
21
21
  __all__ = ["DEFAULT_CONFIG", "DEFAULT_IDIOM_GROUPS", "PROJECT_URL", "VERSION"]
22
22
 
23
- VERSION = "3.6.2"
23
+ VERSION = "3.7.0"
24
24
 
25
25
  PROJECT_URL = "https://github.com/marshallguillory86/maintainability-agent"
26
26
 
@@ -231,6 +231,36 @@ def probe_git(args: list[str], cwd: Path) -> str:
231
231
  return ""
232
232
 
233
233
 
234
+ def ignored_untracked_paths(root: Path) -> set[str]:
235
+ """Paths the repository's own `.gitignore` files exclude and git does not track (D175).
236
+
237
+ A build writes `target/`, `out/` or `bin/` into the working tree, and the
238
+ repository's `.gitignore` is where it says those are not its source.
239
+ That is evidence the repository provides, so ADR 010 can act on it where
240
+ a list of directory names cannot.
241
+
242
+ Only the per-directory `.gitignore` files are read. `--exclude-standard`
243
+ would also honour `.git/info/exclude` and the user's `core.excludesFile`,
244
+ which differ by machine — the same commit would then score differently
245
+ on two laptops (P1). A tracked file matched by an ignore rule is not
246
+ listed, because git tracks it, and an untracked file that is *not*
247
+ ignored stays in: that is uncommitted work, which D56 keeps visible.
248
+
249
+ Directories come back with a trailing slash, which is stripped. A tree
250
+ git cannot read — not a repository, git absent — yields nothing, which
251
+ is the absence of evidence rather than a verdict.
252
+ """
253
+ try:
254
+ output = run_git(
255
+ ["ls-files", "--others", "--ignored",
256
+ "--exclude-per-directory=.gitignore", "--directory", "-z"],
257
+ root, strip=False,
258
+ )
259
+ except GitCommandFailed:
260
+ return set()
261
+ return {entry.rstrip("/") for entry in output.split("\0") if entry.strip("/")}
262
+
263
+
234
264
  def changed_paths(root: Path, revspec: str) -> set[str]:
235
265
  """Paths touched by `revspec`, as forward-slash relative strings.
236
266
 
@@ -4,10 +4,12 @@ This module is transport assembly: tool bindings, resources, prompts and
4
4
  the stdio entry point. The audit tool's own logic — authorization,
5
5
  tri-state resolution, history recording — lives in ``_mcp_audit`` and is
6
6
  re-exported here so every consumer keeps one import path. Setup, the
7
- loop record and baseline adoption may write only five local artifacts:
7
+ loop record and baseline adoption may write only six local artifacts:
8
8
  repository and user configuration, user state, the repository's scan
9
- history, and the repository's baseline. It never writes source or a
10
- report, accepts a command string, or invokes a shell.
9
+ history, the repository's baseline, and — because an audit runs
10
+ secure-code-agent for the security pillar (D177) — that tool's own
11
+ append-only trend. It never writes source or a report, accepts a command
12
+ string, or invokes a shell.
11
13
  """
12
14
 
13
15
  from __future__ import annotations
@@ -66,11 +68,13 @@ SERVER_INSTRUCTIONS = (
66
68
  "step: do not inspect configuration first and do not ask the user "
67
69
  "which config to use — the tool resolves that itself. First contact with an "
68
70
  "unconfigured repository elicits setup, and the audit records its scan "
69
- "history and can adopt a baseline, so it may write exactly five local "
71
+ "history and can adopt a baseline, so it may write exactly six local "
70
72
  "artifacts: the repository's maintainability-agent.json, the user-level "
71
73
  "config, the user state file, the repository's scan history "
72
- "(.maintainability/history.jsonl by default), and a requested baseline "
73
- "(.maintainability/baseline.json by default). Scan history rides the "
74
+ "(.maintainability/history.jsonl by default), a requested baseline "
75
+ "(.maintainability/baseline.json by default), and secure-code-agent's own "
76
+ "trend (.secure-code/history.jsonl), which that tool appends when the audit "
77
+ "runs it for the security pillar. Scan history rides the "
74
78
  "record_history tri-state, where unset means an existing history file "
75
79
  "appends and otherwise the persisted first-run consent decides, "
76
80
  "true forces the write, and false suppresses it. Nothing is audited "
@@ -109,12 +113,14 @@ def server_info(roots: tuple[Path, ...] | None = None) -> dict[str, Any]:
109
113
  "transport": "stdio",
110
114
  "local": True,
111
115
  # Not blanket read-only since D2/D5: setup, the loop record and
112
- # baseline adoption write exactly the five local artifacts
113
- # listed below, never source and never a report.
116
+ # baseline adoption write the local artifacts listed below, and the
117
+ # security pillar's run of secure-code-agent appends that tool's own
118
+ # trend (D177). Never source and never a report.
114
119
  "read_only": False,
115
120
  "writes": [CONFIG_FILENAME, "user config", "user state",
116
121
  f"scan history ({DEFAULT_HISTORY_PATH})",
117
- "baseline (.maintainability/baseline.json)"],
122
+ "baseline (.maintainability/baseline.json)",
123
+ "secure-code-agent history (.secure-code/history.jsonl)"],
118
124
  "never_writes": ["source", "reports"],
119
125
  "allowed_roots": [str(root) for root in authorized_roots],
120
126
  # Stored grants this process will not honour. A hand-written
@@ -69,6 +69,7 @@ def render_ai_prompt(report: dict[str, Any]) -> str:
69
69
  "",
70
70
  ])
71
71
  lines.extend(prompt_analyzer_caveat(report))
72
+ lines.extend(prompt_security_pillar(report))
72
73
  # The prompt is the product artifact (H1): its remedy follows the
73
74
  # same report fact as every other skin, never a stale default.
74
75
  lines.extend(view.remediation_note(
@@ -155,6 +156,7 @@ from ._prompt_sections import ( # noqa: E402,F401 - re-export after the split
155
156
  prompt_focus_sections,
156
157
  prompt_has_work,
157
158
  prompt_pressure_section,
159
+ prompt_security_pillar,
158
160
  prompt_semantic_section,
159
161
  prompt_tdd_section,
160
162
  prompt_work_order,
@@ -214,6 +214,12 @@ def _bounded_markdown(report: dict[str, Any], score: dict[str, Any],
214
214
  lines.extend(summary)
215
215
  lines.extend(render_grade_blockers(report))
216
216
  lines.extend(score_table(score))
217
+ # The pillars, security among them, in the view most people read (D176).
218
+ # Rendered by the same function the complete report uses, so the two
219
+ # skins cannot disagree about a pillar (ADR 011); before this the chat
220
+ # view printed nothing about security at all, measured or not, and a
221
+ # missing pillar read exactly like a clean one (ADR 007).
222
+ lines.extend(pillars_markdown(report.get("pillars"), report.get("practice")))
217
223
  lines.extend([
218
224
  "---", "",
219
225
  "This is the bounded UI view. The complete report — every finding, "
@@ -22,6 +22,7 @@ from ._economics import economic_context_from, economic_impact, reorder_by_expos
22
22
  from ._metrics_types import FileMetric, FunctionMetric
23
23
  from ._pillars import pillar_report
24
24
  from ._practice import practice_level
25
+ from ._security_delegate import run_security_delegate
25
26
  from ._semantic import semantic_findings
26
27
  from ._semantic_policy import load_semantic_policy
27
28
  from ._semantic_ts import discover_type_analysis
@@ -399,27 +400,42 @@ def _attach_semantics(
399
400
 
400
401
  def _pillars_with_delegation(
401
402
  report: dict[str, Any], root: Path, pillar_path: str | None = None,
403
+ changed_revspec: str | None = None,
402
404
  ) -> list[dict[str, Any]]:
403
- """The pillar block, with a delegated pillar's own report folded in.
404
-
405
- ADR 007 §1 makes Security a delegated pillar naming
406
- `secure-code-agent`, reported as `NotApplicable` so silence is never
407
- read as safety. That was a placeholder for an artifact: when the
408
- other tool has left `security-pillar.json` in the tree, the entry
409
- carries its measurement instead of an apology for not having one.
410
-
411
- Absent, the entry stays exactly what it was. Most repositories run
412
- one tool, so that is the ordinary path and not a warning.
405
+ """The pillar block, with the delegated security pillar measured.
406
+
407
+ ADR 007 §1 makes Security a delegated pillar naming `secure-code-agent`.
408
+ Until D177 that was a handoff: the entry carried the other tool's
409
+ measurement only when a `security-pillar.json` had been left in the tree,
410
+ so every audit nobody had prepared — and every audit through the chat
411
+ door — reported the pillar unmeasured.
412
+
413
+ **The audit runs the delegate (D177).** An operator who names a document
414
+ with `--security-pillar` — CI, which runs secure-code-agent as its own
415
+ gated step — has that document used as given. Otherwise this audit runs
416
+ secure-code-agent itself. A `security-pillar.json` sitting in the tree is
417
+ no longer read on its own authority: it is repository content, and a
418
+ repository may not report its own security posture in place of a
419
+ measurement. When nothing trustworthy comes back, the entry says why.
413
420
 
414
421
  Its own function because `build_report` was at eighty lines against a
415
422
  limit of eighty, and adding this inline took it to eighty-eight —
416
423
  caught by this tool's gate on the commit that added it.
417
424
  """
418
- handed_over = (read_delegated(root, pillar_path) if pillar_path
419
- else read_delegated(root))
425
+ if pillar_path:
426
+ handed_over = read_delegated(root, pillar_path)
427
+ reason = None if handed_over else (
428
+ f"the --security-pillar document {pillar_path} was absent or could not be trusted")
429
+ else:
430
+ run = run_security_delegate(root, changed_revspec=changed_revspec)
431
+ handed_over, reason = run.document, run.reason
432
+ if run.environment:
433
+ report["environment_work_order"] = [
434
+ *(report.get("environment_work_order") or []), *run.environment]
420
435
  return pillar_report(
421
436
  report["score"], report["practice"],
422
437
  {"security": handed_over} if handed_over else None,
438
+ {"security": reason} if reason else None,
423
439
  )
424
440
 
425
441
 
@@ -490,7 +506,7 @@ def build_report(
490
506
  report["score"] = score_report(report, analyzer["pressures"])
491
507
  # Condition rolls up aspects; practice stays a separate axis (ADR 007).
492
508
  report["practice"] = practice_level(root, config).as_dict()
493
- report["pillars"] = _pillars_with_delegation(report, root, security_pillar)
509
+ report["pillars"] = _pillars_with_delegation(report, root, security_pillar, changed_revspec)
494
510
  _attach_semantics(report, root, config, only_paths)
495
511
  # Last, because every item's delta is a rubric recomputation and the
496
512
  # rubric needs the scored report to recompute against.