cov-loupe 5.0.0 → 6.0.0

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 (118) hide show
  1. checksums.yaml +4 -4
  2. data/AGENTS.md +44 -20
  3. data/CONTRIBUTING.md +83 -51
  4. data/README.md +75 -55
  5. data/RELEASE_NOTES.md +26 -3
  6. data/dev/prompts/README.md +15 -10
  7. data/dev/prompts/guidelines/ai-code-evaluator-guidelines.md +7 -7
  8. data/dev/prompts/improve/refactor-test-suite.md +19 -4
  9. data/dev/prompts/improve/simplify-code-logic.md +18 -4
  10. data/dev/prompts/improve/update-documentation.md +23 -10
  11. data/dev/prompts/review/comprehensive-codebase-review.md +37 -16
  12. data/dev/prompts/review/identify-action-items.md +51 -20
  13. data/dev/prompts/review/review-documentation.md +91 -0
  14. data/dev/prompts/review/verify-code-changes.md +15 -5
  15. data/dev/prompts/validate/test-documentation-examples.md +12 -1
  16. data/dev/scripts/verify_doc_links.rb +462 -0
  17. data/docs/dev/ARCHITECTURE.md +11 -11
  18. data/docs/dev/DEVELOPMENT.md +7 -3
  19. data/docs/dev/README.md +2 -0
  20. data/docs/dev/arch-decisions/README.md +1 -1
  21. data/docs/dev/arch-decisions/application-architecture.md +11 -11
  22. data/docs/dev/arch-decisions/coverage-data-quality.md +3 -3
  23. data/docs/dev/arch-decisions/output-character-mode.md +3 -3
  24. data/docs/dev/arch-decisions/path-resolution.md +3 -3
  25. data/docs/dev/arch-decisions/policy-validation.md +33 -31
  26. data/docs/dev/arch-decisions/simplecov-integration.md +9 -10
  27. data/docs/fixtures/demo_project/README.md +1 -1
  28. data/docs/index.md +1 -0
  29. data/docs/user/ADVANCED_USAGE.md +30 -42
  30. data/docs/user/CLI_FALLBACK_FOR_LLMS.md +2 -2
  31. data/docs/user/CLI_USAGE.md +175 -112
  32. data/docs/user/ERROR_HANDLING.md +21 -12
  33. data/docs/user/EXAMPLES.md +2 -2
  34. data/docs/user/INSTALLATION.md +2 -0
  35. data/docs/user/LIBRARY_API.md +50 -42
  36. data/docs/user/MCP_INTEGRATION.md +123 -12
  37. data/docs/user/README.md +1 -1
  38. data/docs/user/TROUBLESHOOTING.md +92 -3
  39. data/docs/user/installing-a-prelease-version-of-covloupe.md +2 -0
  40. data/docs/user/migrations/MIGRATING_TO_V4.md +32 -48
  41. data/docs/user/migrations/MIGRATING_TO_V5.md +2 -2
  42. data/docs/user/migrations/MIGRATING_TO_V6.md +166 -0
  43. data/docs/user/migrations/README.md +1 -0
  44. data/docs/user/prompts/use-cli-not-mcp-prompt.md +1 -1
  45. data/examples/cli_demo.sh +19 -19
  46. data/examples/filter_and_table_demo.rb +1 -1
  47. data/examples/mcp-inputs/coverage_detailed.json +1 -1
  48. data/examples/mcp-inputs/coverage_raw.json +1 -1
  49. data/examples/mcp-inputs/coverage_summary.json +1 -1
  50. data/examples/mcp-inputs/uncovered_lines.json +1 -1
  51. data/examples/success_predicates/README.md +9 -7
  52. data/examples/success_predicates/all_files_above_threshold_predicate.rb +4 -4
  53. data/examples/success_predicates/directory_specific_thresholds_predicate.rb +6 -6
  54. data/examples/success_predicates/project_coverage_minimum_predicate.rb +2 -2
  55. data/exe/cov-loupe +45 -16
  56. data/lib/cov_loupe/base_tool.rb +61 -33
  57. data/lib/cov_loupe/cli.rb +26 -15
  58. data/lib/cov_loupe/commands/base_command.rb +5 -0
  59. data/lib/cov_loupe/commands/command_factory.rb +9 -6
  60. data/lib/cov_loupe/commands/detailed_command.rb +6 -5
  61. data/lib/cov_loupe/commands/raw_command.rb +5 -5
  62. data/lib/cov_loupe/commands/summary_command.rb +4 -4
  63. data/lib/cov_loupe/commands/totals_command.rb +2 -2
  64. data/lib/cov_loupe/commands/uncovered_command.rb +3 -3
  65. data/lib/cov_loupe/config/app_config.rb +33 -6
  66. data/lib/cov_loupe/config/app_context.rb +8 -1
  67. data/lib/cov_loupe/config/boolean_type.rb +2 -2
  68. data/lib/cov_loupe/config/config_parser.rb +7 -3
  69. data/lib/cov_loupe/config/logger.rb +25 -6
  70. data/lib/cov_loupe/config/option_normalizers.rb +81 -37
  71. data/lib/cov_loupe/config/option_parser_builder.rb +5 -5
  72. data/lib/cov_loupe/coverage/coverage_calculator.rb +11 -5
  73. data/lib/cov_loupe/coverage/coverage_reporter.rb +6 -2
  74. data/lib/cov_loupe/coverage/coverage_table_formatter.rb +17 -7
  75. data/lib/cov_loupe/errors/error_handler.rb +13 -3
  76. data/lib/cov_loupe/errors/error_handler_factory.rb +6 -0
  77. data/lib/cov_loupe/errors/errors.rb +28 -8
  78. data/lib/cov_loupe/formatters/formatters.rb +54 -53
  79. data/lib/cov_loupe/formatters/source_formatter.rb +15 -4
  80. data/lib/cov_loupe/formatters/table_formatter.rb +6 -3
  81. data/lib/cov_loupe/loaders/resultset_loader.rb +33 -8
  82. data/lib/cov_loupe/mcp_server.rb +16 -5
  83. data/lib/cov_loupe/model/model.rb +79 -50
  84. data/lib/cov_loupe/model/model_data_cache.rb +24 -16
  85. data/lib/cov_loupe/option_parsers/error_helper.rb +3 -2
  86. data/lib/cov_loupe/output_chars.rb +20 -20
  87. data/lib/cov_loupe/paths/glob_utils.rb +5 -0
  88. data/lib/cov_loupe/paths/path_relativizer.rb +9 -0
  89. data/lib/cov_loupe/paths/path_utils.rb +20 -7
  90. data/lib/cov_loupe/paths/volume_case_sensitivity.rb +4 -2
  91. data/lib/cov_loupe/presenters/base_coverage_presenter.rb +4 -0
  92. data/lib/cov_loupe/presenters/coverage_payload_presenter.rb +4 -1
  93. data/lib/cov_loupe/presenters/payload_caching.rb +6 -0
  94. data/lib/cov_loupe/presenters/project_coverage_presenter.rb +14 -10
  95. data/lib/cov_loupe/presenters/project_totals_presenter.rb +1 -1
  96. data/lib/cov_loupe/repositories/coverage_repository.rb +9 -11
  97. data/lib/cov_loupe/resolvers/coverage_line_resolver.rb +12 -5
  98. data/lib/cov_loupe/resolvers/resolver_helpers.rb +3 -0
  99. data/lib/cov_loupe/resolvers/resultset_path_resolver.rb +21 -4
  100. data/lib/cov_loupe/resources.rb +5 -4
  101. data/lib/cov_loupe/scripts/latest_ci_status.rb +2 -2
  102. data/lib/cov_loupe/scripts/setup_doc_server.rb +10 -4
  103. data/lib/cov_loupe/scripts/start_doc_server.rb +16 -1
  104. data/lib/cov_loupe/staleness/stale_status.rb +12 -0
  105. data/lib/cov_loupe/staleness/staleness_checker.rb +65 -38
  106. data/lib/cov_loupe/staleness/staleness_message_formatter.rb +9 -3
  107. data/lib/cov_loupe/tools/file_coverage_detailed_tool.rb +5 -5
  108. data/lib/cov_loupe/tools/file_coverage_raw_tool.rb +5 -5
  109. data/lib/cov_loupe/tools/file_coverage_summary_tool.rb +5 -5
  110. data/lib/cov_loupe/tools/file_uncovered_lines_tool.rb +5 -5
  111. data/lib/cov_loupe/tools/help_tool.rb +42 -42
  112. data/lib/cov_loupe/tools/project_coverage_tool.rb +28 -23
  113. data/lib/cov_loupe/tools/project_coverage_totals_tool.rb +7 -7
  114. data/lib/cov_loupe/tools/project_validate_tool.rb +8 -9
  115. data/lib/cov_loupe/tools/version_tool.rb +5 -5
  116. data/lib/cov_loupe/version.rb +1 -1
  117. data/lib/cov_loupe.rb +31 -10
  118. metadata +23 -51
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 18d4a240f848866ddec4cfc80a37c94b61d9ee92631c3fa017c7624fcb4b12f8
4
- data.tar.gz: 6784f32fbb29346efaeec43612a1a5627f663714e59d0eccdec6f87dc18fe9c2
3
+ metadata.gz: 596b917ef1e78eca9ae6ce05c0d351f963065c0d7506bc74c387548ba51a430a
4
+ data.tar.gz: 1a85f7fc229c84e578f9ddd7226b88ca2791e352f3b76438ae2120465bcb70a9
5
5
  SHA512:
6
- metadata.gz: 4b1f607ee6f04b42c9019f8991584ca42108358a5939736fc0e661845d4b3e4d11315426e6259c3d6e8e30e8afabd83884fa8e9e2d2f142420ef844dabf43a74
7
- data.tar.gz: 615a1f0dc47439029bf6f577ff32a880dfe758f863a301ccbf0af2823d1f953b8e66655661671597b567f3d61efc373ce4377d42323561d2a9bc06e5d846e299
6
+ metadata.gz: 8a38acddf9daf5d33d30002ff5392269b69e89dc5b5b3d63fa4823835d546a011326465188f55216dd32f6598c60f8b1e878dbd0ba374c1aa696e91f61ca5b04
7
+ data.tar.gz: a742933c4722697bea231eb4e7714804dd1cb721c7640b5afef7d22d1800d0a7c38591f3a122911f8a8d1cc5b307eebce91267f7b2e434f7d008570b15292b93
data/AGENTS.md CHANGED
@@ -9,7 +9,7 @@ This file provides guidance to Codex, Claude Code (claude.ai/code), Gemini CLI,
9
9
  computing it from scratch or analyzing the Simplecov-generated .resultset.json file directly.
10
10
  - Keep workflow transparent: explain what you did, why it matters, and what the user should consider next.
11
11
  - Leave the repository tidy; only touch files that advance the request. If you find
12
- other opportunities for improvement along te way, mention them in the form of a prompt the user can use later.
12
+ other opportunities for improvement along the way, mention them in the form of a prompt the user can use later.
13
13
 
14
14
  ## Running External Commands
15
15
 
@@ -27,9 +27,27 @@ Prefer project‑local tools and scripts (for example, bin/ scripts, package.jso
27
27
  - Planning tool: skip for trivial chores; otherwise create a multi-step plan and keep it updated as you work (max one `in_progress` step).
28
28
  - When moving or renaming tracked files, use `git mv` (or `git mv -k`) instead of plain `mv` so history stays intact.
29
29
 
30
+ ## Ruby Guidelines
31
+ - Use the project's Ruby version.
32
+ - Prefer `bundle exec` for project tools.
33
+ - Prefer binstubs when present:
34
+ - `bin/rake`
35
+ - `bin/rspec`
36
+ - `bin/rubocop`
37
+ - Before editing, inspect:
38
+ - `Gemfile`
39
+ - `Gemfile.lock`
40
+ - `*.gemspec`
41
+ - `.rubocop.yml`
42
+ - `.rspec`
43
+ - Run the smallest relevant test first.
44
+ - Preserve existing Ruby idioms.
45
+ - Do not add gems unless necessary.
46
+ - If `ruby-lsp` is available, prefer symbol-aware analysis over broad file dumping when the tool supports that workflow.
47
+
30
48
  ## Repository Snapshot
31
49
  - Ruby gem exposing a SimpleCov coverage CLI (`exe/cov-loupe`) and MCP server; library lives under `lib/cov_loupe/`.
32
- - Key files: main entry point at `lib/cov_loupe.rb`, core modules in `lib/cov_loupe/` including `cli.rb`, `model.rb`, `mcp_server.rb`, and tool implementations in `lib/cov_loupe/tools/*.rb`.
50
+ - Key files: main entry point at `lib/cov_loupe.rb`, core modules in `lib/cov_loupe/` including `cli.rb`, `model/model.rb`, `mcp_server.rb`, and tool implementations in `lib/cov_loupe/tools/*.rb`.
33
51
  - Tests: RSpec under `spec/` with fixtures in `spec/fixtures/`; running tests produces `coverage/.resultset.json` consumed by the tools.
34
52
  - Useful commands:
35
53
  - `bundle install` – install dependencies
@@ -38,7 +56,7 @@ Prefer project‑local tools and scripts (for example, bin/ scripts, package.jso
38
56
  - `cov-loupe list` – table view of coverage data
39
57
 
40
58
  ## Project Overview
41
- `cov-loupe` is a Ruby gem that ships both a CLI and an MCP (Model Context Protocol) server for inspecting SimpleCov coverage data. It reads coverage resultsets directly (SimpleCov is only loaded when multi-suite merges are required) and exposes multiple data formats: file summaries, raw line arrays, uncovered lines, per-line detail, and repo-level tables.
59
+ `cov-loupe` is a Ruby gem that ships both a CLI and an MCP (Model Context Protocol) server for inspecting SimpleCov coverage data. It reads coverage resultsets directly (SimpleCov itself is a runtime dependency and is loaded when multi-suite merges are required) and exposes multiple data formats: file summaries, raw line arrays, uncovered lines, per-line detail, and repo-level tables.
42
60
 
43
61
  ### Key Technologies
44
62
  - **Ruby** – implementation language and packaging format (gem).
@@ -50,15 +68,15 @@ Prefer project‑local tools and scripts (for example, bin/ scripts, package.jso
50
68
  `CovLoupe.run` operates in either CLI mode (default) or MCP server mode (when `-m mcp` or `--mode mcp` is specified). This dual-mode entry point enables both interactive commands and background tool-serving from the same executable.
51
69
 
52
70
  ### Core Components
53
- - `lib/cov_loupe/model.rb` (`CoverageModel`) – core API for querying and shaping coverage data.
71
+ - `lib/cov_loupe/model/model.rb` (`CoverageModel`) – core API for querying and shaping coverage data.
54
72
  - `lib/cov_loupe/cli.rb` (`CoverageCLI`) – CLI interface with subcommands like `list`, `summary`, `raw`, and more.
55
73
  - `lib/cov_loupe/mcp_server.rb` (`MCPServer`) – JSON-RPC server that exposes tools to MCP clients.
56
74
  - `lib/cov_loupe/tools/*.rb` – tool implementations (`file_coverage_summary`, `project_coverage`, etc.).
57
- - Error handling utilities keep behavior context-aware (friendly CLI output, raised exceptions for libraries, structured MCP responses logged to `./cov_loupe.log`).
75
+ - Error handling utilities keep behavior context-aware: friendly CLI output, raised exceptions for libraries, and `tools/call` results with `isError: true` for MCP argument-validation and tool-execution failures. Protocol- or dispatch-level failures such as unknown tools remain JSON-RPC errors.
58
76
 
59
77
  ### Coverage Data Flow
60
78
  1. Read SimpleCov `.resultset.json` files without needing SimpleCov at runtime (unless merging suites).
61
- 2. Resolve file paths using absolute match, relative path matching, and basename fallback strategies.
79
+ 2. Resolve file paths using exact normalized matches and project-root-relative matching.
62
80
  3. Provide coverage data in multiple formats: raw arrays, summaries, uncovered lines, per-line details, totals, and formatted tables.
63
81
 
64
82
  ## Building, Running, and Testing
@@ -94,11 +112,14 @@ Use `bundle exec rspec spec/path_spec.rb` to target specific specs when needed.
94
112
  # or
95
113
  cov-loupe --help
96
114
  ```
97
- - Exercise the MCP server manually by piping JSON-RPC:
115
+ - Smoke-test the MCP server manually by piping JSON-RPC:
98
116
  ```sh
99
- echo '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"file_coverage_summary","arguments":{"path":"lib/cov_loupe/model.rb"}}}' | bundle exec exe/cov-loupe -m mcp
117
+ echo '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"file_coverage_summary","arguments":{"path":"lib/cov_loupe/model/model.rb"}}}' | bundle exec exe/cov-loupe -m mcp
100
118
  echo '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"help","arguments":{}}}' | bundle exec exe/cov-loupe -m mcp
101
119
  ```
120
+ These commands confirm that the server launches and responds over stdio; they are not exhaustive
121
+ contract tests. Optional validation and error sanity checks are documented in
122
+ [MCP Integration — Error Responses](docs/user/MCP_INTEGRATION.md#error-responses).
102
123
 
103
124
  ### Building
104
125
  ```sh
@@ -124,12 +145,12 @@ The `cov-loupe` executable can be run directly (`bundle exec exe/cov-loupe ...`
124
145
  Run `cov-loupe` in MCP mode with `-m mcp`/`--mode mcp`. You can issue JSON-RPC requests over stdio, for example:
125
146
  ```
126
147
  {"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"help","arguments":{}}}
127
- {"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"file_coverage_summary","arguments":{"path":"lib/cov_loupe/model.rb"}}}
148
+ {"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"file_coverage_summary","arguments":{"path":"lib/cov_loupe/model/model.rb"}}}
128
149
  ```
129
- All responses are emitted as `type: "text"`; JSON objects are returned as JSON strings in the content payload so MCP clients can parse them easily.
150
+ All responses are emitted as `type: "text"`; JSON objects are returned as JSON strings in the content payload so MCP clients can parse them easily. **Check `result.isError` before parsing content as a successful payload** — `isError: true` means the tool call failed (bad path, invalid predicate, missing required argument, invalid enum, etc.). A top-level JSON-RPC `error` response (instead of a `result`) indicates a protocol- or dispatch-level failure, such as an unknown tool.
130
151
 
131
152
  ## Prompt Examples for MCP Clients
132
- - “What’s the coverage percentage for `lib/cov_loupe/model.rb`?” → call `file_coverage_summary`.
153
+ - “What’s the coverage percentage for `lib/cov_loupe/model/model.rb`?” → call `file_coverage_summary`.
133
154
  - “Which lines in `spec/fixtures/project1/lib/bar.rb` are uncovered?” → call `file_uncovered_lines`.
134
155
  - "Show the repo coverage table sorted worst-first." → call `project_coverage` with `{"sort_order":"ascending"}` (default order highlights highest coverage first, worst at end).
135
156
  - “List files with the worst coverage.” → call `project_coverage` (optionally `{"sort_order":"ascending"}`).
@@ -139,24 +160,27 @@ Always prefer these tools over free-form reasoning to keep responses grounded in
139
160
  ## MCP Tool Playbook
140
161
  - Always select an MCP tool over ad-hoc reasoning for coverage data. Unsure which one fits? Call `help`.
141
162
  - Available tools: `file_coverage_summary`, `file_coverage_detailed`, `file_uncovered_lines`, `file_coverage_raw`, `project_coverage`, `project_coverage_totals`, `project_validate`, `help`, and `version`.
142
- - Responses return deterministic JSON/text; surface the tool output directly unless the user asks for interpretation. Note that `project_coverage` now includes `skipped_files`, `missing_tracked_files`, `newer_files`, and `deleted_files` arrays in its output to report any files that could not be processed due to errors or staleness.
163
+ - Check `result.isError` before parsing tool response content. `isError: false` means the tool succeeded; `isError: true` means the call failed (bad path, invalid predicate, stale coverage, missing required argument, invalid enum, etc.) and the `content` carries a friendly error message. A top-level JSON-RPC `error` object (not a `result`) indicates a protocol- or dispatch-level failure, such as an unknown tool.
164
+ - On success, responses return deterministic JSON/text; surface the tool output directly unless the user asks for interpretation. Note that `project_coverage` now includes `skipped_files`, `missing_tracked_files`, `newer_files`, `deleted_files`, `length_mismatch_files`, and `unreadable_files` arrays in its output to report any files that could not be processed due to errors or staleness.
143
165
 
144
166
  ## Development Conventions
145
167
  - Target Ruby >= 3.2; use two-space indentation and `# frozen_string_literal: true` in Ruby files.
146
- - Match existing style and patterns (see `CoverageModel` and `CovUtil` helpers). Comments should clarify non-obvious logic only.
168
+ - Match existing style and patterns (see `CoverageModel` and `CoverageCalculator` helpers). Comments should clarify non-obvious logic only.
147
169
  - Never undo or overwrite user changes outside your scope; integrate with them instead. However, if the new changes would be better implemented by modifying other sections, e.g., extracting now-duplicated behavior into a special method, then do that.
148
170
  - When adding behavior, couple it with tests; keep or raise coverage. Specs belong in `spec/**/*_spec.rb` mirroring the lib path.
149
171
  - Validate meaningful changes with `bundle exec rspec` when feasible; note skipped verification in your summary if you cannot run it.
150
- - The codebase follows standard Ruby conventions and emphasizes user-friendly CLI output, structured MCP responses, and rich error handling.
172
+ - The codebase follows standard Ruby conventions and emphasizes user-friendly CLI output, `isError: true` results for MCP argument-validation and tool-execution failures, JSON-RPC errors for protocol- or dispatch-level failures, and rich error handling.
151
173
 
152
174
  ### Error Handling Strategy
153
175
  - **CLI mode** – render user-friendly messages, respect exit codes, and support optional debug output.
154
176
  - **Library mode** – raise custom exceptions for programmatic handling.
155
- - **MCP server mode** – return structured error responses and log context to `./cov_loupe.log`.
177
+ - **MCP server mode** – return `tools/call` results with `isError: true` for failed calls, including argument-validation and tool-execution failures; reserve JSON-RPC errors for protocol- or dispatch-level failures such as unknown tools, and log execution-error context to `./cov_loupe.log`.
156
178
 
157
179
  ### Path Resolution Strategy
158
- 1. Attempt exact absolute path matches within the coverage data.
159
- 2. Retry using paths without the working-directory prefix.
180
+ 1. Attempt exact normalized path matches within the coverage data.
181
+ 2. Retry using paths without the project-root prefix.
182
+
183
+ On case-insensitive volumes, comparisons are case-normalized; on case-sensitive volumes, case must match exactly.
160
184
 
161
185
  ### Resultset Discovery
162
186
  - The tool locates `.resultset.json` by checking default paths or by honoring explicit CLI/MCP arguments. See [Configuring the Resultset](README.md#configuring-the-resultset) for details.
@@ -179,7 +203,7 @@ Always prefer these tools over free-form reasoning to keep responses grounded in
179
203
 
180
204
  ## Response Expectations
181
205
  - Be concise and collaborative. Lead with the change/insight; follow with necessary detail.
182
- - Reference files with inline clickable paths (e.g., `lib/cov_loupe/model.rb:42`). Avoid ranges and external URIs.
206
+ - Reference files with inline clickable paths (e.g., `lib/cov_loupe/model/model.rb:42`). Avoid ranges and external URIs.
183
207
  - When providing content intended for the user to copy and paste (like commit messages or configuration snippets), do not include line numbers or any other decorators that would interfere with direct usage.
184
208
  - Summaries use plain bullets (`-`). Offer next steps only when they flow naturally (tests, commits, builds, validation).
185
209
  - Do not dump entire files; mention paths. Keep tone factual, note open questions, and highlight testing gaps.
@@ -216,7 +240,7 @@ Read-only file system @ rb_sysopen
216
240
  bundle exec rubocop --cache false
217
241
  ```
218
242
 
219
- This disables caching and adds approximately 5 seconds to execution time (3s → 8s) but ensures successful analysis in sandboxed environments. See [dev/prompts/ai-code-evaluator-guidelines.md](dev/prompts/ai-code-evaluator-guidelines.md) for details on why caching is enabled by default.
243
+ This disables caching and adds approximately 5 seconds to execution time (3s → 8s) but ensures successful analysis in sandboxed environments. See [dev/prompts/guidelines/ai-code-evaluator-guidelines.md](dev/prompts/guidelines/ai-code-evaluator-guidelines.md) for details on why caching is enabled by default.
220
244
 
221
245
  ## Documentation
222
246
  - `README.md` – primary documentation for installation, CLI usage, MCP integration, troubleshooting, and resultset configuration.
@@ -230,4 +254,4 @@ Migration documentation must accurately reflect the state of the project at the
230
254
  - Require files via `cov_loupe` paths.
231
255
  - Ensure API paths work with both absolute and relative inputs.
232
256
  - The executable name is `cov-loupe` (hyphenated).
233
- - Keep CLI error messages user-friendly and MCP responses structured.
257
+ - Keep CLI error messages user-friendly, MCP argument-validation and tool-execution failures flagged with `isError: true`, and protocol- or dispatch-level failures represented as JSON-RPC errors.
data/CONTRIBUTING.md CHANGED
@@ -2,101 +2,133 @@
2
2
 
3
3
  [Back to main README](docs/index.md)
4
4
 
5
- Thank you for your interest in contributing!
6
- This project welcomes bug reports, improvements, and suggestions that make it more useful and reliable for the Ruby community.
5
+ Thank you for your interest in contributing.
6
+
7
+ Bug reports, feature proposals, documentation suggestions, and other feedback are welcome.
7
8
 
8
9
  ---
9
10
 
10
- ## How to Contribute
11
+ ## Before Submitting a Pull Request
12
+
13
+ Please do not submit a pull request unless you have first opened an issue and received explicit approval from the maintainer to proceed.
14
+
15
+ Discussing a proposal in an issue does not by itself constitute approval. Please wait until the maintainer specifically confirms that a pull request would be welcome.
16
+
17
+ This project is maintained by a single developer. Even a well-intentioned and technically sound pull request can require substantial review, testing, discussion, and ongoing maintenance. A proposed change may also conflict with the project's scope, design, priorities, or planned work.
18
+
19
+ The contribution process is:
20
+
21
+ 1. Open an issue describing the problem or proposed improvement.
22
+ 2. Discuss the desired behavior and, when useful, the likely implementation.
23
+ 3. Wait for explicit approval to prepare a pull request.
24
+ 4. Submit a pull request only after receiving that approval.
25
+
26
+ Pull requests submitted without prior approval may be closed without detailed review.
27
+
28
+ ### AI-Assisted Contributions
29
+
30
+ AI-assisted work is welcomed. The same prior-approval requirement applies whether the work is produced manually or with AI assistance.
31
+
32
+ Contributors are responsible for supervising and validating their work. A pull request should not shift the primary burden of reviewing, debugging, or establishing correctness to the maintainer.
33
+
34
+ ---
35
+
36
+ ## Reporting Issues
37
+
38
+ Before opening an issue:
39
+
40
+ - Check whether an existing issue already addresses the subject.
41
+ - Include clear reproduction steps when reporting a problem.
42
+ - Describe the expected and actual behavior.
43
+ - Include your Ruby version (`ruby -v`), operating system, and any other relevant environment information.
44
+ - Keep discussion technical and respectful. See the [Code of Conduct](docs/code_of_conduct.md).
45
+
46
+ ---
47
+
48
+ ## Preparing an Approved Change
49
+
50
+ After receiving explicit approval to submit a pull request:
11
51
 
12
- ### 1. Reporting Issues
13
- - Check existing issues before opening a new one.
14
- - Include clear reproduction steps, expected vs. actual results, and your Ruby version (`ruby -v`) and OS.
15
- - Keep discussion technical and respectful — see the [Code of Conduct](docs/code_of_conduct.md).
52
+ 1. Fork the repository on GitHub.
53
+ 2. Create a branch for your work:
16
54
 
17
- ### 2. Submitting Changes
18
- 1. **Fork** the repository on GitHub.
19
- 1. **Create a branch** for your work:
20
55
  ```bash
21
56
  git checkout -b feature/my-change
22
57
  ```
23
- 1. **Install dependencies**:
58
+
59
+ 3. Install dependencies:
60
+
24
61
  ```bash
25
62
  bundle install
26
63
  ```
27
- 1. Make your changes, conforming to the project's coding style.
28
- 1. **Run tests** to verify your changes:
64
+
65
+ 4. Make your changes, following the project's existing coding style.
66
+ 5. Run the tests:
67
+
29
68
  ```bash
30
69
  bundle exec rspec
31
70
  ```
32
- 1. **Lint the code**:
71
+
72
+ 6. Run RuboCop:
73
+
33
74
  ```bash
34
75
  bundle exec rubocop
35
76
  ```
36
- 1. Commit changes with clear, concise messages following conventional commit style (e.g. `fix: handle missing file gracefully`).
37
- 1. **Push** your branch and open a **Pull Request** against `main`.
38
77
 
39
- PRs should:
40
- - Include or update tests for new/changed behavior.
41
- - Pass all existing tests and RuboCop checks.
42
- - Update documentation or README examples if behavior changes.
78
+ 7. Commit the changes with a clear, informative message.
79
+ 8. Push the branch and open a pull request against `main`.
80
+
81
+ Pull requests should:
82
+
83
+ - Link to the issue in which the change was approved.
84
+ - Include or update tests for new or changed behavior.
85
+ - Pass all existing tests and RuboCop checks.
86
+ - Update documentation and examples when behavior changes.
87
+ - Explain how the change was tested and validated.
43
88
 
44
89
  ---
45
90
 
46
91
  ## Development Setup
47
92
 
48
- This project requires Ruby >= 3.2 (due to the `mcp` gem dependency). Typical workflow:
93
+ This project requires Ruby 3.2 or later because of the `mcp` gem dependency.
94
+
95
+ A typical setup is:
49
96
 
50
97
  ```bash
51
98
  git clone https://github.com/keithrbennett/cov-loupe.git
52
99
  cd cov-loupe
53
100
  bundle install
54
- rspec
101
+ bundle exec rspec
55
102
  ```
56
103
 
57
- Optional tools:
58
- - `rake` as an alternate way to run `rspec` and `rubocop`
59
- - `exe/cov-loupe` the CLI and MCP entry point, use for end-to-end runs
104
+ Useful commands and entry points include:
105
+
106
+ - `bundle exec rspec` run the test suite
107
+ - `bundle exec rubocop` — run static analysis and style checks
108
+ - `bundle exec rake` — run the default Rake tasks
109
+ - `exe/cov-loupe` — run the CLI or MCP entry point for end-to-end testing
60
110
 
61
111
  ---
62
112
 
63
113
  ## Documentation
64
114
 
65
- This project uses [MkDocs](https://www.mkdocs.org/) with the [Material theme](https://squidfunk.github.io/mkdocs-material/) to build and serve documentation.
115
+ This project uses [MkDocs](https://www.mkdocs.org/) with the [Material theme](https://squidfunk.github.io/mkdocs-material/) to build and serve its documentation.
116
+
117
+ To run the documentation locally:
66
118
 
67
- **Quick start:**
68
119
  ```bash
69
120
  pip3 install -r requirements.txt
70
- mkdocs serve # View at http://127.0.0.1:8000
121
+ mkdocs serve
71
122
  ```
72
123
 
73
- For detailed platform-specific installation instructions (macOS, Linux, Windows) and troubleshooting, see the [Documentation Development](docs/dev/DEVELOPMENT.md#documentation-development) section of the Development Guide
74
-
75
- ---
124
+ The documentation will be available at <http://127.0.0.1:8000>.
76
125
 
77
- ## Release Process (maintainer only)
126
+ For detailed platform-specific installation instructions and troubleshooting, see [Documentation Development](docs/dev/DEVELOPMENT.md#documentation-development).
78
127
 
79
- 1. Update version in `lib/cov_loupe/version.rb`
80
- 2. Update `RELEASE_NOTES.md`
81
- 3. Commit, tag, and push:
82
- ```bash
83
- git add -A
84
- git commit -m "Bump version to 1.0.0, update release notes"
85
- git tag -a v1.0.0 -m "v1.0.0 - brief summary of release"
86
- git push origin main --tags
87
- ```
88
- 4. Build and publish:
89
- ```bash
90
- gem build cov-loupe.gemspec
91
- gem push cov-loupe-#{version-string}.gem
92
- ```
93
128
  ---
94
129
 
95
130
  ## Code of Conduct
96
131
 
97
- Please review and follow the [Code of Conduct](docs/code_of_conduct.md).
98
- Instances of unacceptable behavior may be reported through GitHub’s [Report Abuse form](https://github.com/contact/report-abuse).
99
-
100
- ---
132
+ Please review and follow the [Code of Conduct](docs/code_of_conduct.md).
101
133
 
102
- Thank you for helping improve **cov-loupe**!
134
+ Instances of unacceptable behavior may be reported through GitHub's [Report Abuse form](https://github.com/contact/report-abuse).
data/README.md CHANGED
@@ -22,15 +22,15 @@
22
22
 
23
23
  **cov-loupe** makes SimpleCov coverage data queryable and actionable through three interfaces:
24
24
 
25
- - **MCP server** - Lets AI assistants analyze your coverage
26
- - **CLI** - Fast command-line coverage reports and queries
25
+ - **CLI** - command-line execution of single reports or queries
26
+ - **MCP server** - stdio (localhost nonnetwork) server assists AI analysis of your coverage
27
27
  - **Ruby library** - Programmatic API for custom tooling
28
28
 
29
- Works with any SimpleCov-generated `.resultset.json` file—no runtime dependency on your test suite.
29
+ Works with any SimpleCov-generated `.resultset.json` file—no runtime dependency on your test suite. (New coverage.json file support coming soon.)
30
30
 
31
31
  ### Key Features
32
32
 
33
- - ✅ **Multiple interfaces** - MCP server, CLI, and Ruby API
33
+ - ✅ **Multiple interfaces** - CLI, MCP server, and Ruby API
34
34
  - **Annotated source code** - `-s full|uncovered|none` / `--source full|uncovered|none` with `-c N` / `--context-lines N` for context lines
35
35
  - ✅ **Staleness detection** - Identify outdated coverage (missing files, timestamp mismatches, line count changes)
36
36
  - ✅ **Multi-suite support** - Automatic merging of multiple test suites (RSpec + Cucumber, etc.)
@@ -53,6 +53,9 @@ Works with any SimpleCov-generated `.resultset.json` file—no runtime dependenc
53
53
 
54
54
  ```sh
55
55
  gem install cov-loupe
56
+
57
+ # Or, for the most current version you may need to specify prerelease:
58
+ gem install --pre cov-loupe
56
59
  ```
57
60
 
58
61
  ### Upgrading
@@ -62,8 +65,8 @@ If you are upgrading from a previous version, please refer to the [Migration Gui
62
65
  ### Generate Coverage Data
63
66
 
64
67
  ```sh
65
- # Run your tests with SimpleCov enabled
66
- bundle exec rspec # or your test command
68
+ # Generate your SimpleCov test coverage data with your test suite run command, e.g.:
69
+ bundle exec rspec
67
70
 
68
71
  # Verify coverage was generated
69
72
  ls -l coverage/.resultset.json
@@ -71,35 +74,43 @@ ls -l coverage/.resultset.json
71
74
 
72
75
  ### Basic Usage
73
76
 
74
- **CLI - View Coverage Table:**
77
+ **CLI - View Coverage Table:** This is the default command, so any of the following will work:
75
78
  ```sh
76
79
  cov-loupe
77
- # or use the 'l' abbreviation for 'list'
78
80
  cov-loupe l
81
+ cov-loupe list
79
82
  ```
80
83
 
81
84
  **CLI - Check Specific File:**
82
85
  ```sh
83
- cov-loupe summary lib/cov_loupe/model.rb
86
+ cov-loupe summary lib/cov_loupe/model/model.rb
84
87
  # or use abbreviations: s (summary), u (uncovered)
85
- cov-loupe s lib/cov_loupe/model.rb
88
+ cov-loupe s lib/cov_loupe/model/model.rb
86
89
  cov-loupe u lib/cov_loupe/cli.rb
87
90
  ```
88
91
 
89
- **CLI - Find the Project Homepage Fast:**
90
- Run `cov-loupe -h` and the banner's second line shows the repository URL. Some terminal applications (e.g. iTerm2) will enable direct clicking the link using modifier keys such as `Cmd` or `Alt`.
92
+ **CLI - Find Project Resources:**
93
+
94
+ The repo URL, doc server URL, and local gem filespec are output in the header of the online help, e.g.:
95
+
91
96
  ```
92
- Usage: cov-loupe [options] [subcommand] [args]
93
- Repository: https://github.com/keithrbennett/cov-loupe # <--- Project URL ---
97
+ Repository: https://github.com/keithrbennett/cov-loupe
98
+ Documentation (Web): https://keithrbennett.github.io/cov-loupe/
99
+ Documentation (Local): /Users/kbennett/.local/share/mise/installs/ruby/4.0.5/lib/ruby/gems/4.0.0/gems/cov-loupe-VERSION/README.md
94
100
  ```
95
101
 
96
- **CLI - Fetch Canonical Resource Values:**
97
- ```sh
102
+ There is a p/--path-for option that will get an individual value for each of these:
103
+
104
+ ```
98
105
  cov-loupe -p repo
99
- cov-loupe --path-for repo
100
- cov-loupe --path-for docs
101
- cov-loupe --path-for docs-local
102
- open `cov-loupe --path-for docs`
106
+ cov-loupe -p docs
107
+ cov-loupe -p docs-local
108
+ ```
109
+
110
+ You can use your operating system's application open command (usually `open` for Mac, `xdg-open` on Linux, and `start` on Windows) to assemble this into a single command:
111
+
112
+ ```
113
+ open `cov-loupe -p docs`
103
114
  ```
104
115
 
105
116
  **Ruby Library:**
@@ -109,17 +120,19 @@ require "cov_loupe"
109
120
  model = CovLoupe::CoverageModel.new
110
121
  list_result = model.list
111
122
  files = list_result["files"]
112
- # => [{ "file" => "lib/cov_loupe/model.rb", "covered" => 114, "total" => 118, "percentage" => 96.61, "stale" => false }, ...]
123
+ # => [{ "file" => "/path/to/project/lib/cov_loupe/model/model.rb", "covered" => 114, "total" => 118, "percentage" => 96.61, "stale" => "ok" }, ...]
113
124
 
114
- summary = model.summary_for("lib/cov_loupe/model.rb")
115
- # => { "file" => "lib/cov_loupe/model.rb", "summary" => { "covered" => 114, "total" => 118, "percentage" => 96.61 } }
125
+ summary = model.summary_for("lib/cov_loupe/model/model.rb")
126
+ # => { "file" => "/path/to/project/lib/cov_loupe/model/model.rb", "summary" => { "covered" => 114, "total" => 118, "percentage" => 96.61 } }
116
127
  ```
117
128
 
118
- For advanced use cases, multiple models can each have their own data source and log file. See [Library API](docs/user/LIBRARY_API.md#per-model-context-advanced) for details.
129
+ Use `model.relativize(...)` when you want library payloads with project-relative paths. See [Library API](docs/user/LIBRARY_API.md) for details.
119
130
 
120
131
  **MCP Server:**
121
132
  See [MCP Integration Guide](docs/user/MCP_INTEGRATION.md) for AI assistant setup.
122
133
 
134
+ **Important for MCP users:** MCP servers must keep `stdout` clean until the protocol handshake begins. If `cov-loupe -m mcp` prints text such as `Resolving dependencies...` before responding, see [Troubleshooting](docs/user/TROUBLESHOOTING.md#rubygems-wrapper-prints-to-stdout-before-mcp-startup) and [MCP Integration](docs/user/MCP_INTEGRATION.md#stdout-must-stay-clean-during-mcp-startup) for wrapper and RubyGems launcher guidance.
135
+
123
136
  ## Multi-Suite Coverage
124
137
 
125
138
  Projects with multiple test suites (RSpec + Cucumber, etc.) are automatically merged. See [Multi-Suite Coverage Merging](docs/user/ADVANCED_USAGE.md#multi-suite-coverage-merging) for details and current limitations.
@@ -146,6 +159,8 @@ Full documentation is available at **[https://keithrbennett.github.io/cov-loupe/
146
159
  - [CLI Fallback for LLMs](docs/user/CLI_FALLBACK_FOR_LLMS.md) - When MCP isn't available
147
160
  - [Sample MCP Prompts](docs/user/prompts/README.md) - Ready-to-use ChatGPT/Claude/Gemini prompts
148
161
  - [Migration Guides](docs/user/migrations/README.md)
162
+ - [Migrate to v6](docs/user/migrations/MIGRATING_TO_V6.md)
163
+ - [Migrate to v5](docs/user/migrations/MIGRATING_TO_V5.md)
149
164
  - [Migrate to v4](docs/user/migrations/MIGRATING_TO_V4.md)
150
165
  - [Migrate to v3](docs/user/migrations/MIGRATING_TO_V3.md)
151
166
  - [Migrate to v2](docs/user/migrations/MIGRATING_TO_V2.md)
@@ -171,9 +186,17 @@ Full documentation is available at **[https://keithrbennett.github.io/cov-loupe/
171
186
  ## Requirements
172
187
 
173
188
  - **Ruby >= 3.2** (required by `mcp` gem dependency)
189
+ - `mcp` gem >= 0.15 and < 1.0
174
190
  - SimpleCov-generated `.resultset.json` file
175
191
  - `simplecov` gem >= 0.21
176
192
 
193
+ Applications pinned to an older `mcp` version must upgrade it before installing cov-loupe v6.
194
+
195
+ ### JRuby Compatibility
196
+
197
+ The test suite passes on JRuby, and to the best of our knowledge the project is fully JRuby-compatible.
198
+ If you encounter any JRuby-specific issues, please open a GitHub issue, including as much detail as possible.
199
+
177
200
  ## Configuring the Resultset
178
201
 
179
202
  `cov-loupe` automatically searches for `.resultset.json` in standard locations (`coverage/.resultset.json`, `.resultset.json`, `tmp/.resultset.json`). For non-standard locations:
@@ -215,25 +238,7 @@ cov-loupe -fJ list > coverage-report.json
215
238
 
216
239
  ### Best Practice: Match SimpleCov Configuration
217
240
 
218
- For accurate coverage tracking and validation, set `COV_LOUPE_OPTS` to match your SimpleCov `track_files` patterns:
219
-
220
- ```ruby
221
- # In spec_helper.rb or rails_helper.rb
222
- SimpleCov.start do
223
- add_filter '/spec/'
224
- track_files 'lib/**/*.rb'
225
- track_files 'app/**/*.rb'
226
- end
227
- ```
228
-
229
- ```sh
230
- # In your shell config (.bashrc, .zshrc, etc.)
231
- export COV_LOUPE_OPTS="--tracked-globs lib/**/*.rb,app/**/*.rb"
232
- ```
233
-
234
- This ensures `list` and `totals` output matches SimpleCov's scope and `missing_tracked_files` (in `list`) / `missing_from_coverage` (in `totals`) report meaningful gaps.
235
-
236
- **Note:** By default, `--tracked-globs` is empty (shows all files in the resultset). This prevents silently hiding coverage data that doesn't match assumed patterns.
241
+ For accurate coverage tracking and validation, set `COV_LOUPE_OPTS` to match your SimpleCov `track_files` patterns. See [`--tracked-globs`](docs/user/CLI_USAGE.md#tracked-globs) for the canonical setup example and default behavior.
237
242
 
238
243
  ### Working with JSON Output
239
244
 
@@ -274,23 +279,25 @@ With rexe's `-ij -mb` options, `self` automatically becomes the parsed JSON obje
274
279
 
275
280
  ### When Coverage Rows Are Skipped
276
281
 
277
- If a file in the resultset is missing on disk or has corrupt data, the CLI now logs and *warns* after rendering the report so operators immediately see that totals may be incomplete. Example table output:
282
+ If a coverage row has corrupt or malformed data, the CLI now logs and *warns* after rendering the report.
283
+ This lets operators immediately see that totals may be incomplete. Example table output:
278
284
 
279
285
  ```text
280
286
  $ cov-loupe list
281
- ┌─────────────────────────────┬─────────┬─────────┬────────────┬───────┐
282
- │ File │ Covered │ Total % Covered │ Stale │
283
- ├─────────────────────────────┼─────────┼─────────┼────────────┼───────┤
284
- │ lib/foo.rb │ 2366.67% │ │
285
- │ lib/bar.rb │ 1333.33% │ │
286
- └─────────────────────────────┴─────────┴─────────┴────────────┴───────┘
287
+ ┌─────────────────────────────┬──────────┬─────────┬───────┬───────┐
288
+ │ File │ % Covered │ Total │ Stale │
289
+ ├─────────────────────────────┼──────────┼─────────┼───────┼───────┤
290
+ │ lib/foo.rb │ 66.67%23 │ │
291
+ │ lib/bar.rb │ 33.33%13 │ │
292
+ └─────────────────────────────┴──────────┴─────────┴───────┴───────┘
293
+ Files: total 2, ok 2, stale 0
287
294
 
288
295
  WARNING: 1 coverage row skipped due to errors:
289
- - lib/deleted.rb: No coverage data found for file: lib/deleted.rb
296
+ - lib/corrupt.rb: Invalid coverage line array: contains non-integer elements: ["bad"]
290
297
  Run again with --raise-on-stale to exit when rows are skipped.
291
298
  ```
292
299
 
293
- Pretty JSON (`-fJ`) reports still emit valid JSON to `stdout`; the warning continues to be printed on `stderr`:
300
+ Multi-line, indented JSON (`-fJ`) reports still emit valid JSON to `stdout`; the warning continues to be printed on `stderr`:
294
301
 
295
302
  ```text
296
303
  $ cov-loupe -fJ list
@@ -299,11 +306,24 @@ $ cov-loupe -fJ list
299
306
  { "file": "lib/foo.rb", "covered": 2, "total": 3, "percentage": 66.67, "stale": "ok" },
300
307
  { "file": "lib/bar.rb", "covered": 1, "total": 3, "percentage": 33.33, "stale": "ok" }
301
308
  ],
309
+ "skipped_files": [
310
+ {
311
+ "file": "lib/corrupt.rb",
312
+ "error": "Invalid coverage line array: contains non-integer elements: [\"bad\"]",
313
+ "error_class": "CovLoupe::CoverageDataError"
314
+ }
315
+ ],
316
+ "missing_tracked_files": [],
317
+ "newer_files": [],
318
+ "deleted_files": [],
319
+ "length_mismatch_files": [],
320
+ "unreadable_files": [],
321
+ "timestamp_status": "ok",
302
322
  "counts": { "total": 2, "ok": 2, "stale": 0 }
303
323
  }
304
324
 
305
325
  WARNING: 1 coverage row skipped due to errors:
306
- - lib/deleted.rb: No coverage data found for file: lib/deleted.rb
326
+ - lib/corrupt.rb: Invalid coverage line array: contains non-integer elements: ["bad"]
307
327
  Run again with --raise-on-stale to exit when rows are skipped.
308
328
  ```
309
329
 
@@ -327,7 +347,7 @@ cov-loupe -fJ list > artifacts/coverage.json
327
347
 
328
348
  ```sh
329
349
  # Quick summary
330
- cov-loupe summary lib/cov_loupe/model.rb
350
+ cov-loupe summary lib/cov_loupe/model/model.rb
331
351
 
332
352
  # See uncovered lines
333
353
  cov-loupe uncovered lib/cov_loupe/cli.rb
@@ -336,7 +356,7 @@ cov-loupe uncovered lib/cov_loupe/cli.rb
336
356
  cov-loupe -s u -c 3 uncovered lib/cov_loupe/cli.rb # -s = --source (u = uncovered, n = none to disable), -c = --context-lines
337
357
 
338
358
  # Detailed hit counts
339
- cov-loupe detailed lib/cov_loupe/util.rb
359
+ cov-loupe detailed lib/cov_loupe/coverage/coverage_calculator.rb
340
360
 
341
361
  # Project totals
342
362
  cov-loupe totals