Module: Evilution::Feedback::SetupWarning
- Defined in:
- lib/evilution/feedback/setup_warning.rb
Overview
Detects “setup misconfiguration” patterns where mutation testing returned a result that is technically valid (score 0.0 with all-errored mutations) but is almost certainly the wrong score because the worker process couldn’t evaluate any mutated source.
Most common cause: MCP runs default to ‘preload: false` to keep the long-lived MCP server clean. Rails / Zeitwerk projects that depend on autoload then fail in every worker with `NameError: uninitialized constant …`. The user sees “0% PASS-but-FAIL” with no obvious hint that they need to pass an explicit `preload: spec/rails_helper.rb` option.
When triggered, this returns a warning string the MCP response can surface alongside the trimmed report — turning a silent wrong score into a loud pointer at the likely fix.
Constant Summary collapse
- ERROR_DOMINANCE_THRESHOLD =
0.8- ERROR_CLASS_CLUSTER_THRESHOLD =
0.8- NAME_ERROR_HINT =
"Most mutations errored with NameError. This usually means autoloaded constants " \ "(Rails / Zeitwerk) weren't available when the mutation re-evaluated the source. " \ "Pass `preload: 'spec/rails_helper.rb'` (or your project's preload entry) so the " \ "MCP server requires it before forking workers."
- LOAD_ERROR_HINT =
"Most mutations errored with LoadError. A `require` in the mutated source path " \ "failed before any test ran. Check that the file's dependencies are reachable from " \ "the MCP server's load path, or pass `preload: '<entrypoint>'` to set them up."
- GENERIC_HINT_TEMPLATE =
"Most mutations errored with %<klass>s (%<count>d / %<total>d). The mutation " \ "score reflects this setup failure, not the test suite. Try the CLI for an " \ "independent reading, or pass `preload: '<path>'` if the failure is autoload-related."
Class Method Summary collapse
Class Method Details
.call(summary) ⇒ Object
25 26 27 28 29 30 31 32 33 34 |
# File 'lib/evilution/feedback/setup_warning.rb', line 25 def call(summary) return nil if summary.nil? return nil unless errors_dominate?(summary) errored = summary.results.select(&:error?) dominant_class = dominant_error_class(errored) return nil unless dominant_class (dominant_class, errored.size, summary.total) end |