cov-loupe 3.0.0 → 4.0.0.pre

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 (281) hide show
  1. checksums.yaml +4 -4
  2. data/AGENTS.md +230 -0
  3. data/CLAUDE.md +5 -0
  4. data/CODE_OF_CONDUCT.md +62 -0
  5. data/CONTRIBUTING.md +102 -0
  6. data/GEMINI.md +5 -0
  7. data/README.md +154 -51
  8. data/RELEASE_NOTES.md +452 -0
  9. data/dev/images/cov-loupe-icon-lores.png +0 -0
  10. data/dev/images/cov-loupe-icon-square.png +0 -0
  11. data/dev/images/cov-loupe-icon.png +0 -0
  12. data/dev/images/cov-loupe-logo.png +0 -0
  13. data/dev/prompts/README.md +74 -0
  14. data/dev/prompts/archive/architectural-review-and-actions-prompt.md +53 -0
  15. data/dev/prompts/archive/investigate-and-report-issues-prompt.md +33 -0
  16. data/dev/prompts/archive/produce-action-items-prompt.md +25 -0
  17. data/dev/prompts/guidelines/ai-code-evaluator-guidelines.md +337 -0
  18. data/dev/prompts/improve/refactor-test-suite.md +18 -0
  19. data/dev/prompts/improve/simplify-code-logic.md +133 -0
  20. data/dev/prompts/improve/update-documentation.md +21 -0
  21. data/dev/prompts/review/comprehensive-codebase-review.md +176 -0
  22. data/dev/prompts/review/identify-action-items.md +143 -0
  23. data/dev/prompts/review/verify-code-changes.md +54 -0
  24. data/dev/prompts/validate/create-screencast-outline.md +234 -0
  25. data/dev/prompts/validate/test-documentation-examples.md +180 -0
  26. data/docs/QUICKSTART.md +63 -0
  27. data/docs/assets/images/cov-loupe-logo-lores.png +0 -0
  28. data/docs/assets/images/cov-loupe-logo.png +0 -0
  29. data/docs/assets/images/favicon.png +0 -0
  30. data/docs/assets/stylesheets/branding.css +16 -0
  31. data/docs/assets/stylesheets/extra.css +15 -0
  32. data/docs/code_of_conduct.md +1 -0
  33. data/docs/contributing.md +1 -0
  34. data/docs/dev/ARCHITECTURE.md +56 -11
  35. data/docs/dev/DEVELOPMENT.md +116 -12
  36. data/docs/dev/FUTURE_ENHANCEMENTS.md +14 -0
  37. data/docs/dev/README.md +3 -2
  38. data/docs/dev/RELEASING.md +2 -0
  39. data/docs/dev/arch-decisions/README.md +10 -7
  40. data/docs/dev/arch-decisions/application-architecture.md +259 -0
  41. data/docs/dev/arch-decisions/coverage-data-quality.md +193 -0
  42. data/docs/dev/arch-decisions/output-character-mode.md +217 -0
  43. data/docs/dev/arch-decisions/path-resolution.md +90 -0
  44. data/docs/dev/arch-decisions/{004-x-arch-decision.md → policy-validation.md} +32 -28
  45. data/docs/dev/arch-decisions/{005-x-arch-decision.md → simplecov-integration.md} +47 -44
  46. data/docs/dev/presentations/cov-loupe-presentation.md +15 -13
  47. data/docs/examples/mcp-inputs.md +3 -0
  48. data/docs/examples/prompts.md +3 -0
  49. data/docs/examples/success_predicates.md +3 -0
  50. data/docs/fixtures/demo_project/.resultset.json +170 -0
  51. data/docs/fixtures/demo_project/README.md +6 -0
  52. data/docs/fixtures/demo_project/app/controllers/admin/audit_logs_controller.rb +19 -0
  53. data/docs/fixtures/demo_project/app/controllers/orders_controller.rb +26 -0
  54. data/docs/fixtures/demo_project/app/models/order.rb +20 -0
  55. data/docs/fixtures/demo_project/app/models/user.rb +19 -0
  56. data/docs/fixtures/demo_project/lib/api/client.rb +22 -0
  57. data/docs/fixtures/demo_project/lib/ops/jobs/cleanup_job.rb +16 -0
  58. data/docs/fixtures/demo_project/lib/ops/jobs/report_job.rb +17 -0
  59. data/docs/fixtures/demo_project/lib/payments/processor.rb +15 -0
  60. data/docs/fixtures/demo_project/lib/payments/refund_service.rb +15 -0
  61. data/docs/fixtures/demo_project/lib/payments/reporting/exporter.rb +16 -0
  62. data/docs/index.md +1 -0
  63. data/docs/license.md +3 -0
  64. data/docs/release_notes.md +3 -0
  65. data/docs/user/ADVANCED_USAGE.md +208 -115
  66. data/docs/user/CLI_FALLBACK_FOR_LLMS.md +2 -0
  67. data/docs/user/CLI_USAGE.md +276 -101
  68. data/docs/user/ERROR_HANDLING.md +4 -4
  69. data/docs/user/EXAMPLES.md +121 -128
  70. data/docs/user/INSTALLATION.md +9 -28
  71. data/docs/user/LIBRARY_API.md +227 -122
  72. data/docs/user/MCP_INTEGRATION.md +114 -203
  73. data/docs/user/README.md +5 -1
  74. data/docs/user/TROUBLESHOOTING.md +49 -27
  75. data/docs/user/installing-a-prelease-version-of-covloupe.md +43 -0
  76. data/docs/user/{V2-BREAKING-CHANGES.md → migrations/MIGRATING_TO_V2.md} +62 -72
  77. data/docs/user/migrations/MIGRATING_TO_V3.md +72 -0
  78. data/docs/user/migrations/MIGRATING_TO_V4.md +591 -0
  79. data/docs/user/migrations/README.md +22 -0
  80. data/docs/user/prompts/README.md +9 -0
  81. data/docs/user/prompts/non-web-coverage-analysis-prompt.md +103 -0
  82. data/docs/user/prompts/rails-coverage-analysis-prompt.md +94 -0
  83. data/docs/user/prompts/use-cli-not-mcp-prompt.md +53 -0
  84. data/examples/cli_demo.sh +77 -0
  85. data/examples/filter_and_table_demo-output.md +114 -0
  86. data/examples/filter_and_table_demo.rb +174 -0
  87. data/examples/fixtures/demo_project/coverage/.resultset.json +10 -0
  88. data/examples/mcp-inputs/README.md +66 -0
  89. data/examples/mcp-inputs/coverage_detailed.json +1 -0
  90. data/examples/mcp-inputs/coverage_raw.json +1 -0
  91. data/examples/mcp-inputs/coverage_summary.json +1 -0
  92. data/examples/mcp-inputs/list.json +1 -0
  93. data/examples/mcp-inputs/uncovered_lines.json +1 -0
  94. data/examples/prompts/README.md +27 -0
  95. data/examples/prompts/custom_resultset.txt +2 -0
  96. data/examples/prompts/detailed_with_source.txt +2 -0
  97. data/examples/prompts/list_lowest.txt +2 -0
  98. data/examples/prompts/summary.txt +2 -0
  99. data/examples/prompts/uncovered.txt +2 -0
  100. data/examples/success_predicates/README.md +198 -0
  101. data/examples/success_predicates/all_files_above_threshold_predicate.rb +21 -0
  102. data/examples/success_predicates/directory_specific_thresholds_predicate.rb +30 -0
  103. data/examples/success_predicates/project_coverage_minimum_predicate.rb +6 -0
  104. data/lib/cov_loupe/base_tool.rb +229 -20
  105. data/lib/cov_loupe/cli.rb +132 -23
  106. data/lib/cov_loupe/commands/base_command.rb +25 -6
  107. data/lib/cov_loupe/commands/command_factory.rb +0 -1
  108. data/lib/cov_loupe/commands/detailed_command.rb +10 -5
  109. data/lib/cov_loupe/commands/list_command.rb +2 -1
  110. data/lib/cov_loupe/commands/raw_command.rb +7 -5
  111. data/lib/cov_loupe/commands/summary_command.rb +12 -7
  112. data/lib/cov_loupe/commands/totals_command.rb +74 -10
  113. data/lib/cov_loupe/commands/uncovered_command.rb +7 -5
  114. data/lib/cov_loupe/commands/validate_command.rb +11 -3
  115. data/lib/cov_loupe/commands/version_command.rb +6 -4
  116. data/lib/cov_loupe/{app_config.rb → config/app_config.rb} +13 -5
  117. data/lib/cov_loupe/config/app_context.rb +43 -0
  118. data/lib/cov_loupe/config/boolean_type.rb +91 -0
  119. data/lib/cov_loupe/config/logger.rb +92 -0
  120. data/lib/cov_loupe/{option_normalizers.rb → config/option_normalizers.rb} +55 -24
  121. data/lib/cov_loupe/{option_parser_builder.rb → config/option_parser_builder.rb} +46 -24
  122. data/lib/cov_loupe/coverage/coverage_calculator.rb +53 -0
  123. data/lib/cov_loupe/coverage/coverage_reporter.rb +63 -0
  124. data/lib/cov_loupe/coverage/coverage_table_formatter.rb +133 -0
  125. data/lib/cov_loupe/{error_handler.rb → errors/error_handler.rb} +21 -33
  126. data/lib/cov_loupe/{errors.rb → errors/errors.rb} +48 -71
  127. data/lib/cov_loupe/formatters/formatters.rb +75 -0
  128. data/lib/cov_loupe/formatters/source_formatter.rb +18 -7
  129. data/lib/cov_loupe/formatters/table_formatter.rb +80 -0
  130. data/lib/cov_loupe/loaders/all.rb +15 -0
  131. data/lib/cov_loupe/loaders/all_cli.rb +10 -0
  132. data/lib/cov_loupe/loaders/all_mcp.rb +23 -0
  133. data/lib/cov_loupe/loaders/resultset_loader.rb +147 -0
  134. data/lib/cov_loupe/mcp_server.rb +3 -2
  135. data/lib/cov_loupe/model/model.rb +520 -0
  136. data/lib/cov_loupe/model/model_data.rb +13 -0
  137. data/lib/cov_loupe/model/model_data_cache.rb +116 -0
  138. data/lib/cov_loupe/option_parsers/env_options_parser.rb +17 -6
  139. data/lib/cov_loupe/option_parsers/error_helper.rb +16 -10
  140. data/lib/cov_loupe/output_chars.rb +192 -0
  141. data/lib/cov_loupe/paths/glob_utils.rb +100 -0
  142. data/lib/cov_loupe/{path_relativizer.rb → paths/path_relativizer.rb} +5 -13
  143. data/lib/cov_loupe/paths/path_utils.rb +265 -0
  144. data/lib/cov_loupe/paths/volume_case_sensitivity.rb +173 -0
  145. data/lib/cov_loupe/presenters/base_coverage_presenter.rb +9 -13
  146. data/lib/cov_loupe/presenters/coverage_payload_presenter.rb +21 -0
  147. data/lib/cov_loupe/presenters/payload_caching.rb +23 -0
  148. data/lib/cov_loupe/presenters/project_coverage_presenter.rb +73 -21
  149. data/lib/cov_loupe/presenters/project_totals_presenter.rb +16 -10
  150. data/lib/cov_loupe/repositories/coverage_repository.rb +149 -0
  151. data/lib/cov_loupe/resolvers/coverage_line_resolver.rb +90 -76
  152. data/lib/cov_loupe/resolvers/{resolver_factory.rb → resolver_helpers.rb} +6 -5
  153. data/lib/cov_loupe/resolvers/resultset_path_resolver.rb +40 -12
  154. data/lib/cov_loupe/scripts/command_execution.rb +113 -0
  155. data/lib/cov_loupe/scripts/latest_ci_status.rb +97 -0
  156. data/lib/cov_loupe/scripts/pre_release_check.rb +164 -0
  157. data/lib/cov_loupe/scripts/setup_doc_server.rb +23 -0
  158. data/lib/cov_loupe/scripts/start_doc_server.rb +24 -0
  159. data/lib/cov_loupe/staleness/stale_status.rb +23 -0
  160. data/lib/cov_loupe/staleness/staleness_checker.rb +328 -0
  161. data/lib/cov_loupe/staleness/staleness_message_formatter.rb +91 -0
  162. data/lib/cov_loupe/tools/coverage_detailed_tool.rb +14 -15
  163. data/lib/cov_loupe/tools/coverage_raw_tool.rb +14 -14
  164. data/lib/cov_loupe/tools/coverage_summary_tool.rb +16 -16
  165. data/lib/cov_loupe/tools/coverage_table_tool.rb +139 -21
  166. data/lib/cov_loupe/tools/coverage_totals_tool.rb +31 -13
  167. data/lib/cov_loupe/tools/help_tool.rb +16 -20
  168. data/lib/cov_loupe/tools/list_tool.rb +65 -0
  169. data/lib/cov_loupe/tools/uncovered_lines_tool.rb +14 -14
  170. data/lib/cov_loupe/tools/validate_tool.rb +18 -24
  171. data/lib/cov_loupe/tools/version_tool.rb +8 -3
  172. data/lib/cov_loupe/version.rb +1 -1
  173. data/lib/cov_loupe.rb +83 -55
  174. metadata +184 -154
  175. data/docs/dev/BRANCH_ONLY_COVERAGE.md +0 -158
  176. data/docs/dev/arch-decisions/001-x-arch-decision.md +0 -95
  177. data/docs/dev/arch-decisions/002-x-arch-decision.md +0 -159
  178. data/docs/dev/arch-decisions/003-x-arch-decision.md +0 -165
  179. data/lib/cov_loupe/app_context.rb +0 -26
  180. data/lib/cov_loupe/constants.rb +0 -22
  181. data/lib/cov_loupe/coverage_reporter.rb +0 -31
  182. data/lib/cov_loupe/formatters.rb +0 -51
  183. data/lib/cov_loupe/mode_detector.rb +0 -56
  184. data/lib/cov_loupe/model.rb +0 -339
  185. data/lib/cov_loupe/presenters/coverage_detailed_presenter.rb +0 -14
  186. data/lib/cov_loupe/presenters/coverage_raw_presenter.rb +0 -14
  187. data/lib/cov_loupe/presenters/coverage_summary_presenter.rb +0 -14
  188. data/lib/cov_loupe/presenters/coverage_uncovered_presenter.rb +0 -14
  189. data/lib/cov_loupe/resultset_loader.rb +0 -131
  190. data/lib/cov_loupe/staleness_checker.rb +0 -247
  191. data/lib/cov_loupe/table_formatter.rb +0 -64
  192. data/lib/cov_loupe/tools/all_files_coverage_tool.rb +0 -51
  193. data/lib/cov_loupe/util.rb +0 -88
  194. data/spec/MCP_INTEGRATION_TESTS_README.md +0 -111
  195. data/spec/TIMESTAMPS.md +0 -48
  196. data/spec/all_files_coverage_tool_spec.rb +0 -53
  197. data/spec/app_config_spec.rb +0 -142
  198. data/spec/base_tool_spec.rb +0 -62
  199. data/spec/cli/show_default_report_spec.rb +0 -33
  200. data/spec/cli_enumerated_options_spec.rb +0 -90
  201. data/spec/cli_error_spec.rb +0 -184
  202. data/spec/cli_format_spec.rb +0 -123
  203. data/spec/cli_json_options_spec.rb +0 -50
  204. data/spec/cli_source_spec.rb +0 -44
  205. data/spec/cli_spec.rb +0 -192
  206. data/spec/cli_table_spec.rb +0 -28
  207. data/spec/cli_usage_spec.rb +0 -42
  208. data/spec/commands/base_command_spec.rb +0 -107
  209. data/spec/commands/command_factory_spec.rb +0 -76
  210. data/spec/commands/detailed_command_spec.rb +0 -34
  211. data/spec/commands/list_command_spec.rb +0 -28
  212. data/spec/commands/raw_command_spec.rb +0 -69
  213. data/spec/commands/summary_command_spec.rb +0 -34
  214. data/spec/commands/totals_command_spec.rb +0 -34
  215. data/spec/commands/uncovered_command_spec.rb +0 -55
  216. data/spec/commands/validate_command_spec.rb +0 -213
  217. data/spec/commands/version_command_spec.rb +0 -38
  218. data/spec/constants_spec.rb +0 -61
  219. data/spec/cov_loupe/formatters/source_formatter_spec.rb +0 -267
  220. data/spec/cov_loupe/formatters_spec.rb +0 -76
  221. data/spec/cov_loupe/presenters/base_coverage_presenter_spec.rb +0 -79
  222. data/spec/cov_loupe_model_spec.rb +0 -454
  223. data/spec/cov_loupe_module_spec.rb +0 -37
  224. data/spec/cov_loupe_opts_spec.rb +0 -185
  225. data/spec/coverage_reporter_spec.rb +0 -102
  226. data/spec/coverage_table_tool_spec.rb +0 -59
  227. data/spec/coverage_totals_tool_spec.rb +0 -37
  228. data/spec/error_handler_spec.rb +0 -197
  229. data/spec/error_mode_spec.rb +0 -139
  230. data/spec/errors_edge_cases_spec.rb +0 -312
  231. data/spec/errors_stale_spec.rb +0 -83
  232. data/spec/file_based_mcp_tools_spec.rb +0 -99
  233. data/spec/help_tool_spec.rb +0 -26
  234. data/spec/integration_spec.rb +0 -789
  235. data/spec/logging_fallback_spec.rb +0 -128
  236. data/spec/mcp_logging_spec.rb +0 -44
  237. data/spec/mcp_server_integration_spec.rb +0 -23
  238. data/spec/mcp_server_spec.rb +0 -106
  239. data/spec/mode_detector_spec.rb +0 -153
  240. data/spec/model_error_handling_spec.rb +0 -269
  241. data/spec/model_staleness_spec.rb +0 -79
  242. data/spec/option_normalizers_spec.rb +0 -203
  243. data/spec/option_parsers/env_options_parser_spec.rb +0 -221
  244. data/spec/option_parsers/error_helper_spec.rb +0 -222
  245. data/spec/path_relativizer_spec.rb +0 -98
  246. data/spec/presenters/coverage_detailed_presenter_spec.rb +0 -19
  247. data/spec/presenters/coverage_raw_presenter_spec.rb +0 -15
  248. data/spec/presenters/coverage_summary_presenter_spec.rb +0 -15
  249. data/spec/presenters/coverage_uncovered_presenter_spec.rb +0 -16
  250. data/spec/presenters/project_coverage_presenter_spec.rb +0 -87
  251. data/spec/presenters/project_totals_presenter_spec.rb +0 -144
  252. data/spec/resolvers/coverage_line_resolver_spec.rb +0 -282
  253. data/spec/resolvers/resolver_factory_spec.rb +0 -61
  254. data/spec/resolvers/resultset_path_resolver_spec.rb +0 -60
  255. data/spec/resultset_loader_spec.rb +0 -167
  256. data/spec/shared_examples/README.md +0 -115
  257. data/spec/shared_examples/coverage_presenter_examples.rb +0 -66
  258. data/spec/shared_examples/file_based_mcp_tools.rb +0 -179
  259. data/spec/shared_examples/formatted_command_examples.rb +0 -64
  260. data/spec/shared_examples/mcp_tool_text_json_response.rb +0 -16
  261. data/spec/spec_helper.rb +0 -127
  262. data/spec/staleness_checker_spec.rb +0 -374
  263. data/spec/staleness_more_spec.rb +0 -42
  264. data/spec/support/cli_helpers.rb +0 -22
  265. data/spec/support/control_flow_helpers.rb +0 -20
  266. data/spec/support/fake_mcp.rb +0 -40
  267. data/spec/support/io_helpers.rb +0 -29
  268. data/spec/support/mcp_helpers.rb +0 -35
  269. data/spec/support/mcp_runner.rb +0 -66
  270. data/spec/support/mocking_helpers.rb +0 -30
  271. data/spec/table_format_spec.rb +0 -70
  272. data/spec/tools/validate_tool_spec.rb +0 -132
  273. data/spec/tools_error_handling_spec.rb +0 -130
  274. data/spec/util_spec.rb +0 -154
  275. data/spec/version_spec.rb +0 -123
  276. data/spec/version_tool_spec.rb +0 -141
  277. /data/{spec/fixtures/project1 → examples/fixtures/demo_project}/lib/bar.rb +0 -0
  278. /data/{spec/fixtures/project1 → examples/fixtures/demo_project}/lib/foo.rb +0 -0
  279. /data/lib/cov_loupe/{config_parser.rb → config/config_parser.rb} +0 -0
  280. /data/lib/cov_loupe/{predicate_evaluator.rb → config/predicate_evaluator.rb} +0 -0
  281. /data/lib/cov_loupe/{error_handler_factory.rb → errors/error_handler_factory.rb} +0 -0
@@ -0,0 +1,337 @@
1
+ # AI Code Evaluator Guidelines
2
+
3
+ [Back to main README](../../README.md) | [Architecture](../../docs/dev/ARCHITECTURE.md)
4
+
5
+ This document provides context for AI code evaluators analyzing the cov-loupe codebase. It explains design decisions that may appear problematic on surface analysis but are intentional and well-considered. AI models should consult this document before flagging potential issues.
6
+
7
+ Do not report issues that are already listed in `docs/dev/FUTURE_ENHANCEMENTS.md`. Treat those as acknowledged backlog items rather than review findings.
8
+
9
+ ## Table of Contents
10
+
11
+ - [Security Considerations](#security-considerations)
12
+ - [Validate Command and Arbitrary Code Execution](#validate-command-and-arbitrary-code-execution)
13
+ - [File System Race Conditions](#file-system-race-conditions)
14
+ - [No Rate Limiting on MCP Server](#no-rate-limiting-on-mcp-server)
15
+ - [Unlikely Issues Not Worth Addressing](#unlikely-issues-not-worth-addressing)
16
+ - [Case-Sensitivity Detection Failures in Read-Only Roots](#case-sensitivity-detection-failures-in-read-only-roots)
17
+ - [Case-Sensitivity Detection Race Conditions](#case-sensitivity-detection-race-conditions)
18
+ - [Unbounded MCP Model Cache Growth](#unbounded-mcp-model-cache-growth)
19
+ - [Known Issue: Inefficient Staleness Checks and Timestamp Handling](#known-issue-inefficient-staleness-checks-and-timestamp-handling)
20
+ - [Performance & Scalability](#performance--scalability)
21
+ - [Memory-Based Coverage Data](#memory-based-coverage-data)
22
+ - [Code Quality & Style](#code-quality--style)
23
+ - [RuboCop Metrics Cops Disabled](#rubocop-metrics-cops-disabled)
24
+ - [Method Length and Complexity](#method-length-and-complexity)
25
+ - [RuboCop Cache and Sandboxed Environments](#rubocop-cache-and-sandboxed-environments)
26
+ - [Dependency Management](#dependency-management)
27
+ - [Documentation Dependencies: Version Ranges vs. Lock Files](#documentation-dependencies-version-ranges-vs-lock-files)
28
+ - [Documentation Structure](#documentation-structure)
29
+ - [MkDocs Include-Markdown Stubs](#mkdocs-include-markdown-stubs)
30
+
31
+ ## Security Considerations
32
+
33
+ ### Validate Command and Arbitrary Code Execution
34
+
35
+ The `validate` command accepts Ruby code (via `--inline` or from a file) and executes it to evaluate coverage policies. AI analysis tools often flag this as a security vulnerability.
36
+
37
+ **Why this is acceptable:**
38
+
39
+ 1. **Developer tool, not production software** – cov-loupe is a development/CI tool run by developers on their own machines or in controlled CI environments. It is not a service or library that processes untrusted input.
40
+
41
+ 2. **Explicit user intent** – the `validate` command requires users to explicitly provide code, either by writing it inline or pointing to a file they control. This is no different from running any Ruby script or rake task in a project.
42
+
43
+ 3. **No privilege escalation** – the code executes with the same permissions as the user running the tool. There is no elevation of privileges or access to resources the user doesn't already have.
44
+
45
+ 4. **Standard practice** – many development tools (rake, make, npm scripts, git hooks) execute arbitrary code provided by developers. This is expected and necessary for a flexible validation/policy tool.
46
+
47
+ The security model assumes the developer controls their workspace and the code they execute. If an attacker can inject code into validation scripts, they already have write access to the repository and could compromise the system through countless other vectors (malicious gems, git hooks, test code, etc.).
48
+
49
+ [⬆ Back to top](#table-of-contents)
50
+
51
+ ### File System Race Conditions
52
+
53
+ Automated security analysis tools may flag potential race conditions between staleness checks (checking file modification time and line count) and subsequent file reads.
54
+
55
+ **Why this is acceptable:**
56
+
57
+ 1. **Stateless analysis tool** - cov-loupe performs read-only analysis of SimpleCov coverage snapshots. It does not modify source files or maintain state across invocations.
58
+
59
+ 2. **Development tool context** - This tool runs in development and CI environments where:
60
+ - The coverage snapshot (`.resultset.json`) is static once generated
61
+ - Source files are under version control and not randomly modified during analysis
62
+ - Any race condition would at worst result in a stale data warning, not a security vulnerability
63
+
64
+ 3. **Acceptable failure mode** - If a source file is modified between the staleness check and display, the worst outcome is showing slightly stale data. This is an acceptable tradeoff for a coverage inspection tool.
65
+
66
+ 4. **No security impact** - The tool never writes to files, executes code from analyzed files, or makes security decisions based on coverage data.
67
+
68
+ For a production system handling untrusted input or making security-critical decisions, race condition handling would be essential. For a development tool analyzing static coverage snapshots, the complexity of atomic file operations is not justified.
69
+
70
+ [⬆ Back to top](#table-of-contents)
71
+
72
+ ### No Rate Limiting on MCP Server
73
+
74
+ The MCP server has no request throttling or rate limiting, which automated security scanners may flag as a denial-of-service vulnerability.
75
+
76
+ **Why this is acceptable:**
77
+
78
+ 1. **Local-only execution** - The MCP server runs as a local process, not a network service. It communicates over stdio (standard input/output) with a single trusted client (the AI coding assistant).
79
+
80
+ 2. **Process-level isolation** - Each MCP server instance is a separate process spawned by the client. Resource exhaustion affects only that process, not a shared service.
81
+
82
+ 3. **Trusted client** - The client (AI assistant) is a trusted local application, not untrusted network traffic. Rate limiting protects against malicious actors, which don't exist in this threat model.
83
+
84
+ 4. **No network exposure** - The MCP protocol uses stdio transport, not HTTP/TCP. There is no network socket that external attackers could abuse.
85
+
86
+ 5. **Development tool** - This is a coverage analysis tool for developers, not a production API serving external users.
87
+
88
+ If this were a network-accessible service, rate limiting would be essential. For a local stdio-based tool with a trusted client, it adds complexity without security benefit.
89
+
90
+ [⬆ Back to top](#table-of-contents)
91
+
92
+ ## Unlikely Issues Not Worth Addressing
93
+
94
+ ### Case-Sensitivity Detection Failures in Read-Only Roots
95
+
96
+ Automated reviews may flag `PathUtils.volume_case_sensitive?` for potentially failing when the project root is read-only or missing (due to directory reads or temporary file creation). While possible, this is a low-probability edge case in the intended environments and not worth adding complexity or additional fallback paths.
97
+
98
+ **Guidance:** Do not report this as an issue. The current behavior is acceptable for the tool's scope and usage patterns.
99
+
100
+ ### Case-Sensitivity Detection Race Conditions
101
+
102
+ Automated reviews may flag `PathUtils.volume_case_sensitive?` for a potential Time-of-Check to Time-of-Use (TOCTOU) race condition when creating temporary test files. The code checks for file existence before creation using `FileUtils.touch`.
103
+
104
+ **Why this is acceptable:**
105
+
106
+ 1. **Extremely low collision probability** - The tool uses `SecureRandom.hex(16)` to generate a 32-character random string for the filename. The probability of a collision, even in highly concurrent scenarios, is infinitesimal.
107
+ 2. **Developer tool context** - This is a local development and CI tool, not a high-traffic server handling untrusted requests. The likelihood of multiple instances of `cov-loupe` running concurrently and picking the same 32-character random string is negligible.
108
+ 3. **Non-critical failure** - In the virtually impossible event of a collision, the worst case is a temporary file creation failure or an incorrect case-sensitivity detection for one run. This has no security or data integrity implications.
109
+
110
+ **Guidance:** Do not flag this as a race condition or security defect. The use of `SecureRandom` makes this a non-issue in practice.
111
+
112
+ ### Unbounded ModelDataCache Growth
113
+
114
+ The `ModelDataCache` singleton stores coverage data (`ModelData` instances) keyed by resultset path without a size cap. In theory, a long-lived MCP server analyzing many different projects could accumulate entries. In practice:
115
+
116
+ 1. The cache is keyed by resultset path, not by project or model configuration
117
+ 2. Multiple models using the same resultset share a single cache entry
118
+ 3. MCP servers are typically short-lived and used for a small set of projects
119
+ 4. The cache automatically evicts stale data when resultset files change
120
+
121
+ Adding eviction logic (LRU, TTL, size limits) would add complexity without meaningful benefit for the tool's intended use case.
122
+
123
+ **Guidance:** Do not report this as an issue. The current behavior is a reasonable tradeoff for simplicity.
124
+
125
+ [⬆ Back to top](#table-of-contents)
126
+
127
+ ## Known Issue: Inefficient Staleness Checks and Timestamp Handling
128
+
129
+ - **Description:** Coverage timestamps are collapsed to a single max value for all suites (handled when `CovLoupe::CoverageModel` loads resultsets via `ResultsetLoader`), and staleness checks reread each file to count lines (implemented in `CovLoupe::StalenessChecker`).
130
+ **Impact:** Multi-suite projects get false positives/negatives on freshness, and large repositories pay O(total lines) per query, making results unreliable and slow for larger code bases.
131
+ **Urgency:** Medium.
132
+ **Estimated Cost-to-Fix:** High (store per-suite/file metadata and cache line counts/mtimes).
133
+ **Rationale for Status Quo:** Fixing this requires a significant architectural overhaul to track per-file/per-suite metadata. Simple caching of file stats is insufficient because the primary use case involves active development where source files change frequently, invalidating caches. Given the high cost of a proper fix and the tool's focus on small-to-medium projects, the current O(N) check is an acceptable tradeoff.
134
+
135
+ [⬆ Back to top](#table-of-contents)
136
+
137
+ ## Performance & Scalability
138
+
139
+ ### Memory-Based Coverage Data
140
+
141
+ cov-loupe loads the entire SimpleCov resultset into memory for analysis. This means it is not designed to handle extremely large codebases that produce coverage data too large to fit in memory.
142
+
143
+ **Why this is acceptable:**
144
+
145
+ 1. **Target use case** – cov-loupe is designed for small-to-medium sized Ruby projects. The typical SimpleCov resultset for such projects is measured in megabytes, well within modern system capabilities.
146
+
147
+ 2. **SimpleCov's own limitations** – SimpleCov itself loads coverage data into memory. If SimpleCov can generate the resultset, cov-loupe can analyze it.
148
+
149
+ 3. **Performance trade-off** – in-memory processing enables fast queries, rich data transformations, and a responsive CLI. Streaming or database-backed approaches would add significant complexity for marginal benefit in the target use case.
150
+
151
+ 4. **Practical upper bound** – even large Ruby projects (Rails, GitLab) generate resultsets in the tens of megabytes. Modern machines have gigabytes of RAM. The constraint is theoretical rather than practical for the intended audience.
152
+
153
+ If a project grows large enough that coverage analysis becomes a memory bottleneck, it likely has deeper problems (test suite organization, monolith vs services architecture) that should be addressed at that level rather than by adding complexity to a coverage inspection tool.
154
+
155
+ [⬆ Back to top](#table-of-contents)
156
+
157
+ ### Model Cache Digest Reads
158
+
159
+ The MCP model cache computes an MD5 digest of the resultset file on each fetch. This can look like unnecessary file I/O, but it is intentional.
160
+
161
+ **Why this is acceptable:**
162
+
163
+ 1. **Correctness over metadata shortcuts** – mtime/size/inode can miss changes (e.g., clock skew, restored files, or filesystem quirks). Hashing is the only reliable way to guarantee the content is unchanged.
164
+ 2. **Cheaper than parsing** – reading and hashing the file is far faster than parsing JSON into memory, so the cache still provides meaningful savings.
165
+ 3. **Scoped to MCP usage** – this path is used for repeated MCP tool calls where avoiding full parsing is the main goal.
166
+
167
+ **Guidance:** Do not flag this as a performance defect; it is a deliberate tradeoff for correctness.
168
+
169
+ [⬆ Back to top](#table-of-contents)
170
+
171
+ ## Code Quality & Style
172
+
173
+ ### RuboCop Metrics Cops Disabled
174
+
175
+ All RuboCop Metrics cops (AbcSize, BlockLength, ClassLength, CyclomaticComplexity, MethodLength, ModuleLength, ParameterLists, PerceivedComplexity, BlockNesting) are intentionally disabled in `.rubocop.yml`.
176
+
177
+ **Why this is acceptable:**
178
+
179
+ 1. **Arbitrary thresholds don't account for domain complexity** – Some problems are inherently complex. SimpleCov coverage analysis involves edge cases (staleness checking, path resolution, multi-suite merging) that require comprehensive logic. Artificial method splitting can scatter cohesive logic and reduce clarity.
180
+
181
+ 2. **Comprehensive error handling adds necessary lines** – This project prioritizes reliability through extensive error handling with context-rich messages. Error handling code is inherently verbose but critical for user experience across three modes (CLI, library, MCP).
182
+
183
+ 3. **Quality maintained through other means** – The codebase achieves:
184
+ - 100% line coverage (1815/1815 lines)
185
+ - 94% branch coverage
186
+ - 0 RuboCop violations (all non-Metrics cops)
187
+ - Comprehensive code review
188
+ - Clear inline documentation for complex logic
189
+ - Voluntary file size restraint (most files < 200 lines)
190
+
191
+ 4. **Readability over arbitrary limits** – The project values clear, cohesive methods over arbitrary line limits. When a method's length accurately reflects its necessary complexity, splitting it just to meet a metric harms rather than helps. Key examples:
192
+ - `StalenessChecker#compute_file_staleness_details` (30 lines) handles complex edge cases with clear documentation
193
+ - `CoverageDataProjectStaleError#build_details` (22 lines) builds error messages through simple sequential operations
194
+
195
+ **Evidence:** Manual review shows appropriate complexity for domain logic, with no god objects or unclear methods.
196
+
197
+ [⬆ Back to top](#table-of-contents)
198
+
199
+ ### Method Length and Complexity
200
+
201
+ AI code analysis tools may flag methods as "too long" based on line count alone. However, **line count is not always a proxy for complexity**. Many long methods in this codebase are intentionally structured for clarity and maintainability.
202
+
203
+ **When long methods are acceptable:**
204
+
205
+ 1. **Sequential data structure building** – Methods that build arrays or hashes through sequential operations are highly readable despite line count:
206
+ - `CoverageDataProjectStaleError#build_details` (22 lines, lib/cov_loupe/errors.rb:163-184) – builds error message parts in an array through simple, similar operations
207
+ - This pattern is far clearer than extracting fragmented helper methods
208
+
209
+ 2. **Comprehensive conditional handling** – Methods with extensive if-elsif-else chains that handle different cases clearly:
210
+ - `ErrorHandler#convert_runtime_error` (22 lines, lib/cov_loupe/error_handler.rb:103-124) – converts different error types with appropriate context
211
+ - Each branch is simple; complexity lies in coverage, not algorithmic difficulty
212
+
213
+ 3. **Well-documented edge case handling** – Methods handling multiple edge cases with clear inline documentation:
214
+ - `StalenessChecker#compute_file_staleness_details` (30 lines, lib/cov_loupe/staleness_checker.rb:160-190) – handles file existence, timestamps, and line count mismatches with inline explanations
215
+ - Comments clarify intent; the logic itself remains straightforward
216
+
217
+ 4. **Coordinated multi-step operations** – Methods that orchestrate several well-defined steps in a logical flow:
218
+ - While `CoverageModel#list` was previously 48 lines, it has been refactored to 16 lines (lib/cov_loupe/model.rb:80-95) by extracting helper methods
219
+ - This demonstrates that extraction makes sense when it improves clarity, not to meet arbitrary line limits
220
+
221
+ **When to refactor:**
222
+
223
+ Long methods warrant refactoring when they exhibit:
224
+ - Deeply nested conditionals (>3 levels)
225
+ - Mixed concerns (I/O, business logic, and presentation in one method)
226
+ - High cyclomatic complexity (many independent decision points)
227
+ - Difficulty understanding purpose or flow even with comments
228
+
229
+ **Guidance for AI analysis tools:**
230
+
231
+ Before flagging a long method, assess:
232
+ - **What is it doing?** One cohesive thing, or mixing concerns?
233
+ - **Would splitting improve readability?** Or just scatter related logic?
234
+ - **What causes the length?** Data structures, error handling, or algorithmic complexity?
235
+ - **Is it well-documented?** Inline comments can make complex logic clear.
236
+
237
+ Method length is a heuristic, not a rule. Judge methods by clarity, cohesion, and testability rather than line count alone.
238
+
239
+ [⬆ Back to top](#table-of-contents)
240
+
241
+ ### RuboCop Cache and Sandboxed Environments
242
+
243
+ RuboCop may crash in sandboxed environments (such as AI coding assistants with file system restrictions) when attempting to write cache files:
244
+
245
+ ```
246
+ Read-only file system @ rb_sysopen
247
+ → /home/user/.cache/rubocop_cache/...
248
+ → Parallel.work_in_processes
249
+ ```
250
+
251
+ **Why this happens:**
252
+
253
+ RuboCop runs in parallel mode by default, forking worker processes via the `parallel` gem. Each worker attempts to cache analysis results to `~/.cache/rubocop_cache/`. When sandbox restrictions prevent writes outside the project directory, the cache write fails and crashes the analysis.
254
+
255
+ **Why this is not a code quality issue:**
256
+
257
+ Running RuboCop with `--cache false` completes successfully with **0 violations**:
258
+ ```
259
+ 164 files inspected, no offenses detected
260
+ ```
261
+
262
+ The codebase has perfect RuboCop compliance. The crash is purely environmental.
263
+
264
+ **Workaround:**
265
+
266
+ Use `bundle exec rubocop --cache false` in sandboxed environments. This adds approximately 5 seconds to execution time (3s → 8s) but ensures successful analysis. Cache performance benefits are modest for this project size, making the tradeoff acceptable.
267
+
268
+ **Why caching is not disabled by default:**
269
+
270
+ The 3-second speedup is valuable for frequent local development. Developers in non-sandboxed environments (the common case) benefit from faster linting. The issue only affects specific sandboxed AI tools and CI environments, which can use the `--cache false` flag when needed.
271
+
272
+ [⬆ Back to top](#table-of-contents)
273
+
274
+ ## Dependency Management
275
+
276
+ ### Documentation Dependencies: Version Ranges vs. Lock Files
277
+
278
+ The project uses **both** `requirements.txt` (version ranges) and `requirements-lock.txt` (exact pins) for Python documentation build dependencies.
279
+
280
+ **Why version ranges are used in `requirements.txt`:**
281
+
282
+ 1. **Optional dependencies** - These Python packages are only needed for building documentation. They are NOT part of the Ruby gem or required for using cov-loupe as an MCP server.
283
+
284
+ 2. **Library compatibility** - Contributors may be working on multiple projects with different documentation tooling. Flexible ranges allow them to use compatible versions already in their environment without conflicts.
285
+
286
+ 3. **Development flexibility** - Local documentation builds should work with any compatible version. Overly strict pinning would create unnecessary friction for contributors.
287
+
288
+ **Why lock files are used in CI (`requirements-lock.txt`):**
289
+
290
+ 1. **Reproducible builds** - CI documentation builds must be deterministic. The same commit should always produce the same documentation output.
291
+
292
+ 2. **Prevent drift** - Without locked versions, a new minor/patch release could silently change docs rendering, break the build, or introduce bugs.
293
+
294
+ 3. **Standard practice** - This is the recommended pattern in Python: flexible ranges for development (`requirements.txt`/`requirements.in`), exact pins for deployment (`requirements-lock.txt`).
295
+
296
+ **How it works:**
297
+
298
+ - Contributors run `pip install -r requirements.txt` locally (flexible)
299
+ - CI runs `pip install -r requirements-lock.txt` (reproducible)
300
+ - Users of the gem/MCP server are unaffected (these are Python-only doc dependencies)
301
+
302
+ This dual-file approach is intentional and follows Python packaging best practices for applications with optional documentation tooling.
303
+
304
+ [⬆ Back to top](#table-of-contents)
305
+
306
+ ## Documentation Structure
307
+
308
+ ### MkDocs Include-Markdown Stubs
309
+
310
+ The files `docs/contributing.md` and `docs/code_of_conduct.md` appear to be minimal 46-byte stubs when examined directly. AI code analysis tools often flag these as missing or incomplete documentation.
311
+
312
+ **Why this is not an issue:**
313
+
314
+ These files use MkDocs' `include-markdown` plugin to pull in comprehensive documentation from the repository root:
315
+
316
+ - `docs/contributing.md` → `{% include-markdown "../CONTRIBUTING.md" %}`
317
+ - `docs/code_of_conduct.md` → `{% include-markdown "../CODE_OF_CONDUCT.md" %}`
318
+
319
+ The actual comprehensive documentation exists at:
320
+ - `CONTRIBUTING.md` (103 lines) - Full contributing guide with PR workflow, development setup, testing requirements, and release process
321
+ - `CODE_OF_CONDUCT.md` (61 lines) - Complete Contributor Covenant v2.1
322
+
323
+ **Why this pattern is used:**
324
+
325
+ 1. **Single source of truth** - The actual content lives in standard locations (`CONTRIBUTING.md` and `CODE_OF_CONDUCT.md` at repository root) where GitHub, developers, and tools expect to find them.
326
+
327
+ 2. **Documentation site integration** - MkDocs automatically includes these files in the generated documentation website without duplication or manual synchronization.
328
+
329
+ 3. **Standard practice** - This is the recommended approach in the MkDocs documentation for including existing project files in the documentation site.
330
+
331
+ AI tools analyzing file sizes directly will see 46-byte stubs, but the documentation is complete and properly structured.
332
+
333
+ [⬆ Back to top](#table-of-contents)
334
+
335
+ ---
336
+
337
+ *This document should be updated whenever design decisions are made that might appear problematic to automated analysis but are intentional and defensible.*
@@ -0,0 +1,18 @@
1
+ # Thoroughly Review Test Suite
2
+
3
+ Carefully examine the test suite. Report and fix:
4
+
5
+ - duplicate tests testing the same thing
6
+ - tests that test the test setup rather than the actual production code
7
+ - verbose tests, e.g.:
8
+ - multiple calls to `to include` that should be compressed into a single call with a comma separated string list
9
+ - duplicate test code that can be made more concise by the use of arrays of test data with an `.each`, etc. block
10
+ - complex tests that could be clarified with comments, intermediate variables, extracted methods, etc.
11
+
12
+ Ensure that any code changes comply with rubocop linting:
13
+
14
+ - run `rubocop` to see if there are any errors. If cache writes fail (e.g., in a sandboxed environment), use `bundle exec rubocop --cache false`.
15
+ - run `rubocop -A` (or `bundle exec rubocop -A --cache false` if needed) to fix anything rubocop is capable of fixing
16
+ - fix the other errors yourself
17
+
18
+ Run the test suite as necessary to verify that all tests pass.
@@ -0,0 +1,133 @@
1
+ # Simplify and Document Code Logic
2
+
3
+ **Purpose:** Identify and improve complex, unclear, or surprising code logic through simplification or documentation.
4
+
5
+ ## When to Use This
6
+
7
+ - Code has complex conditionals (>3 levels of nesting)
8
+ - Logic is surprising or differs from standard conventions
9
+ - Methods/functions are difficult to understand
10
+ - Variable or method names are unclear
11
+ - Edge cases lack explanation
12
+
13
+ ## What to Look For
14
+
15
+ ### Complexity Indicators
16
+ - **Deep nesting:** Conditionals or loops nested more than 3 levels
17
+ - **Long methods:** Methods that require excessive mental effort to understand
18
+ - **Unclear variable names:** Names that don't clearly indicate purpose
19
+ - **Magic numbers/strings:** Unexplained literal values
20
+ - **Complex boolean expressions:** Compound conditions that are hard to parse
21
+
22
+ ### Surprising Behavior
23
+ - Logic that differs from typical language/framework conventions
24
+ - Non-obvious side effects
25
+ - Implicit assumptions about state or input
26
+ - Edge case handling that isn't self-evident
27
+
28
+ ### Missing Context
29
+ - Unclear intent or purpose
30
+ - Inadequate or missing explanatory comments
31
+ - Undocumented edge cases
32
+ - Assumptions that aren't stated
33
+
34
+ ## Actions to Take
35
+
36
+ For each instance of complex or unclear logic:
37
+
38
+ ### 1. Assess Simplification Potential
39
+ - Can the logic be rewritten more clearly?
40
+ - Would extracting helper methods improve clarity?
41
+ - Can complex conditions be simplified or inverted?
42
+ - Would better variable names help?
43
+
44
+ ### 2. If Simplification is Possible
45
+ - Refactor to simpler, more readable code
46
+ - Extract helper methods with clear, descriptive names
47
+ - Use early returns to reduce nesting
48
+ - Break complex expressions into named intermediate variables
49
+ - Replace magic values with named constants
50
+
51
+ ### 3. If Simplification is Not Possible
52
+ - Add clarifying comments explaining the "why"
53
+ - Document edge cases and assumptions
54
+ - Add examples in comments if helpful
55
+ - Explain why simpler approaches won't work
56
+
57
+ ### 4. Maintain Functionality
58
+ - Add tests if coverage is missing
59
+ - Run existing tests to verify no regressions
60
+ - Follow Rubocop rules
61
+ - Preserve documented design decisions
62
+
63
+ ## Constraints
64
+
65
+ - **Follow guidelines:** Respect decisions documented in `dev/prompts/guidelines/ai-code-evaluator-guidelines.md`
66
+ - **Maintain behavior:** Do not change functionality
67
+ - **Add tests:** Ensure adequate test coverage for any refactored code
68
+ - **Rubocop compliance:** Run `rubocop` (or `rubocop --cache false` in sandboxed environments) when feasible
69
+ - **Preserve intent:** Maintain the original purpose and behavior
70
+
71
+ ## Examples
72
+
73
+ ### Before: Complex nested conditionals
74
+ ```ruby
75
+ def process_order(order)
76
+ if order.valid?
77
+ if order.items.any?
78
+ if order.payment_method
79
+ if order.payment_method.authorized?
80
+ complete_order(order)
81
+ else
82
+ reject_order(order, "Payment not authorized")
83
+ end
84
+ else
85
+ reject_order(order, "No payment method")
86
+ end
87
+ else
88
+ reject_order(order, "No items")
89
+ end
90
+ else
91
+ reject_order(order, "Invalid order")
92
+ end
93
+ end
94
+ ```
95
+
96
+ ### After: Using early returns
97
+ ```ruby
98
+ def process_order(order)
99
+ return reject_order(order, "Invalid order") unless order.valid?
100
+ return reject_order(order, "No items") if order.items.empty?
101
+ return reject_order(order, "No payment method") unless order.payment_method
102
+ return reject_order(order, "Payment not authorized") unless order.payment_method.authorized?
103
+
104
+ complete_order(order)
105
+ end
106
+ ```
107
+
108
+ ### Before: Unclear logic
109
+ ```ruby
110
+ def calculate_price(item)
111
+ # What is 0.8? Why multiply by it?
112
+ item.base_price * 0.8 if item.category == 3
113
+ end
114
+ ```
115
+
116
+ ### After: Documented with constants
117
+ ```ruby
118
+ # Discount rate for clearance items (20% off)
119
+ CLEARANCE_DISCOUNT = 0.8
120
+ CLEARANCE_CATEGORY = 3
121
+
122
+ def calculate_price(item)
123
+ return item.base_price unless item.category == CLEARANCE_CATEGORY
124
+
125
+ item.base_price * CLEARANCE_DISCOUNT
126
+ end
127
+ ```
128
+
129
+ ## Output
130
+
131
+ Make changes directly to the code files. No separate report is needed unless you want to summarize the improvements made.
132
+
133
+ Do not run `git commit`. If the user asks for a commit, suggest a concise message that explains what was simplified or documented and why.
@@ -0,0 +1,21 @@
1
+ # Review and Revise Documentation as Necessary
2
+
3
+ Examine carefully the Markdown documentation files in:
4
+
5
+ - *.md
6
+ - docs/**/*.md
7
+ - docs/user/**/*.md
8
+ - docs/dev/arch-decisions/**/*.md
9
+
10
+ Make any changes necessary to make them accurate, clear, and complete.
11
+
12
+ Make sure that documents are linked in both directions, e.g. from the top level readme
13
+ to the specialized document, and vice versa.
14
+
15
+ Ensure that there is enough verbiage to explain a given point, but not too much as to
16
+ unnecessarily reduce the signal to noise ratio.
17
+
18
+ If a given point is addressed in multiple documents, look to see if that is sensible, and fix if necessary.
19
+
20
+ Ensure that any code examples are correct and relevant.
21
+