maintainability-agent 3.7.1__tar.gz → 3.7.4__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 (393) hide show
  1. {maintainability_agent-3.7.1/src/maintainability_agent.egg-info → maintainability_agent-3.7.4}/PKG-INFO +14 -3
  2. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/README.md +13 -1
  3. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/pyproject.toml +1 -9
  4. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4/src/maintainability_agent.egg-info}/PKG-INFO +14 -3
  5. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_agent.egg-info/SOURCES.txt +5 -0
  6. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_agent.egg-info/requires.txt +0 -1
  7. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/__init__.py +1 -1
  8. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_html_view.py +7 -2
  9. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_mcp_audit.py +6 -0
  10. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_prompt_sections.py +13 -6
  11. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_scan_view.py +8 -2
  12. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_security_delegate.py +57 -4
  13. maintainability_agent-3.7.4/src/maintainability_audit/_security_work_order.py +120 -0
  14. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_work_order.py +24 -6
  15. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_work_order_view.py +31 -7
  16. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/config.py +1 -1
  17. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/mcp_server.py +4 -1
  18. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/renderers.py +7 -2
  19. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/report.py +35 -18
  20. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_analyzer_pinning.py +6 -3
  21. maintainability_agent-3.7.4/tests/test_security_delegate_versions_agree.py +86 -0
  22. maintainability_agent-3.7.4/tests/test_security_findings_keep_their_handoff.py +156 -0
  23. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_security_pillar_runs_and_shows.py +38 -0
  24. maintainability_agent-3.7.4/tests/test_semantic_findings_stay_inside_the_audited_files.py +66 -0
  25. maintainability_agent-3.7.4/tests/test_withheld_work_keeps_its_boundary.py +107 -0
  26. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/LICENSE +0 -0
  27. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/setup.cfg +0 -0
  28. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_agent.egg-info/dependency_links.txt +0 -0
  29. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_agent.egg-info/entry_points.txt +0 -0
  30. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_agent.egg-info/top_level.txt +0 -0
  31. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/__main__.py +0 -0
  32. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_adapters.py +0 -0
  33. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_analysis.py +0 -0
  34. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_analyzer_sections.py +0 -0
  35. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_anchor.py +0 -0
  36. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_arguments.py +0 -0
  37. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_aspects.py +0 -0
  38. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_assets/analyzer-catalog.json +0 -0
  39. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_assets/standard.md +0 -0
  40. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_attestation.py +0 -0
  41. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_backfill.py +0 -0
  42. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_bands.py +0 -0
  43. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_banner.py +0 -0
  44. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_built_ins.py +0 -0
  45. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_calibration.py +0 -0
  46. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_catalog.py +0 -0
  47. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_charts.py +0 -0
  48. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_cognitive.py +0 -0
  49. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_config_defaults.py +0 -0
  50. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_conformance.py +0 -0
  51. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_corroborate.py +0 -0
  52. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_coverage_notes.py +0 -0
  53. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_criteria_scope.py +0 -0
  54. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_delegated_pillar.py +0 -0
  55. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_derive.py +0 -0
  56. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_discovery.py +0 -0
  57. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_documents.py +0 -0
  58. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_economics.py +0 -0
  59. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_economics_view.py +0 -0
  60. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_environment.py +0 -0
  61. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_evidence_reader.py +0 -0
  62. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_evidence_view.py +0 -0
  63. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_finding_match.py +0 -0
  64. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_first_run.py +0 -0
  65. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_formula.py +0 -0
  66. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_gates.py +0 -0
  67. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_generic.py +0 -0
  68. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_grammar.py +0 -0
  69. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_grant_ledger.py +0 -0
  70. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_history_view.py +0 -0
  71. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_hostile_prompt.py +0 -0
  72. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_hotspots.py +0 -0
  73. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_html_report_sections.py +0 -0
  74. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_identity.py +0 -0
  75. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_in_loop.py +0 -0
  76. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_in_loop_view.py +0 -0
  77. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_jvm_adapters.py +0 -0
  78. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_markdown_sections.py +0 -0
  79. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_masking.py +0 -0
  80. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_mcp_gate.py +0 -0
  81. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_mcp_grants.py +0 -0
  82. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_mcp_refusals.py +0 -0
  83. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_mcp_resources.py +0 -0
  84. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_mcp_setup.py +0 -0
  85. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_metric_adapters.py +0 -0
  86. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_metrics_types.py +0 -0
  87. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_operator_reads.py +0 -0
  88. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_pillars.py +0 -0
  89. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_practice.py +0 -0
  90. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_precommit.py +0 -0
  91. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_precommit_install.py +0 -0
  92. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_precommit_view.py +0 -0
  93. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_pressures.py +0 -0
  94. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_ranges_c.py +0 -0
  95. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_ranges_cobol.py +0 -0
  96. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_ranges_core.py +0 -0
  97. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_ranges_cpp.py +0 -0
  98. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_ranges_csharp.py +0 -0
  99. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_ranges_fortran.py +0 -0
  100. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_ranges_go.py +0 -0
  101. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_ranges_java.py +0 -0
  102. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_ranges_js.py +0 -0
  103. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_ranges_php.py +0 -0
  104. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_ranges_ruby.py +0 -0
  105. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_ranges_rust.py +0 -0
  106. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_ranges_swift.py +0 -0
  107. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_ratchet.py +0 -0
  108. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_ratio_adapters.py +0 -0
  109. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_recurrence.py +0 -0
  110. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_run_comparison.py +0 -0
  111. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_runner.py +0 -0
  112. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_safe_write.py +0 -0
  113. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_scan_history.py +0 -0
  114. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_second_source.py +0 -0
  115. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_selection.py +0 -0
  116. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_semantic.py +0 -0
  117. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_semantic_policy.py +0 -0
  118. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_semantic_ts.py +0 -0
  119. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_semantic_view.py +0 -0
  120. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_setup_errors.py +0 -0
  121. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_setup_persist.py +0 -0
  122. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_skill_data/SKILL.md +0 -0
  123. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_skill_data/agents/anthropic.yaml +0 -0
  124. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_skill_data/agents/copilot.yaml +0 -0
  125. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_skill_data/agents/openai.yaml +0 -0
  126. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_skill_data/copilot/maintainability-agent.prompt.md +0 -0
  127. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_skill_data/references/finding-taxonomy.md +0 -0
  128. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_skill_install.py +0 -0
  129. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_stored_grants.py +0 -0
  130. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_tdd_view.py +0 -0
  131. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_test_commands.py +0 -0
  132. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_test_execution.py +0 -0
  133. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_test_pairing.py +0 -0
  134. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_tokens.py +0 -0
  135. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_tool_adapters.py +0 -0
  136. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_trends.py +0 -0
  137. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_user_config.py +0 -0
  138. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_verdict_adapters.py +0 -0
  139. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_verification.py +0 -0
  140. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_work_order_weights.py +0 -0
  141. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/_xml.py +0 -0
  142. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/baseline.py +0 -0
  143. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/cli.py +0 -0
  144. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/deadcode.py +0 -0
  145. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/declarations.py +0 -0
  146. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/duplication.py +0 -0
  147. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/evidence.py +0 -0
  148. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/git_tools.py +0 -0
  149. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/history.py +0 -0
  150. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/idioms.py +0 -0
  151. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/instructions.py +0 -0
  152. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/metrics.py +0 -0
  153. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/prompts.py +0 -0
  154. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/sarif.py +0 -0
  155. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/scoring.py +0 -0
  156. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/similarity.py +0 -0
  157. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/src/maintainability_audit/source.py +0 -0
  158. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_acquisition_trust.py +0 -0
  159. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_adapter_docs.py +0 -0
  160. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_adapter_recordings.py +0 -0
  161. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_adapters.py +0 -0
  162. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_added_lines.py +0 -0
  163. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_analysis_coverage.py +0 -0
  164. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_analysis_execution.py +0 -0
  165. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_analyzer_bridge.py +0 -0
  166. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_analyzer_config_isolation.py +0 -0
  167. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_analyzer_estimate_claims.py +0 -0
  168. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_analyzer_primary_estimate.py +0 -0
  169. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_analyzer_provenance.py +0 -0
  170. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_analyzer_provenance_exclusions.py +0 -0
  171. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_analyzer_scoring_path.py +0 -0
  172. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_analyzer_spread_range.py +0 -0
  173. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_analyzer_xml_bounds.py +0 -0
  174. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_anchor_and_mode.py +0 -0
  175. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_anchor_caveat_and_counts_follow_the_run.py +0 -0
  176. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_anchor_disclosure.py +0 -0
  177. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_annotations_match_behaviour.py +0 -0
  178. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_anticipated_refusals.py +0 -0
  179. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_architecture.py +0 -0
  180. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_artifact_write_route_class.py +0 -0
  181. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_aspect_coverage.py +0 -0
  182. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_asset_snapshot_class.py +0 -0
  183. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_ast_reading_resolves_spellings.py +0 -0
  184. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_attestation.py +0 -0
  185. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_audit_components.py +0 -0
  186. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_authorization_freshness.py +0 -0
  187. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_authorship_gates.py +0 -0
  188. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_backfill.py +0 -0
  189. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_band_concealment_class.py +0 -0
  190. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_band_concealment_p3.py +0 -0
  191. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_band_pressures.py +0 -0
  192. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_bands.py +0 -0
  193. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_body_or_signature_class.py +0 -0
  194. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_build_output_is_not_the_repositorys_code.py +0 -0
  195. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_c_declarations.py +0 -0
  196. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_calibration_corpus.py +0 -0
  197. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_calibration_drift.py +0 -0
  198. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_calibration_tooling.py +0 -0
  199. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_catalog_selection.py +0 -0
  200. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_catalog_tier_promise.py +0 -0
  201. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_chat_leads_with_the_work_order.py +0 -0
  202. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_chat_primary_docs.py +0 -0
  203. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_check_refuses_plus_only_fragments.py +0 -0
  204. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_checkstyle_adapter.py +0 -0
  205. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_checkstyle_catalog.py +0 -0
  206. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_child_sandbox.py +0 -0
  207. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_ci_history_recipe.py +0 -0
  208. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_ci_installs_the_analyzer_pool.py +0 -0
  209. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_claimed_languages.py +0 -0
  210. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_cli.py +0 -0
  211. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_clone_group_class.py +0 -0
  212. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_cobol_declarations.py +0 -0
  213. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_cognitive_complexity.py +0 -0
  214. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_cohort_statistics.py +0 -0
  215. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_concealment_properties.py +0 -0
  216. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_config_shape.py +0 -0
  217. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_consent_and_grant.py +0 -0
  218. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_consumer_migration.py +0 -0
  219. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_contract_claims.py +0 -0
  220. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_corroborate.py +0 -0
  221. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_coverage_by_language.py +0 -0
  222. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_cpp_declarations.py +0 -0
  223. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_criteria_completion.py +0 -0
  224. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_csharp_declarations.py +0 -0
  225. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_d15_composition.py +0 -0
  226. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_d15_goal_directed.py +0 -0
  227. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_dead_code.py +0 -0
  228. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_declaration_criteria_scope.py +0 -0
  229. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_declaration_edge_cases.py +0 -0
  230. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_declaration_grading.py +0 -0
  231. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_declaration_ranges.py +0 -0
  232. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_declaration_source.py +0 -0
  233. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_declarative_parsers.py +0 -0
  234. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_declared_authorship.py +0 -0
  235. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_declared_imports.py +0 -0
  236. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_delegated_security_pillar.py +0 -0
  237. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_demo_tree.py +0 -0
  238. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_derivation_mix.py +0 -0
  239. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_determinism.py +0 -0
  240. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_dimension_ratchet.py +0 -0
  241. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_direct_runner_availability_class.py +0 -0
  242. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_discovery.py +0 -0
  243. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_doc_claims.py +0 -0
  244. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_docs_links.py +0 -0
  245. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_economic_context.py +0 -0
  246. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_empty_output_not_clean.py +0 -0
  247. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_empty_output_not_clean_adapters.py +0 -0
  248. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_environment_work_order.py +0 -0
  249. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_every_surface_says_what_the_run_found.py +0 -0
  250. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_evidence_invariants.py +0 -0
  251. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_evidence_normalization.py +0 -0
  252. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_evidence_properties.py +0 -0
  253. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_example_config_opens_claimed_languages.py +0 -0
  254. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_exclusion_dialects.py +0 -0
  255. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_exposure_never_outranks_band.py +0 -0
  256. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_falsifier_standard.py +0 -0
  257. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_file_list_cap_class.py +0 -0
  258. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_finding_identity.py +0 -0
  259. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_first_run_elicitation.py +0 -0
  260. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_first_run_prompt.py +0 -0
  261. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_first_run_reelicitation.py +0 -0
  262. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_fix_breadth_window.py +0 -0
  263. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_fixed_form_fortran.py +0 -0
  264. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_format_ask.py +0 -0
  265. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_fortran_declarations.py +0 -0
  266. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_fortran_metrics.py +0 -0
  267. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_fortran_practice.py +0 -0
  268. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_git_argv.py +0 -0
  269. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_git_read_only.py +0 -0
  270. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_git_readonly_class.py +0 -0
  271. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_go_declarations.py +0 -0
  272. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_grammar_constructs.py +0 -0
  273. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_grammar_token_coverage.py +0 -0
  274. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_grant_only_user_tier.py +0 -0
  275. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_history.py +0 -0
  276. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_history_boundary.py +0 -0
  277. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_history_manifest.py +0 -0
  278. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_history_schema2.py +0 -0
  279. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_history_window.py +0 -0
  280. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_hostile_prompt.py +0 -0
  281. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_html_executive.py +0 -0
  282. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_html_section_parity_class.py +0 -0
  283. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_identity_docs.py +0 -0
  284. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_identity_resolution.py +0 -0
  285. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_idiom_divergence.py +0 -0
  286. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_in_loop_budgets.py +0 -0
  287. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_in_loop_check.py +0 -0
  288. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_installed_wheel_runtime.py +0 -0
  289. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_instruction_targets.py +0 -0
  290. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_java_range_guard.py +0 -0
  291. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_java_ranges.py +0 -0
  292. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_java_scored.py +0 -0
  293. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_java_wiring.py +0 -0
  294. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_js_complexity_operators.py +0 -0
  295. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_js_declarations.py +0 -0
  296. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_language_coverage.py +0 -0
  297. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_language_support_honesty.py +0 -0
  298. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_mcp_baseline_payload.py +0 -0
  299. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_mcp_format_contract.py +0 -0
  300. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_mcp_history.py +0 -0
  301. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_mcp_server.py +0 -0
  302. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_mcp_start_failure_names_what_is_installed.py +0 -0
  303. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_migration_1_0.py +0 -0
  304. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_near_duplicates.py +0 -0
  305. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_network_disclosure.py +0 -0
  306. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_one_setup_across_surfaces_class.py +0 -0
  307. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_operator_named_paths.py +0 -0
  308. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_operator_named_reads.py +0 -0
  309. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_pairing_reads_imports.py +0 -0
  310. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_pattern_budget.py +0 -0
  311. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_phase6_claims.py +0 -0
  312. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_php_declarations.py +0 -0
  313. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_pillars_and_practice.py +0 -0
  314. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_platform_claim.py +0 -0
  315. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_pmd_adapter.py +0 -0
  316. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_pmd_audit_closures.py +0 -0
  317. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_policy_claims.py +0 -0
  318. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_pool_runs_by_config.py +0 -0
  319. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_population_floors.py +0 -0
  320. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_practice_nested_gates_class.py +0 -0
  321. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_precommit_staged.py +0 -0
  322. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_presentation_refusals.py +0 -0
  323. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_promises.py +0 -0
  324. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_prompt_does_not_issue_rates_when_unscored.py +0 -0
  325. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_prompt_escalation_once.py +0 -0
  326. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_prompt_honesty.py +0 -0
  327. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_prompt_location_escalation_class.py +0 -0
  328. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_prove_falsifiers.py +0 -0
  329. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_python_complexity.py +0 -0
  330. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_python_declarations.py +0 -0
  331. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_read_boundary.py +0 -0
  332. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_readme_claims.py +0 -0
  333. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_recurrence.py +0 -0
  334. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_release_needs_an_empty_ledger.py +0 -0
  335. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_release_plan.py +0 -0
  336. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_release_plan_status.py +0 -0
  337. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_report_remedy_copy.py +0 -0
  338. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_roles_recorded.py +0 -0
  339. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_root_grants.py +0 -0
  340. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_rubric_ignores_project_lint_config.py +0 -0
  341. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_ruby_declarations.py +0 -0
  342. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_run_comparison.py +0 -0
  343. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_runner.py +0 -0
  344. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_rust_declarations.py +0 -0
  345. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_sarif.py +0 -0
  346. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_scan_history.py +0 -0
  347. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_scan_scope.py +0 -0
  348. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_scanner_unsafe_direction.py +0 -0
  349. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_scanning.py +0 -0
  350. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_schema_fidelity.py +0 -0
  351. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_scope_conformance.py +0 -0
  352. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_scoring_calibration.py +0 -0
  353. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_semantic_policy.py +0 -0
  354. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_setup_gate_completeness.py +0 -0
  355. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_setup_gate_independent_contract.py +0 -0
  356. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_setup_precondition.py +0 -0
  357. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_skill_install.py +0 -0
  358. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_sonar_resolve.py +0 -0
  359. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_source_index.py +0 -0
  360. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_spotbugs_adapter.py +0 -0
  361. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_spotbugs_catalog.py +0 -0
  362. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_stage8_contract.py +0 -0
  363. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_stdout_outputs.py +0 -0
  364. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_suite_isolation.py +0 -0
  365. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_swift_declarations.py +0 -0
  366. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_tdd_structure.py +0 -0
  367. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_terminal_asks_the_same_questions.py +0 -0
  368. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_test_commands.py +0 -0
  369. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_test_execution_class.py +0 -0
  370. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_three_presentations.py +0 -0
  371. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_tool_resolution.py +0 -0
  372. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_tree_cannot_opt_the_host_in.py +0 -0
  373. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_tree_chosen_spawn.py +0 -0
  374. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_tree_reads_use_the_primitive.py +0 -0
  375. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_trends.py +0 -0
  376. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_type_fields_not_functions_class.py +0 -0
  377. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_uat_falsifiers.py +0 -0
  378. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_unanchored_set_matches_corpus.py +0 -0
  379. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_unread_code.py +0 -0
  380. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_user_config_tier.py +0 -0
  381. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_verification_audit_closures.py +0 -0
  382. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_verified_grade.py +0 -0
  383. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_version_claim.py +0 -0
  384. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_wheel_contents.py +0 -0
  385. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_work_items_state_their_own_finding.py +0 -0
  386. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_work_order.py +0 -0
  387. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_work_order_binds_to_this_interpreter.py +0 -0
  388. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_work_order_items.py +0 -0
  389. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_work_order_selection.py +0 -0
  390. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_workflow_supply_chain.py +0 -0
  391. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_write_boundary.py +0 -0
  392. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/tests/test_write_route_class.py +0 -0
  393. {maintainability_agent-3.7.1 → maintainability_agent-3.7.4}/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.7.1
3
+ Version: 3.7.4
4
4
  Summary: Maintainability gate and AI remediation prompt generator for CI.
5
5
  Author: Marshall Guillory
6
6
  License: MIT
@@ -19,7 +19,6 @@ 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
23
22
  Provides-Extra: test
24
23
  Requires-Dist: pytest>=8; extra == "test"
25
24
  Requires-Dist: pytest-cov>=5; extra == "test"
@@ -47,7 +46,7 @@ Dynamic: license-file
47
46
  **A deterministic, offline maintainability audit whose output is a _bounded
48
47
  work order_ for an AI coding agent** — a copy-paste prompt, per finding, that
49
48
  says *fix exactly these and refactor nothing else*. Chat-primary; CLI for CI.
50
- Version **3.7.1**.
49
+ Version **3.7.4**.
51
50
 
52
51
  **Languages parsed:** Python, Java, C, C++, C#, Go, Rust, PHP, Ruby, Swift,
53
52
  COBOL, Fortran (free-form *and* fixed-form), and the JS/TS/HTML family — each
@@ -81,6 +80,18 @@ and `test_the_readme_names_the_analyzer_pool_ci_installs` fails if the two ever
81
80
  disagree. Nothing here is required — the audit runs without any of it and tells
82
81
  you what it could not measure.
83
82
 
83
+ **Install secure-code-agent for the security pillar.** Every audit runs it; it is
84
+ installed alongside rather than as a dependency, so the two tools release
85
+ independently. Without it the report says the security pillar was not measured
86
+ and gives this command. Its scanners decide what it can grade — see
87
+ [machine setup](docs/machine-setup.md#4-toolchain) for which to install, and
88
+ don't add its `[mcp]` extra to this environment (it pins `mcp<2`).
89
+
90
+ ```bash
91
+ pip install 'secure-code-agent>=0.12.1'
92
+ brew install gitleaks osv-scanner semgrep checkov # its scanners; pip install bandit
93
+ ```
94
+
84
95
  **One command to a work order.** A config file is the whole setup — with one
85
96
  present, nothing is asked and nothing is written into your tree:
86
97
 
@@ -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.7.1**.
8
+ Version **3.7.4**.
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
@@ -39,6 +39,18 @@ and `test_the_readme_names_the_analyzer_pool_ci_installs` fails if the two ever
39
39
  disagree. Nothing here is required — the audit runs without any of it and tells
40
40
  you what it could not measure.
41
41
 
42
+ **Install secure-code-agent for the security pillar.** Every audit runs it; it is
43
+ installed alongside rather than as a dependency, so the two tools release
44
+ independently. Without it the report says the security pillar was not measured
45
+ and gives this command. Its scanners decide what it can grade — see
46
+ [machine setup](docs/machine-setup.md#4-toolchain) for which to install, and
47
+ don't add its `[mcp]` extra to this environment (it pins `mcp<2`).
48
+
49
+ ```bash
50
+ pip install 'secure-code-agent>=0.12.1'
51
+ brew install gitleaks osv-scanner semgrep checkov # its scanners; pip install bandit
52
+ ```
53
+
42
54
  **One command to a work order.** A config file is the whole setup — with one
43
55
  present, nothing is asked and nothing is written into your tree:
44
56
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "maintainability-agent"
7
- version = "3.7.1"
7
+ version = "3.7.4"
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,14 +13,6 @@ 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
- ]
24
16
  license = { text = "MIT" }
25
17
  authors = [
26
18
  { name = "Marshall Guillory" }
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: maintainability-agent
3
- Version: 3.7.1
3
+ Version: 3.7.4
4
4
  Summary: Maintainability gate and AI remediation prompt generator for CI.
5
5
  Author: Marshall Guillory
6
6
  License: MIT
@@ -19,7 +19,6 @@ 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
23
22
  Provides-Extra: test
24
23
  Requires-Dist: pytest>=8; extra == "test"
25
24
  Requires-Dist: pytest-cov>=5; extra == "test"
@@ -47,7 +46,7 @@ Dynamic: license-file
47
46
  **A deterministic, offline maintainability audit whose output is a _bounded
48
47
  work order_ for an AI coding agent** — a copy-paste prompt, per finding, that
49
48
  says *fix exactly these and refactor nothing else*. Chat-primary; CLI for CI.
50
- Version **3.7.1**.
49
+ Version **3.7.4**.
51
50
 
52
51
  **Languages parsed:** Python, Java, C, C++, C#, Go, Rust, PHP, Ruby, Swift,
53
52
  COBOL, Fortran (free-form *and* fixed-form), and the JS/TS/HTML family — each
@@ -81,6 +80,18 @@ and `test_the_readme_names_the_analyzer_pool_ci_installs` fails if the two ever
81
80
  disagree. Nothing here is required — the audit runs without any of it and tells
82
81
  you what it could not measure.
83
82
 
83
+ **Install secure-code-agent for the security pillar.** Every audit runs it; it is
84
+ installed alongside rather than as a dependency, so the two tools release
85
+ independently. Without it the report says the security pillar was not measured
86
+ and gives this command. Its scanners decide what it can grade — see
87
+ [machine setup](docs/machine-setup.md#4-toolchain) for which to install, and
88
+ don't add its `[mcp]` extra to this environment (it pins `mcp<2`).
89
+
90
+ ```bash
91
+ pip install 'secure-code-agent>=0.12.1'
92
+ brew install gitleaks osv-scanner semgrep checkov # its scanners; pip install bandit
93
+ ```
94
+
84
95
  **One command to a work order.** A config file is the whole setup — with one
85
96
  present, nothing is asked and nothing is written into your tree:
86
97
 
@@ -95,6 +95,7 @@ src/maintainability_audit/_scan_history.py
95
95
  src/maintainability_audit/_scan_view.py
96
96
  src/maintainability_audit/_second_source.py
97
97
  src/maintainability_audit/_security_delegate.py
98
+ src/maintainability_audit/_security_work_order.py
98
99
  src/maintainability_audit/_selection.py
99
100
  src/maintainability_audit/_semantic.py
100
101
  src/maintainability_audit/_semantic_policy.py
@@ -342,7 +343,10 @@ tests/test_scanning.py
342
343
  tests/test_schema_fidelity.py
343
344
  tests/test_scope_conformance.py
344
345
  tests/test_scoring_calibration.py
346
+ tests/test_security_delegate_versions_agree.py
347
+ tests/test_security_findings_keep_their_handoff.py
345
348
  tests/test_security_pillar_runs_and_shows.py
349
+ tests/test_semantic_findings_stay_inside_the_audited_files.py
346
350
  tests/test_semantic_policy.py
347
351
  tests/test_setup_gate_completeness.py
348
352
  tests/test_setup_gate_independent_contract.py
@@ -375,6 +379,7 @@ tests/test_verification_audit_closures.py
375
379
  tests/test_verified_grade.py
376
380
  tests/test_version_claim.py
377
381
  tests/test_wheel_contents.py
382
+ tests/test_withheld_work_keeps_its_boundary.py
378
383
  tests/test_work_items_state_their_own_finding.py
379
384
  tests/test_work_order.py
380
385
  tests/test_work_order_binds_to_this_interpreter.py
@@ -1,4 +1,3 @@
1
- secure-code-agent<0.11,>=0.10
2
1
 
3
2
  [dev]
4
3
  pytest>=8
@@ -1,3 +1,3 @@
1
1
  """Maintainability Audit CI."""
2
2
 
3
- __version__ = "3.7.1"
3
+ __version__ = "3.7.4"
@@ -26,7 +26,9 @@ from . import _charts
26
26
  from . import _evidence_view as view
27
27
  from ._grammar import agreement
28
28
  from ._html_report_sections import coverage_section, remaining_sections, trend_section
29
+ from ._security_work_order import complete_html as security_work_order_html
29
30
  from ._semantic_view import semantic_class_label
31
+ from ._work_order import escalated_fingerprints
30
32
  from ._work_order_view import prompt_body_lines
31
33
 
32
34
  _SEVERITY_BY_RISK = {5: "Severe", 4: "High", 3: "Medium"}
@@ -82,6 +84,7 @@ def render_html(report: dict[str, Any], records: list[Any]) -> str:
82
84
  *trend_section(report),
83
85
  *remaining_sections(report),
84
86
  *_work_order_section(report),
87
+ *security_work_order_html(report),
85
88
  *_hard_gate_section(report),
86
89
  *_unidentified_paths_section(report),
87
90
  *_semantic_section(report),
@@ -290,10 +293,12 @@ def _work_order_section(report: dict[str, Any]) -> list[str]:
290
293
  rows.extend([
291
294
  "<h3>Copy-paste prompts</h3>",
292
295
  "<p>One self-contained prompt per item — copy any block into a coding "
293
- "agent.</p>",
296
+ "agent. A block for an item that needs a design decision asks for that "
297
+ "decision, not a patch.</p>",
294
298
  ])
299
+ escalated = escalated_fingerprints(report)
295
300
  for item in items:
296
- body = "\n".join(prompt_body_lines(item, root_label))
301
+ body = "\n".join(prompt_body_lines(item, root_label, escalated))
297
302
  rows.append(f"<h4>{escape(str(item.get('title') or ''))}</h4>")
298
303
  rows.append(f"<pre>{escape(body)}</pre>")
299
304
  return rows
@@ -37,6 +37,7 @@ from ._scan_history import (
37
37
  record_of,
38
38
  segments,
39
39
  )
40
+ from ._security_work_order import KEY as SECURITY_WORK_ORDER
40
41
  from ._stored_grants import (
41
42
  StaleStandingGrant,
42
43
  refuse_a_stale_standing_grant,
@@ -301,6 +302,11 @@ def _top_level_result(report: dict[str, Any], root: Path, status: str,
301
302
  # travels only for json, so the remedy cannot live only inside it.
302
303
  if report.get("environment_work_order"):
303
304
  result["environment_work_order"] = report["environment_work_order"]
305
+ # D179, on the same reasoning: the bounded chat view has no room for
306
+ # secure-code-agent's whole work order, and the report dict travels only
307
+ # for json, so it rides every format at the top level.
308
+ if report.get(SECURITY_WORK_ORDER):
309
+ result[SECURITY_WORK_ORDER] = report[SECURITY_WORK_ORDER]
304
310
  if include_prompt:
305
311
  result["remediation_prompt"] = render_ai_prompt(report)
306
312
  return result
@@ -24,8 +24,10 @@ from typing import Any
24
24
 
25
25
  from . import _evidence_view as view
26
26
  from ._hotspots import hotspot_measure, hotspot_name
27
+ from ._security_work_order import KEY as SECURITY_WORK_ORDER
28
+ from ._security_work_order import severity_counts
27
29
  from ._tdd_view import tdd_sentences
28
- from ._work_order import prompt_items
30
+ from ._work_order import escalated_fingerprints, prompt_items
29
31
 
30
32
 
31
33
  def prompt_tdd_section(report: dict[str, Any]) -> list[str]:
@@ -134,10 +136,18 @@ def prompt_security_pillar(report: dict[str, Any]) -> list[str]:
134
136
  producer = entry.get("delegated_to") or "the delegated tool"
135
137
  version = f" {entry['producer_version']}" if entry.get("producer_version") else ""
136
138
  condition = "not graded" if entry.get("condition") is None else f"{entry['condition']:.1f}"
139
+ counts = severity_counts(entry)
140
+ found = f" Findings: {counts}." if counts else ""
141
+ # Where that tool's work order is, when this run kept it (D179). The
142
+ # prompt names it rather than absorbing it: the security findings are
143
+ # not this prompt's task, and are not re-ranked into it.
144
+ where = (f" Its own work order for them is `{SECURITY_WORK_ORDER}`, in the report."
145
+ if report.get(SECURITY_WORK_ORDER) else "")
137
146
  return [
138
147
  f"**Security pillar (measured by {producer}{version}):** posture "
139
148
  f"{entry.get('posture')}, practice level {entry.get('practice')}, condition "
140
- f"{condition}. Its findings are that tool's work order, not this one.",
149
+ f"{condition}.{found} Its findings are that tool's work order, not this "
150
+ f"one.{where}",
141
151
  "",
142
152
  ]
143
153
 
@@ -188,10 +198,7 @@ def _prompt_work_items(report: dict[str, Any]) -> list[dict[str, Any]]:
188
198
  # Withhold anything the history shows was fixed and came back
189
199
  # twice. Naming it as a design candidate while asking an agent to
190
200
  # patch it a third time would change nothing.
191
- escalated = {
192
- item["fingerprint"] for item in report.get("design_review_candidates") or []
193
- }
194
- return prompt_items(report.get("work_order") or [], escalated=escalated)
201
+ return prompt_items(report.get("work_order") or [], escalated=escalated_fingerprints(report))
195
202
 
196
203
 
197
204
  def prompt_has_work(report: dict[str, Any]) -> bool:
@@ -19,6 +19,7 @@ from __future__ import annotations
19
19
  from typing import Any
20
20
 
21
21
  from ._coverage_notes import coverage_notes
22
+ from ._security_work_order import severity_counts
22
23
 
23
24
 
24
25
  def _by_language_rows(coverage: dict[str, Any]) -> list[str]:
@@ -364,15 +365,20 @@ def pillar_cells(entry: dict[str, Any]) -> tuple[str, str]:
364
365
  condition = "—" if entry["condition"] is None else f"{entry['condition']:.1f}"
365
366
  if entry["posture"] is None:
366
367
  return condition, "not measured — see below"
368
+ # What the producer found, in both states: an ungraded pillar still
369
+ # counted its findings, and printing only why no grade was issued hid
370
+ # five critical ones behind "scanner coverage is partial" (D179).
371
+ counts = severity_counts(entry)
372
+ found = f"; findings: {counts}" if counts else ""
367
373
  if entry["condition"] is None:
368
374
  # An ungraded pillar is `unverified` because nothing could be graded,
369
375
  # not because a clean scan lacks enforcement — the note for that cell
370
376
  # told a reader of secure-code-agent's partial-coverage pillar that
371
377
  # its scan was clean (D176). Say why no grade was issued instead.
372
378
  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}"
379
+ return condition, f"{entry['posture']}: not graded — {why}{found}"
374
380
  note = POSTURE_NOTE.get(entry["posture"], entry["posture"])
375
- return condition, f"{entry['posture']}: {note}"
381
+ return condition, f"{entry['posture']}: {note}{found}"
376
382
 
377
383
 
378
384
  def _pillar_row(entry: dict[str, Any]) -> str:
@@ -11,7 +11,8 @@ Marshall: the pillar is complete, so the audit runs it.
11
11
  **What the child writes.** Every report `secure-code-agent` can produce is
12
12
  redirected into a temporary directory this process owns: the Markdown and
13
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
14
+ document itself. The pillar document and the remediation prompt — that
15
+ tool's work order — are read back before the directory goes (D179). The one write that cannot be redirected is its append-only
15
16
  trend, `.secure-code/history.jsonl` in the audited tree, which it writes on
16
17
  every run from its own configuration. Turning that off would mean handing
17
18
  it a configuration from outside the tree, and `secure-code-agent` trusts an
@@ -44,8 +45,19 @@ from typing import Any
44
45
  from ._delegated_pillar import read_produced
45
46
  from ._runner import Invocation, Outcome, run
46
47
 
47
- #: The distribution the pillar requires, and the range this tool reads.
48
- REQUIREMENT = "secure-code-agent>=0.10,<0.11"
48
+ #: The releases this audit runs, and the install command's requirement.
49
+ #:
50
+ #: **Not a package dependency.** 3.7.0 made it one, and within the day it
51
+ #: capped the tool below its current release — installing this package
52
+ #: downgraded a machine's secure-code-agent — and put the two tools' opposed
53
+ #: `mcp` pins into one environment. secure-code-agent's D3 and this project's
54
+ #: ADR 008 both hold the tools independently releasable. So the audit runs
55
+ #: whichever release is installed, when it falls in this range, and says so
56
+ #: when it does not. The ceiling is the next major: within 0.x the pillar
57
+ #: document is versioned by its own `schema_version`, which the reader checks.
58
+ SUPPORTED_FLOOR = (0, 12, 1)
59
+ SUPPORTED_CEILING = (1,)
60
+ REQUIREMENT = "secure-code-agent>=0.12.1,<1"
49
61
 
50
62
  #: How long the child may run before the pillar is reported as unmeasured.
51
63
  DEFAULT_TIMEOUT_SECONDS = 300
@@ -60,6 +72,9 @@ class DelegateRun:
60
72
  document: dict[str, Any] | None
61
73
  reason: str | None = None
62
74
  environment: list[dict[str, str]] = field(default_factory=list)
75
+ #: The delegate's own remediation prompt — its work order — read before
76
+ #: the directory it was written into is deleted (D179).
77
+ work_order: str | None = None
63
78
 
64
79
 
65
80
  def _install_remedy(reason: str) -> dict[str, str]:
@@ -82,6 +97,12 @@ def run_security_delegate(
82
97
  if importlib.util.find_spec("secure_code_audit") is None:
83
98
  reason = "secure-code-agent is not installed for the interpreter running this audit"
84
99
  return DelegateRun(None, reason, [_install_remedy(reason)])
100
+ installed = _installed_version()
101
+ if installed is None or not (SUPPORTED_FLOOR <= installed < SUPPORTED_CEILING):
102
+ shown = ".".join(map(str, installed)) if installed else "an unreadable version"
103
+ reason = (f"secure-code-agent {shown} is installed; this audit runs "
104
+ f"{REQUIREMENT.removeprefix('secure-code-agent')}")
105
+ return DelegateRun(None, reason, [_install_remedy(reason)])
85
106
  with tempfile.TemporaryDirectory(prefix="ma-security-") as scratch:
86
107
  out = Path(scratch)
87
108
  pillar = out / "security-pillar.json"
@@ -103,7 +124,7 @@ def run_security_delegate(
103
124
  ), timeout_seconds=timeout_seconds)
104
125
  document = read_produced(pillar)
105
126
  if document is not None:
106
- return DelegateRun(document)
127
+ return DelegateRun(document, work_order=_read_text(out / "prompt.md"))
107
128
  if result.outcome is Outcome.TIMED_OUT:
108
129
  return DelegateRun(None, f"secure-code-agent did not finish within {timeout_seconds}s")
109
130
  detail = _last_line(result.stderr) or _last_line(result.stdout) or result.detail
@@ -116,6 +137,38 @@ def run_security_delegate(
116
137
  return DelegateRun(None, reason)
117
138
 
118
139
 
140
+ def _installed_version() -> tuple[int, ...] | None:
141
+ """The installed release as integers, or `None` when it cannot be read.
142
+
143
+ No `packaging` import: this package has no runtime dependencies. A
144
+ pre-release or local suffix is cut at the first non-numeric part, which
145
+ compares a `0.13.0rc1` as `0.13.0` — conservative at the ceiling.
146
+ """
147
+ import importlib.metadata as metadata
148
+ import re
149
+
150
+ try:
151
+ text = metadata.version("secure-code-agent")
152
+ except metadata.PackageNotFoundError:
153
+ return None
154
+ parts = []
155
+ for piece in text.split("."):
156
+ match = re.match(r"\d+", piece)
157
+ if not match:
158
+ break
159
+ parts.append(int(match.group()))
160
+ if match.group() != piece:
161
+ break
162
+ return tuple(parts) or None
163
+
164
+
165
+ def _read_text(path: Path) -> str | None:
166
+ try:
167
+ return path.read_text(encoding="utf-8")
168
+ except (OSError, UnicodeDecodeError):
169
+ return None
170
+
171
+
119
172
  def _last_line(text: str | None) -> str:
120
173
  lines = [line.strip() for line in (text or "").splitlines() if line.strip()]
121
174
  return lines[-1][:200] if lines else ""
@@ -0,0 +1,120 @@
1
+ """What secure-code-agent found, and its own work order for it (D179).
2
+
3
+ 3.7.0 made every audit run secure-code-agent (D177), and then kept one
4
+ thing from that run: the pillar document. An audit of this repository
5
+ recorded five critical findings and one high, and every skin printed
6
+ "unverified: not graded — scanner coverage is partial" with no count. The
7
+ remediation prompt secure-code-agent had written — 74 findings to fix, 5 to
8
+ review, each located and constrained — sat in a temporary directory that
9
+ was deleted before the report was built. The run measured the work and the
10
+ reader was handed neither its size nor its instructions.
11
+
12
+ **Two things, each where it is read.** The severity counts come from the
13
+ pillar document and appear wherever the pillar does. The work order is
14
+ secure-code-agent's own text, carried unchanged under `security_work_order`
15
+ and printed whole in the complete reports. It stays that tool's work order,
16
+ not this one's: this tool does not re-rank, merge or reword security
17
+ findings (ADR 007 §1), so the maintainability prompt names it and does not
18
+ absorb it.
19
+ """
20
+ from __future__ import annotations
21
+
22
+ from html import escape
23
+ from typing import Any
24
+
25
+ #: The report key, and the chat door's top-level key, that carries it.
26
+ KEY = "security_work_order"
27
+
28
+ _ORDER = ("critical", "high", "medium", "low", "informational")
29
+
30
+
31
+ def severity_counts(entry: dict[str, Any]) -> str | None:
32
+ """`5 critical, 1 high, …` from a measured pillar, or `None` when it carries none.
33
+
34
+ A pillar document with an empty count reads "no findings": that is the
35
+ producer's statement, and it is different from a pillar with no count at
36
+ all, which says nothing and is printed as nothing.
37
+ """
38
+ counts = entry.get("findings_by_severity")
39
+ if not isinstance(counts, dict):
40
+ return None
41
+ named = [name for name in _ORDER if counts.get(name)]
42
+ named += sorted(name for name in counts if name not in _ORDER and counts[name])
43
+ if not named:
44
+ return "no findings"
45
+ return ", ".join(f"{counts[name]} {name}" for name in named)
46
+
47
+
48
+ def carried(markdown: str | None, entry: dict[str, Any]) -> dict[str, Any] | None:
49
+ """The report entry for a work order the delegate wrote, or `None`."""
50
+ if not markdown or not markdown.strip():
51
+ return None
52
+ return {
53
+ "producer": entry.get("delegated_to"),
54
+ "producer_version": entry.get("producer_version"),
55
+ "markdown": markdown,
56
+ }
57
+
58
+
59
+ def _source(work_order: dict[str, Any]) -> str:
60
+ version = f" {work_order['producer_version']}" if work_order.get("producer_version") else ""
61
+ return f"{work_order.get('producer') or 'the delegated tool'}{version}"
62
+
63
+
64
+ def pointer_markdown(report: dict[str, Any]) -> list[str]:
65
+ """The bounded view's line: the work order exists, and where it is."""
66
+ work_order = report.get(KEY)
67
+ if not work_order:
68
+ return []
69
+ return [
70
+ f"**Security work order.** {_source(work_order)} wrote its own work order "
71
+ f"for these findings. It is carried whole as `{KEY}` and printed in the "
72
+ "complete Markdown and HTML reports.",
73
+ "",
74
+ ]
75
+
76
+
77
+ def _demoted(markdown: str) -> list[str]:
78
+ """The delegate's headings two levels down, so they nest under this report's.
79
+
80
+ Lines inside a fence are left alone: a `#` there is a comment in a quoted
81
+ snippet, not a heading.
82
+ """
83
+ lines = []
84
+ fenced = False
85
+ for line in markdown.rstrip("\n").splitlines():
86
+ if line.lstrip().startswith("```"):
87
+ fenced = not fenced
88
+ elif not fenced and line.startswith("#"):
89
+ line = "##" + line
90
+ lines.append(line)
91
+ return lines
92
+
93
+
94
+ def _intro(work_order: dict[str, Any]) -> str:
95
+ return (
96
+ f"Written by {_source(work_order)} and reproduced as it wrote it. It is "
97
+ "that tool's work order, not this one's: its findings are not re-ranked "
98
+ "or merged into the maintainability work order above."
99
+ )
100
+
101
+
102
+ def complete_markdown(report: dict[str, Any]) -> list[str]:
103
+ """The complete report's section: the delegate's work order, whole."""
104
+ work_order = report.get(KEY)
105
+ if not work_order:
106
+ return []
107
+ return ["## Security Work Order", "", _intro(work_order), "",
108
+ *_demoted(work_order["markdown"]), ""]
109
+
110
+
111
+ def complete_html(report: dict[str, Any]) -> list[str]:
112
+ """The HTML report's section: the same text, preformatted."""
113
+ work_order = report.get(KEY)
114
+ if not work_order:
115
+ return []
116
+ return [
117
+ "<h2>Security Work Order</h2>",
118
+ f"<p>{escape(_intro(work_order))}</p>",
119
+ f"<pre>{escape(work_order['markdown'])}</pre>",
120
+ ]
@@ -479,6 +479,29 @@ def combined_delta(report: dict[str, Any], items: list[dict[str, Any]]) -> float
479
479
  return round(max(0.0, (after or before) - before), 3)
480
480
 
481
481
 
482
+ def escalated_fingerprints(report: dict[str, Any]) -> set[str]:
483
+ """The findings history shows were fixed and came back, as fingerprints."""
484
+ return {item["fingerprint"] for item in report.get("design_review_candidates") or []}
485
+
486
+
487
+ def withheld_reason(item: dict[str, Any], escalated: set[str] | None = None) -> str | None:
488
+ """Why no agent is handed this item as a patch, or `None` when one is (D180).
489
+
490
+ The one rule the bounded prompt and every copy-paste block read. The
491
+ prompt withheld the demo's two duplicated blocks as needing a design
492
+ decision while the report's standalone block for each said "Task: remove
493
+ the duplicated block" — the same run authorising and forbidding the same
494
+ change, depending on which text was pasted.
495
+ """
496
+ if item["band"] == Band.MAJOR_PROJECT.value:
497
+ return ("it is a Major Project — the change it needs is a design "
498
+ "decision before code moves, not one reviewable patch")
499
+ if item.get("fingerprint") in (escalated or set()):
500
+ return ("it was fixed before and came back, so the same edit is known "
501
+ "not to hold and the surrounding design needs a decision")
502
+ return None
503
+
504
+
482
505
  def prompt_items(items: list[dict[str, Any]], limit: int = 12,
483
506
  escalated: set[str] | None = None) -> list[dict[str, Any]]:
484
507
  """Agent subset: no major projects, no escalated returns; Severe leads.
@@ -487,12 +510,7 @@ def prompt_items(items: list[dict[str, Any]], limit: int = 12,
487
510
  so a risk-5 item can still sit below hotter Quick Wins of other classes.
488
511
  The table can stay exposure-ordered; the paste of 12 cannot drop Severe.
489
512
  """
490
- blocked = escalated or set()
491
- eligible = [
492
- item for item in items
493
- if item["band"] != Band.MAJOR_PROJECT.value
494
- and item.get("fingerprint") not in blocked
495
- ]
513
+ eligible = [item for item in items if withheld_reason(item, escalated) is None]
496
514
  severe = [item for item in eligible if item.get("risk") == 5]
497
515
  rest = [item for item in eligible if item.get("risk") != 5]
498
516
  return _one_per_class(severe + rest)[:limit]
@@ -21,7 +21,7 @@ from __future__ import annotations
21
21
 
22
22
  from typing import Any
23
23
 
24
- from ._work_order import work_order_rows
24
+ from ._work_order import withheld_reason, work_order_rows
25
25
  from ._work_order_weights import AUDIT_VERIFICATION
26
26
 
27
27
  # The report lists the whole backlog; these caps apply only to the bounded
@@ -40,7 +40,9 @@ def item_location(item: dict[str, Any]) -> str:
40
40
  return item["path"] + (f":{item['line']}" if item.get("line") else "")
41
41
 
42
42
 
43
- def prompt_body_lines(item: dict[str, Any], root_label: str = ".") -> list[str]:
43
+ def prompt_body_lines(
44
+ item: dict[str, Any], root_label: str = ".", escalated: set[str] | None = None,
45
+ ) -> list[str]:
44
46
  """The copy-paste prompt text for one item, skin-agnostic.
45
47
 
46
48
  Deterministic: built entirely from the item's own fields, so the same
@@ -48,7 +50,26 @@ def prompt_body_lines(item: dict[str, Any], root_label: str = ".") -> list[str]:
48
50
  Markdown fences it as ``text`` and HTML wraps it in ``<pre>``; the text
49
51
  between is identical, so the two skins can never disagree about what an
50
52
  agent is being asked to do.
53
+
54
+ **A block travels alone, so it carries its own boundary (D180).** An
55
+ item the bounded prompt withholds is still listed with a block — a
56
+ human deciding on a forty-file deduplication needs to see it — but the
57
+ block asks for the decision, never the patch.
51
58
  """
59
+ withheld = withheld_reason(item, escalated)
60
+ if withheld:
61
+ return [
62
+ f"Repository: {root_label}",
63
+ f"Design decision needed, not a patch: {item['title']}.",
64
+ f"Location: {item_location(item)}",
65
+ f"Why: {item['rationale']}",
66
+ f"Direction once decided: {item['target']}.",
67
+ "",
68
+ f"Do not change code for this item, because {withheld}. Lay out the "
69
+ "options for the surrounding design — what each would change, and "
70
+ "where — then stop for a human decision. If this is a false "
71
+ "positive, say so.",
72
+ ]
52
73
  verify = item.get("verification") or AUDIT_VERIFICATION
53
74
  return [
54
75
  f"Repository: {root_label}",
@@ -63,7 +84,9 @@ def prompt_body_lines(item: dict[str, Any], root_label: str = ".") -> list[str]:
63
84
  ]
64
85
 
65
86
 
66
- def item_prompt_block(item: dict[str, Any], root_label: str = ".") -> list[str]:
87
+ def item_prompt_block(
88
+ item: dict[str, Any], root_label: str = ".", escalated: set[str] | None = None,
89
+ ) -> list[str]:
67
90
  """One item's copy-paste prompt as Markdown: heading, then a fenced block.
68
91
 
69
92
  Fenced as ``text`` so a reader copies the whole thing into a coding
@@ -76,7 +99,7 @@ def item_prompt_block(item: dict[str, Any], root_label: str = ".") -> list[str]:
76
99
  f"`{item_location(item)}` · {item['band']}",
77
100
  "",
78
101
  "```text",
79
- *prompt_body_lines(item, root_label),
102
+ *prompt_body_lines(item, root_label, escalated),
80
103
  "```",
81
104
  "",
82
105
  ]
@@ -114,7 +137,7 @@ _BAND_IS_PER_CLASS = (
114
137
 
115
138
  def work_order_markdown(
116
139
  items: list[dict[str, Any]] | None, *, complete: bool = False, root_label: str = ".",
117
- exposure_ordered: bool = False,
140
+ exposure_ordered: bool = False, escalated: set[str] | None = None,
118
141
  ) -> list[str]:
119
142
  """The ordered work, worth first, with a copy-paste prompt for each item.
120
143
 
@@ -149,10 +172,11 @@ def work_order_markdown(
149
172
  lines.extend([
150
173
  "### Copy-paste prompts", "",
151
174
  "One self-contained prompt per item — paste any block whole into a "
152
- "coding agent.", "",
175
+ "coding agent. A block for an item that needs a design decision asks "
176
+ "for that decision, not a patch.", "",
153
177
  ])
154
178
  for item in items[:limit]:
155
- lines.extend(item_prompt_block(item, root_label))
179
+ lines.extend(item_prompt_block(item, root_label, escalated))
156
180
  return lines
157
181
 
158
182