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,591 @@
1
+ # V4.0 Breaking Changes Guide
2
+
3
+ [Back to main README](../../index.md)
4
+
5
+ This document describes the breaking changes introduced in version 4.0.0. These changes affect the CLI flags for mode selection and staleness checks, as well as a method rename in the Ruby API.
6
+
7
+ ## Table of Contents
8
+
9
+ - [CLI Changes](#cli-changes)
10
+ - [MCP Mode Now Requires Explicit `-m/--mode mcp` Flag](#mcp-mode-now-requires-explicit-m-mode-mcp-flag)
11
+ - [Unified Stale Coverage Enforcement](#unified-stale-coverage-enforcement)
12
+ - [`--raise-on-stale` / `-S` - Explicit Value Required](#raise-on-stale-s-explicit-value-required)
13
+ - [`--color` / `-C` - Explicit Value Required](#color-c-explicit-value-required)
14
+ - [`--tracked-globs` Default Changed to Empty Array](#tracked-globs-default-changed-to-empty-array)
15
+ - [Ruby API Changes](#ruby-api-changes)
16
+ - [CoverageLineResolver Now Requires `root:` and `volume_case_sensitive:`](#coveragelineresolver-now-requires-root-and-volume_case_sensitive)
17
+ - [Method Renamed](#method-renamed)
18
+ - [Return Type Changed: `list` Now Returns a Hash](#return-type-changed-list-now-returns-a-hash)
19
+ - [Return Type Changed: `project_totals` Schema Updated](#return-type-changed-project_totals-schema-updated)
20
+ - [Logger Initialization Changed](#logger-initialization-changed)
21
+ - [Deleted Files Now Raise `FileNotFoundError`](#deleted-files-now-raise-filenotfounderror)
22
+ - [Staleness Indicators Changed from Strings to Symbols](#staleness-indicators-changed-from-strings-to-symbols)
23
+ - [Removed Branch-Only Coverage Support](#removed-branch-only-coverage-support)
24
+ - [Getting Help](#getting-help)
25
+
26
+ ---
27
+
28
+ ## CLI Changes
29
+
30
+ ### ⚠️ MCP Mode Now Requires Explicit `-m/--mode mcp` Flag
31
+
32
+ **BREAKING**: Automatic mode detection has been removed.
33
+ The `-m/--mode mcp` flag is now **required** to run cov-loupe as an MCP server.
34
+
35
+ #### Previous Behavior (v3.x)
36
+ - cov-loupe automatically detected MCP mode based on TTY/stdin status
37
+ - `--force-mode` could override detection (values: `cli`, `mcp`, `auto`)
38
+
39
+ #### New Behavior (v4.x)
40
+ - **No automatic detection** - mode defaults to `cli`
41
+ - `-m mcp` or `--mode mcp` is **required** for MCP server mode
42
+ - Accepted values: `cli` (default) or `mcp`
43
+
44
+ #### Migration for MCP Users
45
+
46
+ **If you use cov-loupe as an MCP server, you MUST update your configuration:**
47
+
48
+ 1. **Remove the old entry** (see [MCP Integration Guide - Setup by Client](../MCP_INTEGRATION.md#setup-by-client)
49
+ for removal commands with proper `--scope` options)
50
+ 2. **Add the new entry with `-m mcp` flag:**
51
+
52
+ ```sh
53
+ # Claude Code
54
+ claude mcp add cov-loupe cov-loupe -- -m mcp
55
+
56
+ # Codex
57
+ codex mcp add cov-loupe cov-loupe -m mcp
58
+
59
+ # Gemini
60
+ gemini mcp add cov-loupe cov-loupe -- -m mcp
61
+ ```
62
+
63
+ **Without `-m mcp` or `--mode mcp`, the server will run in CLI mode and hang waiting for subcommands.**
64
+
65
+ #### Migration for CLI Users
66
+
67
+ CLI users are unaffected. The default mode is `cli`, so no changes are needed. However:
68
+ - `--force-cli` removed → use `-m cli` or `--mode cli` if you need to be explicit (rare)
69
+ - `--force-mode` removed → use `-m/--mode` instead
70
+
71
+ ### Unified Stale Coverage Enforcement
72
+
73
+ The staleness checking logic has been unified into a single flag that raises an error if *any* staleness is detected.
74
+
75
+ * **Old**: `--staleness` / `check_stale` (inconsistent behavior)
76
+ * **New**: `--raise-on-stale` (boolean)
77
+
78
+ #### Behavior
79
+ * **`--raise-on-stale true` (or `raise_on_stale: true`)**: The command will exit with an error code if any file in the result set is stale or if the project totals are stale.
80
+ * **Default (false)**: Staleness is reported in the output (e.g., status `M`, `T`, `L`), but the command returns success (unless other errors occur).
81
+
82
+ #### Migration
83
+ * If you relied on previous flags to enforce staleness checks, switch to `--raise-on-stale true` or `-S true`.
84
+
85
+ **IMPORTANT:** As of v4.0.0, boolean flags now require explicit values for consistency.
86
+
87
+ ### `--raise-on-stale` / `-S` - Explicit Value Required {#raise-on-stale-s-explicit-value-required}
88
+ * **Old (no longer works)**: `--raise-on-stale`, `-S`
89
+ * **New (required)**: `--raise-on-stale true`, `-S true`, `--raise-on-stale=yes`, etc.
90
+
91
+ ### `--color` / `-C` - Explicit Value Required {#color-c-explicit-value-required}
92
+ * **Old (no longer works)**: `--color`, `-C`
93
+ * **New (required)**: `--color true`, `-C true`, `--color=on`, etc.
94
+
95
+ These changes improve consistency between short and long flag forms and eliminate ambiguous behavior where long-form bare flags would fail but short-form bare flags would succeed.
96
+
97
+ ### ⚠️ --tracked-globs Default Changed to Empty Array {#tracked-globs-default-changed-to-empty-array}
98
+
99
+ **BREAKING**: The `--tracked-globs` CLI option now defaults to `[]` (empty) instead of `lib/**/*.rb,app/**/*.rb,src/**/*.rb`. The Ruby API (`CoverageModel`) now also defaults `tracked_globs:` to `[]` (previously `nil`, which behaved the same).
100
+
101
+ This affects:
102
+ - **CLI**: `cov-loupe list` (without `--tracked-globs`)
103
+ - **Ruby API**: `CoverageModel.new` (for consistency, though behavior is unchanged)
104
+
105
+ #### Previous Behavior (v4.x early versions)
106
+ - `--tracked-globs` CLI option defaulted to `lib/**/*.rb,app/**/*.rb,src/**/*.rb`
107
+ - Files outside these patterns were silently excluded from CLI output
108
+ - `missing_tracked_files` (in `list`) included any tracked files not in coverage
109
+
110
+ #### New Behavior (v4.x current)
111
+ - `--tracked-globs` defaults to `[]` (empty)
112
+ - Shows all files in the resultset without filtering
113
+ - No files are flagged as missing unless you explicitly set globs
114
+
115
+ #### Rationale
116
+
117
+ The previous default caused three problems:
118
+ 1. **Silent exclusions**: Coverage results for files not matching the default patterns (e.g., `config/`, custom directories) were hidden
119
+ 2. **False positives**: Files like migrations, bin scripts, etc. were incorrectly flagged as "missing"
120
+ 3. **Wrong assumptions**: Not all projects use `lib/` and `app/` - some use `src/`, others have custom structures
121
+
122
+ The new default shows all coverage data transparently without making assumptions about your project structure.
123
+
124
+ #### Migration Steps
125
+
126
+ **For CLI usage** (if you want the old filtering behavior with `lib/**/*.rb,app/**/*.rb,src/**/*.rb`):
127
+
128
+ Set `COV_LOUPE_OPTS` to match your SimpleCov `track_files` configuration:
129
+
130
+ ```ruby
131
+ # In spec_helper.rb or similar
132
+ SimpleCov.start do
133
+ add_filter '/spec/'
134
+ track_files 'lib/**/*.rb'
135
+ track_files 'app/**/*.rb'
136
+ end
137
+ ```
138
+
139
+ ```sh
140
+ # In your shell config (.bashrc, .zshrc, etc.)
141
+ export COV_LOUPE_OPTS="--tracked-globs lib/**/*.rb,app/**/*.rb"
142
+ ```
143
+
144
+ **For Ruby API usage**:
145
+
146
+ No functional changes needed, but the default signature has changed for consistency. The Ruby API now defaults `tracked_globs: []` (previously `nil`). Both behave identically, so existing code works unchanged:
147
+
148
+ ```ruby
149
+ # Default behavior (behavior unchanged, signature updated for consistency)
150
+ model = CovLoupe::CoverageModel.new(root: '.')
151
+ result = model.list # tracked_globs: [] → no filtering
152
+
153
+ # Explicit globs for filtering and tracking
154
+ model = CovLoupe::CoverageModel.new(
155
+ root: '.',
156
+ tracked_globs: ['lib/**/*.rb', 'app/**/*.rb']
157
+ )
158
+ result = model.list # Uses explicit globs
159
+ ```
160
+
161
+ **If you're fine with seeing all files in the resultset (and _only_ files in the resultset)** (no action needed for CLI or Ruby API):
162
+ - The new default shows all files that have coverage data
163
+ - No filtering applied, but also no detection of files lacking coverage data
164
+
165
+ #### Important Note
166
+
167
+ **Files lacking any coverage at all** (not loaded during tests) will not appear in the resultset and therefore won't be visible with the default empty array. To detect such files, you must set `--tracked-globs` to match the files you expect to have coverage.
168
+
169
+ [↑ Back to top](#table-of-contents)
170
+
171
+ ## Ruby API Changes
172
+
173
+ ### CoverageLineResolver Now Requires `root:` and `volume_case_sensitive:`
174
+
175
+ **Breaking Change**: `CovLoupe::Resolvers::CoverageLineResolver` now requires `root:` and `volume_case_sensitive:` keyword arguments, and `CovLoupe::Resolvers::ResolverHelpers.lookup_lines` / `create_coverage_resolver` now require these parameters as well.
176
+
177
+ #### Migration
178
+ ```ruby
179
+ # Old
180
+ resolver = CovLoupe::Resolvers::CoverageLineResolver.new(cov_data)
181
+ lines = CovLoupe::Resolvers::ResolverHelpers.lookup_lines(cov_data, abs_path)
182
+
183
+ # New
184
+ root = '/path/to/project'
185
+ volume_case_sensitive = CovLoupe::PathUtils.volume_case_sensitive?(root)
186
+ resolver = CovLoupe::Resolvers::CoverageLineResolver.new(cov_data, root: root, volume_case_sensitive: volume_case_sensitive)
187
+ lines = CovLoupe::Resolvers::ResolverHelpers.lookup_lines(cov_data, abs_path, root: root, volume_case_sensitive: volume_case_sensitive)
188
+ ```
189
+
190
+ **Note**: If you're using `CoverageModel` (recommended), this is handled automatically - the model detects volume case-sensitivity during initialization based on the project root and passes it to resolvers internally.
191
+
192
+ ### Method Renamed
193
+
194
+ * **Old**: `CoverageModel#all_files_coverage`
195
+ * **New**: `CoverageModel#list`
196
+
197
+ ### Return Type Changed: `list` Now Returns a Hash
198
+
199
+ **Breaking Change**: `CoverageModel#list` now returns a **hash** containing comprehensive staleness information instead of just an array of file data.
200
+
201
+ #### Old Behavior (v3.x)
202
+ ```ruby
203
+ model = CovLoupe::CoverageModel.new(root: '.')
204
+ files = model.list # Returns array directly
205
+
206
+ # Filter and use the array
207
+ low_coverage = files.select { |f| f['percentage'] < 80 }
208
+ model.format_table(files)
209
+ ```
210
+
211
+ #### New Behavior (v4.x)
212
+ ```ruby
213
+ model = CovLoupe::CoverageModel.new(root: '.')
214
+ result = model.list # Returns hash with multiple keys
215
+
216
+ # Access the files array
217
+ files = result['files']
218
+
219
+ # Filter and use the array
220
+ low_coverage = files.select { |f| f['percentage'] < 80 }
221
+ model.format_table(files)
222
+
223
+ # Access new staleness information
224
+ result['skipped_files'] # Files that raised errors during processing
225
+ result['missing_tracked_files'] # Files from tracked_globs not in coverage
226
+ result['newer_files'] # Files modified after coverage was generated
227
+ result['deleted_files'] # Files in coverage that no longer exist
228
+ ```
229
+
230
+ #### Migration Steps
231
+
232
+ **Option 1: Quick Fix (Extract files array)**
233
+ ```ruby
234
+ # Old
235
+ files = model.list
236
+
237
+ # New
238
+ files = model.list['files']
239
+ ```
240
+
241
+ **Option 2: Leverage New Staleness Data**
242
+ ```ruby
243
+ result = model.list
244
+
245
+ # Use the files array as before
246
+ files = result['files']
247
+ low_coverage = files.select { |f| f['percentage'] < 80 }
248
+
249
+ # Now you can also:
250
+ if result['skipped_files'].any?
251
+ warn "Warning: #{result['skipped_files'].size} files were skipped due to errors"
252
+ result['skipped_files'].each do |skip|
253
+ warn " #{skip['file']}: #{skip['error']}"
254
+ end
255
+ end
256
+
257
+ if result['newer_files'].any?
258
+ warn "Warning: #{result['newer_files'].size} files are newer than coverage data"
259
+ end
260
+ ```
261
+
262
+ #### Impact on `format_table`
263
+
264
+ The `format_table` method still accepts an array of file hashes (not the full hash from `list`):
265
+
266
+ ```ruby
267
+ # Correct
268
+ files = model.list['files']
269
+ table = model.format_table(files)
270
+
271
+ # Also correct (passing nil gets all files)
272
+ table = model.format_table(nil)
273
+
274
+ # Incorrect - do not pass the full hash
275
+ result = model.list
276
+ table = model.format_table(result) # This will fail
277
+ ```
278
+
279
+ ### Return Type Changed: `project_totals` Schema Updated
280
+
281
+ **Breaking Change**: `CoverageModel#project_totals` now returns a structured hash with
282
+ explicit `lines`, `tracking`, and `files` sections. The top-level `percentage` and
283
+ `excluded_files` fields were removed.
284
+
285
+ #### Old Behavior (v3.x)
286
+ ```ruby
287
+ totals = model.project_totals
288
+ # => {
289
+ # "lines" => { "total" => 123, "covered" => 100, "uncovered" => 23 },
290
+ # "percentage" => 81.3,
291
+ # "files" => { "total" => 4, "ok" => 4, "stale" => 0 },
292
+ # "excluded_files" => { ... }
293
+ # }
294
+ ```
295
+
296
+ #### New Behavior (v4.x)
297
+ ```ruby
298
+ totals = model.project_totals
299
+ # => {
300
+ # "lines" => { "total" => 123, "covered" => 100, "uncovered" => 23, "percent_covered" => 81.3 },
301
+ # "tracking" => { "enabled" => true, "globs" => ["lib/**/*.rb"] },
302
+ # "files" => {
303
+ # "total" => 4,
304
+ # "with_coverage" => { "total" => 4, "ok" => 4, "stale" => { "total" => 0, "by_type" => { ... } } }
305
+ # }
306
+ # }
307
+ ```
308
+
309
+ #### Migration Steps
310
+ - Replace `totals['percentage']` with `totals['lines']['percent_covered']`.
311
+ - Replace `totals['files']['ok']` and `totals['files']['stale']` with
312
+ `totals['files']['with_coverage']['ok']` and `totals['files']['with_coverage']['stale']['total']`.
313
+ - If you relied on `excluded_files`, use `files.with_coverage.stale.by_type` and
314
+ `files.without_coverage.by_type` (present only when tracking is enabled).
315
+
316
+ ### Logger Initialization Changed
317
+
318
+ The `CovLoupe::Logger` class has updated its `initialize` signature.
319
+
320
+ * **Old**: `initialize(target:, mcp_mode: false)`
321
+ * **New**: `initialize(target:, mode: :library)` # or :cli or :mcp
322
+
323
+ #### Migration
324
+
325
+ If you are manually instantiating `CovLoupe::Logger`:
326
+
327
+ ```ruby
328
+ # Old
329
+ logger = CovLoupe::Logger.new(target: 'cov_loupe.log', mcp_mode: true)
330
+ logger = CovLoupe::Logger.new(target: 'cov_loupe.log', mcp_mode: false)
331
+
332
+ # New
333
+ logger = CovLoupe::Logger.new(target: 'cov_loupe.log', mode: :mcp)
334
+ logger = CovLoupe::Logger.new(target: 'cov_loupe.log', mode: :cli) # or :library
335
+ ```
336
+
337
+ [↑ Back to top](#table-of-contents)
338
+
339
+ ## Deleted Files Now Raise `FileNotFoundError`
340
+
341
+ **Breaking Change**: Querying a file that has been deleted (but still exists in the coverage resultset) now raises `FileNotFoundError` instead of returning stale coverage data.
342
+
343
+ ### Previous Behavior (v3.x)
344
+ ```ruby
345
+ # File lib/foo.rb was deleted after running tests
346
+ model = CovLoupe::CoverageModel.new(root: '.')
347
+ result = model.summary_for('lib/foo.rb')
348
+ # => { 'file' => '/path/to/lib/foo.rb', 'summary' => { 'covered' => 4, 'total' => 6, 'percentage' => 66.67 } }
349
+ # Returns stale coverage data with no error
350
+ ```
351
+
352
+ ```sh
353
+ # CLI would return coverage percentage and exit 0
354
+ $ cov-loupe summary lib/foo.rb
355
+ lib/foo.rb: 66.67% (4/6)
356
+ $ echo $?
357
+ 0
358
+ ```
359
+
360
+ ### New Behavior (v4.x)
361
+ ```ruby
362
+ # File lib/foo.rb was deleted after running tests
363
+ model = CovLoupe::CoverageModel.new(root: '.')
364
+ result = model.summary_for('lib/foo.rb')
365
+ # => raises CovLoupe::FileNotFoundError: "File not found: lib/foo.rb"
366
+ ```
367
+
368
+ ```sh
369
+ # CLI raises error and exits 1
370
+ $ cov-loupe summary lib/foo.rb
371
+ Error: File not found: lib/foo.rb
372
+ $ echo $?
373
+ 1
374
+ ```
375
+
376
+ ### Rationale
377
+
378
+ Deleted files represent **stale data** that:
379
+ 1. Misleads coverage metrics and statistics
380
+ 2. Violates the API contract (docstring already promised `FileNotFoundError`)
381
+ 3. Should be treated the same as other staleness issues
382
+
383
+ If a file no longer exists, its coverage data is no longer meaningful. The new behavior ensures you don't accidentally include deleted file coverage in your metrics.
384
+
385
+ ### Impact
386
+
387
+ This affects:
388
+ - `model.summary_for(path)` - All single-file query methods
389
+ - `model.raw_for(path)`
390
+ - `model.uncovered_for(path)`
391
+ - `model.detailed_for(path)`
392
+ - CLI commands: `summary`, `raw`, `uncovered`, `detailed`
393
+ - MCP tools: `coverage_summary_tool`, `coverage_raw_tool`, etc.
394
+
395
+ ### Migration
396
+
397
+ **If you expect deleted files to raise errors** (recommended):
398
+ - No action needed. This is the correct behavior.
399
+
400
+ **If you relied on getting coverage for deleted files**:
401
+ - This was incorrect behavior. Update your workflow to:
402
+ 1. Re-run tests after file deletions to get fresh coverage, OR
403
+ 2. Use the `list` command to see deleted files in the `deleted_files` array without querying them directly
404
+
405
+ **Example: Checking for deleted files**
406
+ ```ruby
407
+ model = CovLoupe::CoverageModel.new(root: '.')
408
+ result = model.list
409
+
410
+ if result['deleted_files'].any?
411
+ puts "Warning: Coverage data exists for deleted files:"
412
+ result['deleted_files'].each { |f| puts " - #{f}" }
413
+ end
414
+ ```
415
+
416
+ [↑ Back to top](#table-of-contents)
417
+
418
+ ---
419
+
420
+ ## Staleness Indicators Changed from Strings to Symbols
421
+
422
+ **Breaking Change**: Staleness indicators in the `stale` field now use Ruby symbols instead of single-character strings.
423
+
424
+ ### Previous Behavior (v3.x)
425
+ ```ruby
426
+ result = model.list
427
+ # => { 'files' => [{ 'file' => 'lib/foo.rb', 'stale' => 'M', ... }], ... }
428
+
429
+ # Staleness was indicated by strings:
430
+ # 'M' - Missing file
431
+ # 'T' - Timestamp mismatch
432
+ # 'L' - Line count mismatch
433
+ # 'E' - Error during staleness check
434
+ # false - Fresh coverage data
435
+ ```
436
+
437
+ ### New Behavior (v4.x)
438
+ ```ruby
439
+ result = model.list
440
+ # => { 'files' => [{ 'file' => 'lib/foo.rb', 'stale' => "missing", ... }], ... }
441
+
442
+ # Staleness is now indicated by symbols:
443
+ # "missing" - Missing file
444
+ # "newer" - Timestamp mismatch
445
+ # "length_mismatch" - Line count mismatch
446
+ # "error" - Error during staleness check
447
+ # "ok" - Fresh coverage data
448
+ ```
449
+
450
+ ### Rationale
451
+
452
+ Symbols are more idiomatic in Ruby for enumerated values and provide:
453
+ - **Better performance**: Symbols are interned, so comparisons are faster
454
+ - **Clearer semantics**: Symbols represent categories/concepts, not text
455
+ - **Consistency**: Aligns with Ruby conventions for status indicators
456
+ - **Type safety**: Symbol vs String distinction catches bugs
457
+
458
+ ### Impact
459
+
460
+ This affects code that:
461
+ - **Checks equality with string literals**: `stale == 'M'` will no longer match
462
+ - **Uses string pattern matching**: Case statements with string patterns need updating
463
+ - **Serializes to JSON**: Symbols are converted to strings in JSON output
464
+ - **Type checks**: `stale.is_a?(Symbol)` instead of `stale.is_a?(String)`
465
+
466
+ **Frequency**: High - affects any code that checks staleness status.
467
+
468
+ ### Migration
469
+
470
+ **If you check equality with string literals**:
471
+ ```ruby
472
+ # Old
473
+ if file['stale'] == 'M'
474
+ puts "File is missing"
475
+ end
476
+
477
+ # New - use symbols
478
+ if file['stale'] == 'missing'
479
+ puts "File is missing"
480
+ end
481
+
482
+ # Or use string comparison (less efficient but works with both versions)
483
+ if file['stale'].to_s == 'missing'
484
+ puts "File is missing"
485
+ end
486
+ ```
487
+
488
+ **If you use case statements with string patterns**:
489
+ ```ruby
490
+ # Old
491
+ case file['stale']
492
+ when 'M' then handle_missing
493
+ when 'T' then handle_timestamp
494
+ when 'L' then handle_length
495
+ when 'E' then handle_error
496
+ when false then handle_fresh
497
+ end
498
+
499
+ # New - use symbols
500
+ case file['stale']
501
+ when 'missing' then handle_missing
502
+ when 'newer' then handle_timestamp
503
+ when 'length_mismatch' then handle_length
504
+ when 'error' then handle_error
505
+ when 'ok' then handle_fresh
506
+ end
507
+
508
+ # Or use to_s for backward compatibility
509
+ case file['stale'].to_s
510
+ when 'missing' then handle_missing
511
+ when 'newer' then handle_timestamp
512
+ when 'length_mismatch' then handle_length
513
+ when 'error' then handle_error
514
+ when 'ok' then handle_fresh
515
+ end
516
+ ```
517
+
518
+ **If you check for any staleness**:
519
+ ```ruby
520
+ # Old (works for both versions)
521
+ if file['stale']
522
+ puts "Stale file (#{file['stale']})"
523
+ end
524
+
525
+ # New - explicit type check
526
+ if file['stale'].is_a?(Symbol)
527
+ puts "Stale file (#{file['stale']})"
528
+ end
529
+
530
+ # Or use the same approach (works for both versions)
531
+ if file['stale']
532
+ puts "Stale file (#{file['stale']})"
533
+ end
534
+ ```
535
+
536
+ **JSON serialization note**: When serializing to JSON (CLI, MCP, etc.), symbols are automatically converted to strings:
537
+ ```ruby
538
+ # In Ruby
539
+ file['stale'] # => "missing"
540
+
541
+ # In JSON output
542
+ { "file": "lib/foo.rb", "stale": "missing" }
543
+ ```
544
+
545
+ **Table output legend updated**:
546
+ ```
547
+ Staleness: missing = Missing file, newer = Timestamp mismatch, length_mismatch = Line count mismatch, error = Check failed
548
+ ```
549
+
550
+ ### Complete Staleness Value Reference
551
+
552
+ | Status | v3.x (String) | v4.x (Symbol) | Description |
553
+ |--------|----------------|------------------|-------------|
554
+ | Fresh | `false` | `"ok"` | Coverage data is current |
555
+ | Missing file | `'M'` | `"missing"` | File no longer exists on disk |
556
+ | Timestamp mismatch | `'T'` | `"newer"` | File modified after coverage was generated |
557
+ | Line count mismatch | `'L'` | `"length_mismatch"` | Source file line count differs from coverage data |
558
+ | Check error | `'E'` | `"error"` | Staleness check failed (permissions, I/O errors, etc.) |
559
+
560
+ [↑ Back to top](#table-of-contents)
561
+
562
+ ---
563
+
564
+ ## Removed Branch-Only Coverage Support
565
+
566
+ **Breaking Change**: The automatic synthesis of line coverage data from SimpleCov branch-only coverage results has been removed.
567
+
568
+ ### Rationale
569
+ The logic required to maintain this feature was complex and prone to edge cases, particularly regarding staleness detection and line-count mismatches. Additionally, branch-only coverage is a rarely used configuration in the SimpleCov ecosystem.
570
+
571
+ ### Impact
572
+ If your project is configured to track **only** branch coverage in SimpleCov (e.g., `enable_coverage :branch` without also tracking lines), `cov-loupe` will no longer be able to process your coverage data and will raise a `CorruptCoverageDataError`.
573
+
574
+ ### How to Migrate
575
+ Most users do not need to take any action. Line coverage is enabled by default in SimpleCov.
576
+
577
+ If you have `enable_coverage :branch` in your configuration, your `.resultset.json` contains both `lines` and `branches` data. **This is fully supported.** `cov-loupe` will read and report the `lines` coverage as usual.
578
+
579
+ The change in v4.0 is simply that `cov-loupe` no longer looks at the `branches` data at all. Previously, if `lines` data was missing (a rare edge case), `cov-loupe` would attempt to calculate line coverage by summing up branch hits. This fallback logic has been removed.
580
+
581
+ [↑ Back to top](#table-of-contents)
582
+
583
+ ---
584
+
585
+ ## Getting Help
586
+
587
+ If you encounter issues migrating to v4.0:
588
+
589
+ 1. Check the [TROUBLESHOOTING.md](../TROUBLESHOOTING.md) guide.
590
+ 2. Review the [CLI_USAGE.md](../CLI_USAGE.md) for complete CLI reference.
591
+ 3. Open an issue at https://github.com/keithrbennett/cov-loupe/issues.
@@ -0,0 +1,22 @@
1
+ # Migration Guides
2
+
3
+ Upgrade guides for major version changes in cov-loupe.
4
+
5
+ ## Available Guides
6
+
7
+ - [Migrating to v4](MIGRATING_TO_V4.md) - Upgrade from v3.x to v4.x
8
+ - [Migrating to v3](MIGRATING_TO_V3.md) - Upgrade from v2.x to v3.x
9
+ - [Migrating to v2](MIGRATING_TO_V2.md) - Upgrade from v1.x to v2.x
10
+
11
+ ## General Migration Tips
12
+
13
+ 1. Always review the [Release Notes](../../release_notes.md) for your target version
14
+ 2. Run your test suite after upgrading to catch any breaking changes
15
+ 3. Check the [Troubleshooting Guide](../TROUBLESHOOTING.md) if you encounter issues
16
+
17
+ ## Need Help?
18
+
19
+ If you encounter issues during migration, please:
20
+ - Check the relevant migration guide above for your version
21
+ - Review the [Troubleshooting Guide](../TROUBLESHOOTING.md)
22
+ - Search or open an issue on [GitHub](https://github.com/keithrbennett/cov-loupe/issues)
@@ -0,0 +1,9 @@
1
+ # Prompt Library
2
+
3
+ [Back to main README](../../index.md)
4
+
5
+ Starter prompts you can paste into MCP-compatible assistants when you need cov-loupe to run targeted reports or fall back to CLI execution.
6
+
7
+ - [Rails Coverage Analysis](rails-coverage-analysis-prompt.md) – Guide an assistant through triaging a Rails `.resultset.json`
8
+ - [Non-Web Coverage Analysis](non-web-coverage-analysis-prompt.md) – Prompts for service/library repos
9
+ - [Use CLI Instead of MCP](use-cli-not-mcp-prompt.md) – Scripted fallback when MCP transport is blocked