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,66 @@
1
+ ## MCP JSON Inputs
2
+
3
+ [Back to main README](../../docs/index.md)
4
+
5
+ This directory contains example JSON-RPC requests that can be sent to the MCP server over stdio.
6
+
7
+ Each file contains a single line of JSON (NDJSON-ready), so you can pipe it directly to the executable.
8
+
9
+ **Target Project:** These inputs are designed to work with the demo project located at `docs/fixtures/demo_project`.
10
+
11
+ ### Running the Examples
12
+
13
+ From the repository root:
14
+
15
+ ```sh
16
+ exe/cov-loupe -m mcp < examples/mcp-inputs/coverage_summary.json
17
+ exe/cov-loupe -m mcp < examples/mcp-inputs/uncovered_lines.json
18
+ ```
19
+
20
+ If `cov-loupe` is installed globally and available on your `PATH`:
21
+
22
+ ```sh
23
+ cov-loupe -m mcp < examples/mcp-inputs/coverage_summary.json
24
+ ```
25
+
26
+ ### Formatting Tips (jq and rexe)
27
+
28
+ You can use tools like [jq](https://github.com/jqlang/jq) or [rexe](https://github.com/keithrbennett/rexe) to format the JSON input and output, which is especially helpful for debugging.
29
+
30
+ **Pretty-print an input file:**
31
+
32
+ Using `jq`:
33
+ ```sh
34
+ jq . examples/mcp-inputs/coverage_summary.json
35
+ ```
36
+
37
+ Using Ruby:
38
+ ```sh
39
+ ruby -r json -e '
40
+ puts JSON.pretty_generate(JSON.parse(File.read("examples/mcp-inputs/coverage_summary.json")))
41
+ '
42
+ ```
43
+
44
+ Using `rexe`:
45
+ ```sh
46
+ rexe -f examples/mcp-inputs/coverage_summary.json -oJ
47
+ ```
48
+
49
+ **Pretty-print the MCP server's JSON response (NDJSON):**
50
+
51
+ Using `jq`:
52
+ ```sh
53
+ exe/cov-loupe -m mcp < examples/mcp-inputs/coverage_summary.json | jq .
54
+ ```
55
+
56
+ Using Ruby:
57
+ ```sh
58
+ exe/cov-loupe -m mcp < examples/mcp-inputs/coverage_summary.json | ruby -r json -e '
59
+ puts JSON.pretty_generate(JSON.parse($stdin.read))
60
+ '
61
+ ```
62
+
63
+ Using `rexe`:
64
+ ```sh
65
+ exe/cov-loupe -m mcp < examples/mcp-inputs/coverage_summary.json | rexe -ml -ij -oJ
66
+ ```
@@ -0,0 +1 @@
1
+ {"jsonrpc":"2.0","id":4,"method":"tools/call","params":{"name":"coverage_detailed_tool","arguments":{"path":"lib/foo.rb","root":"docs/fixtures/demo_project"}}}
@@ -0,0 +1 @@
1
+ {"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"coverage_raw_tool","arguments":{"path":"lib/foo.rb","root":"docs/fixtures/demo_project"}}}
@@ -0,0 +1 @@
1
+ {"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"coverage_summary_tool","arguments":{"path":"lib/foo.rb","root":"docs/fixtures/demo_project"}}}
@@ -0,0 +1 @@
1
+ {"jsonrpc":"2.0","id":5,"method":"tools/call","params":{"name":"list_tool","arguments":{"root":"docs/fixtures/demo_project"}}}
@@ -0,0 +1 @@
1
+ {"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"uncovered_lines_tool","arguments":{"path":"lib/foo.rb","root":"docs/fixtures/demo_project"}}}
@@ -0,0 +1,27 @@
1
+ ## Example Prompts for MCP-Aware Assistants
2
+
3
+ [Back to main README](../../docs/index.md)
4
+
5
+ This directory contains example natural-language prompts that you can use with an MCP-enabled AI assistant to interact with the `cov-loupe` server and analyze your project's test coverage.
6
+
7
+ These prompts demonstrate how to request different types of coverage information. You can adapt them to your specific project and needs.
8
+
9
+ ### Getting Started
10
+
11
+ 1. **Copy a prompt:** Choose a prompt from one of the `.txt` files in this directory.
12
+ 2. **Paste it into your assistant:** Paste the prompt into your chat with an MCP-enabled AI assistant.
13
+ 3. **Adjust file paths:** If necessary, change the file paths in the prompt to match your project's structure.
14
+
15
+ ### Example Prompts
16
+
17
+ * **`summary.txt`**: A basic prompt to get a high-level summary of your project's test coverage.
18
+ * **`detailed_with_source.txt`**: A more advanced prompt that requests a detailed breakdown of coverage, including the source code of the files.
19
+ * **`list_lowest.txt`**: A prompt to find the files with the lowest test coverage.
20
+ * **`uncovered.txt`**: A prompt to get a list of all the lines that are not covered by tests.
21
+ * **`custom_resultset.txt`**: An example of how to specify a custom SimpleCov resultset file for analysis.
22
+
23
+ ### Tips for Writing Your Own Prompts
24
+
25
+ * **Be specific:** The more specific you are in your request, the better the assistant will be able to understand you.
26
+ * **Request JSON for machine-readable output:** If you want to process the output programmatically, ask for the results in JSON format.
27
+ * **Specify the root directory:** If your project is not in the current working directory, you can specify the root directory in your prompt.
@@ -0,0 +1,2 @@
1
+ Read coverage from build/coverage/.resultset.json for src/app.rb. Compare its coverage level to typical standards for application entry points. If coverage is incomplete, explain what failure modes or edge cases might be untested and why that matters for a main application file.
2
+
@@ -0,0 +1,2 @@
1
+ Examine the detailed line-by-line coverage for lib/foo.rb. Identify patterns in what's tested vs untested (e.g., are error paths covered? edge cases? happy paths only?). Highlight any concerning gaps and suggest what test cases would address them.
2
+
@@ -0,0 +1,2 @@
1
+ Identify the 5 files with the lowest test coverage. For each, analyze what type of code it contains (core logic, utilities, error handling, etc.) and assess the risk of inadequate testing. Recommend a priority order for adding tests based on both coverage percentage and code criticality.
2
+
@@ -0,0 +1,2 @@
1
+ Analyze the coverage for lib/foo.rb. If coverage is below 80%, identify the riskiest uncovered areas and suggest specific test scenarios that would improve quality. Prioritize by impact.
2
+
@@ -0,0 +1,2 @@
1
+ Find all uncovered lines in lib/foo.rb. Analyze which uncovered sections represent the highest risk (e.g., error handling, edge cases, complex logic). Recommend which lines should be tested first and why.
2
+
@@ -0,0 +1,198 @@
1
+ # Coverage Validation Predicate Examples
2
+
3
+ [Back to main README](../../docs/index.md)
4
+
5
+ This directory contains example coverage validation predicates for use with the `validate` subcommand.
6
+
7
+ > **⚠️ SECURITY WARNING**
8
+ >
9
+ > Success predicates execute as **arbitrary Ruby code with full system privileges**. They have unrestricted access to:
10
+ > - File system operations (read, write, delete)
11
+ > - Network operations (HTTP requests, sockets)
12
+ > - System commands (via backticks, `system()`, `exec()`, etc.)
13
+ > - Environment variables and sensitive data
14
+ >
15
+ > **Only use predicate files from trusted sources.** Treat them like any other executable code in your project.
16
+ > - Never use predicates from untrusted or unknown sources
17
+ > - Review predicates before use, especially in CI/CD environments
18
+ > - Store predicates in version control with code review
19
+ > - Be cautious when copying examples from the internet
20
+
21
+ ## Usage
22
+
23
+ **File mode:**
24
+ ```sh
25
+ cov-loupe validate examples/success_predicates/<filename>.rb
26
+ ```
27
+
28
+ **String mode:**
29
+ ```sh
30
+ cov-loupe validate -i '->(model) { model.list["files"].all? { |f| f["percentage"] >= 80 } }'
31
+ ```
32
+
33
+ The predicate receives a `CoverageModel` instance and returns:
34
+ - **Truthy value** → Exit code 0 (success)
35
+ - **Falsy value** → Exit code 1 (failure)
36
+ - **Exception** → Exit code 2 (error)
37
+
38
+ ## Available Examples
39
+
40
+ ### `all_files_above_threshold_predicate.rb`
41
+ All files must have >= 80% coverage.
42
+
43
+ ```sh
44
+ cov-loupe validate examples/success_predicates/all_files_above_threshold_predicate.rb
45
+ ```
46
+
47
+ ### `project_coverage_minimum_predicate.rb`
48
+ Total project coverage must be >= 85%.
49
+
50
+ ```sh
51
+ cov-loupe validate examples/success_predicates/project_coverage_minimum_predicate.rb
52
+ ```
53
+
54
+ ### `directory_specific_thresholds_predicate.rb`
55
+ Different thresholds for different directories:
56
+ - `lib/api/` - 90% required
57
+ - `lib/core/` - 85% required
58
+ - `lib/legacy/` - 60% required
59
+
60
+ ```sh
61
+ cov-loupe validate examples/success_predicates/directory_specific_thresholds_predicate.rb
62
+ ```
63
+
64
+ ## Creating Custom Predicates
65
+
66
+ A predicate must be a callable object (lambda, proc, or class with `#call` method):
67
+
68
+ **Lambda example:**
69
+ ```ruby
70
+ ->(model) do
71
+ model.list['files'].all? { |f| f['percentage'] >= 80 }
72
+ end
73
+ ```
74
+
75
+ **Class method example:**
76
+ ```ruby
77
+ class MyPolicy
78
+ def self.call(model)
79
+ model.list['files'].all? { |f| f['percentage'] >= @threshold }
80
+ end
81
+ end
82
+
83
+ MyPolicy # The class itself
84
+ ```
85
+
86
+ **Instance method example:**
87
+ ```ruby
88
+ class MyPolicy
89
+ def initialize(threshold = 80)
90
+ @threshold = threshold
91
+ end
92
+
93
+ def call(model)
94
+ model.list['files'].all? { |f| f['percentage'] >= @threshold }
95
+ end
96
+ end
97
+
98
+ MyPolicy
99
+
100
+ ```
101
+
102
+ ### CoverageModel API
103
+
104
+ The `model` parameter provides:
105
+
106
+ ```ruby
107
+ # Get all files
108
+ files = model.list['files']
109
+ # => [{ "file" => "...", "covered" => 12, "total" => 14, "percentage" => 85.71, "stale" => false }, ...]
110
+
111
+ # Filter by globs
112
+ api_files = model.list(tracked_globs: ['lib/api/**/*.rb'])['files']
113
+
114
+ # Get specific file data
115
+ summary = model.summary_for('lib/model.rb')
116
+ uncovered = model.uncovered_for('lib/model.rb')
117
+ ```
118
+
119
+ See [docs/user/LIBRARY_API.md](../../docs/user/LIBRARY_API.md) for the complete API.
120
+
121
+ ### When to Use Standalone Scripts Instead
122
+
123
+ For more complex scenarios, you may prefer writing a standalone Ruby script that uses the `cov-loupe` library directly instead of using the `validate` subcommand.
124
+
125
+ **Use a standalone script when:**
126
+ - **External dependencies needed** - Your policy requires other gems or libraries
127
+ - **Complex setup required** - You need custom logging, database connections, or API calls
128
+ - **Easier testing desired** - Standalone scripts can be tested like any Ruby code
129
+ - **More explicit control** - You want full control over model initialization and error handling
130
+ - **Sophisticated logic** - Multi-step analysis, data aggregation, or integration with other tools
131
+
132
+ **Predicate approach is better when:**
133
+ - Policy is simple and self-contained (most common use case)
134
+ - You want the tool to handle option parsing (--resultset, --raise-on-stale, etc.)
135
+ - Consistent error handling and exit codes are desired
136
+ - Less boilerplate is preferred
137
+
138
+ **Example standalone script:**
139
+ ```ruby
140
+ #!/usr/bin/env ruby
141
+ require 'cov_loupe'
142
+ require 'httparty' # External gem
143
+
144
+ # Custom initialization
145
+ model = CovLoupe::CoverageModel.new(
146
+ resultset: ENV['COVERAGE_PATH'],
147
+ raise_on_stale: true
148
+ )
149
+
150
+ # Complex logic with external API
151
+ files = model.list['files']
152
+ low_coverage_files = files.select { |f| f['percentage'] < 80 }
153
+
154
+ # Post to Slack
155
+ if low_coverage_files.any?
156
+ HTTParty.post(
157
+ ENV['SLACK_WEBHOOK_URL'],
158
+ body: { text: "#{low_coverage_files.size} files below 80%" }.to_json
159
+ )
160
+ exit 1
161
+ else
162
+ exit 0
163
+ end
164
+ ```
165
+
166
+ Both approaches execute arbitrary code with full system privileges, so the security considerations are identical. Choose the approach that best fits your use case.
167
+
168
+ ## CI/CD Integration
169
+
170
+ **GitHub Actions:**
171
+ ```yaml
172
+ - name: Enforce Coverage Policy
173
+ run: bundle exec cov-loupe validate coverage_policy.rb
174
+ ```
175
+
176
+ **GitLab CI:**
177
+ ```yaml
178
+ coverage:enforce:
179
+ script:
180
+ - bundle exec cov-loupe validate coverage_policy.rb
181
+ ```
182
+
183
+ **Jenkins:**
184
+ ```groovy
185
+ stage('Coverage Policy') {
186
+ steps {
187
+ sh 'bundle exec cov-loupe validate coverage_policy.rb'
188
+ }
189
+ }
190
+ ```
191
+
192
+ ## Exit Codes
193
+
194
+ - **0** - Predicate returned truthy (success)
195
+ - **1** - Predicate returned falsy (failure)
196
+ - **2** - Predicate raised an error
197
+
198
+ Use exit code 1 to fail CI/CD builds when coverage doesn't meet policy.
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Success predicate: All files must have >= 80% coverage, illustrates use of a class `call` method
4
+ # Usage: cov-loupe --success-predicate examples/success_predicates/all_files_above_threshold_predicate.rb
5
+ class AllFilesAboveThreshold
6
+ THRESHOLD = 95
7
+
8
+ def self.call(model)
9
+ low_files = model.list.select { |f| f['percentage'] < THRESHOLD }
10
+
11
+ if low_files.any?
12
+ # Can add custom logging/reporting here
13
+ warn "Files below #{THRESHOLD}%:"
14
+ low_files.each { |f| warn format('%5.1f%% %s', f['percentage'], f['name']) }
15
+ end
16
+
17
+ low_files.none?
18
+ end
19
+ end
20
+
21
+ AllFilesAboveThreshold
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Success predicate: Different thresholds for different directories, using a `call` class method
4
+ # Usage: cov-loupe --success-predicate examples/success_predicates/directory_specific_thresholds_predicate.rb
5
+
6
+ class DirectorySpecificThresholds
7
+ def self.call(model)
8
+ new(model).call
9
+ end
10
+
11
+ def initialize(model)
12
+ @files = model.relativize(model.list)
13
+ end
14
+
15
+ def files_ok?(filemask, threshold_percentage)
16
+ files = @files.select { |f| File.fnmatch?(filemask, f['file']) }
17
+ files.all? { |f| f['percentage'] >= threshold_percentage }
18
+ end
19
+
20
+ def call
21
+ [
22
+ ['lib/cov_loupe/**/*.rb', 85], # global default minimum
23
+ ['lib/cov_loupe/option_parsers/**/*.rb', 95],
24
+ ['lib/cov_loupe/tools/**/*.rb', 100]
25
+ ].map { |(filemask, threshold_pct)| files_ok?(filemask, threshold_pct) }
26
+ .all?
27
+ end
28
+ end
29
+
30
+ DirectorySpecificThresholds
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Success predicate: Total project coverage >= 85%
4
+ # Usage: cov-loupe --success-predicate examples/success_predicates/project_coverage_minimum_predicate.rb
5
+
6
+ ->(model) { model.project_totals['lines']['percent_covered'] >= 85.0 }