evilution 0.17.0 → 0.18.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: adc5fa5ff465865f50dc8faf28531463e2ecf931db42f9c7f43d736d8ae03165
4
- data.tar.gz: 03c3c1ebebd3c3316f453049f7bd9625ac4f4217f94ad27655a86dd80c8b4a1a
3
+ metadata.gz: f7dccdb22393202cfc4e6dc80d4066e88d5c500992b5cdbac0071bfcdf6f3e49
4
+ data.tar.gz: e0b5f72ab55296c76618e1e50d79a54a44e0df3e71b7280782399076e796cc3b
5
5
  SHA512:
6
- metadata.gz: 5f2e6afc1b39ef3befd736860cb1c1d63cb25c53018021202cec45823bca3e804d1df495053845959d423b760fc2c1f894433ca069de11b622ebaa1bb055d543
7
- data.tar.gz: 58802ed6dfee68bfb3dfc3b867444322598e7f2af8b085a5d39ac03c7d99859351bfe62d5643b251203e0009dab28ac5001e918999f1a4432907fec03ecd08c2
6
+ metadata.gz: be52b1f27bde0281efbd40312be56df9f843d25260dc0e0bd615a22c419bd0728df7b0b02f78d0c02378a1710466e9b714b30c8201fa5f7c4a7cd3c14b99fa38
7
+ data.tar.gz: 74265ced2a848088153e22dc5a13d2b283ded3e7b8a8431ffcd364782aceef4461cfeed69abf5f1b39d22d64b26bdc4b708cbf7c6223f902fdeb9bebb572a9bb
@@ -1 +1 @@
1
- 1774807809
1
+ 1775191651
data/.beads/issues.jsonl CHANGED
@@ -65,56 +65,56 @@
65
65
  {"id":"EV-151","title":"Implement pattern matching alternative mutation","description":"Mutate pattern alternatives (in pat1 | pat2). Mutations: remove each alternative individually, swap order. Prism alternation_pattern_node.","status":"in_progress","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:18:23.447046732+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-30T10:45:02.759245169+07:00","dependencies":[{"issue_id":"EV-151","depends_on_id":"EV-141","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
66
66
  {"id":"EV-152","title":"Epic: Type-aware return value mutations","description":"Add mutations that replace return values with type-appropriate empty/zero values: Array→[], Hash→{}, String→\"\", Integer→0, Float→0.0, true→false. Mutant does this extensively; Evilution only does body→nil.","status":"open","priority":2,"issue_type":"feature","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:18:23.546834696+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:18:23.546834696+07:00"}
67
67
  {"id":"EV-153","title":"Epic: Dynamic work allocation for parallel execution","description":"Replace static batch-based work distribution with a shared work queue for dynamic load balancing. Mutant uses a shared queue where workers pull the next mutation as they complete work. Evilution's current static batching can lead to uneven utilization when mutation execution times vary.","status":"open","priority":2,"issue_type":"feature","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:18:26.946371704+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:18:26.946371704+07:00"}
68
- {"id":"EV-154","title":"Implement type-aware return mutations for collection types","description":"When a method body returns an Array literal or Hash literal, also generate mutations returning the empty version ([] or {}). Detect by return value node type.","status":"open","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:18:31.525962391+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:18:31.525962391+07:00","dependencies":[{"issue_id":"EV-154","depends_on_id":"EV-152","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
68
+ {"id":"EV-154","title":"Implement type-aware return mutations for collection types","description":"When a method body returns an Array literal or Hash literal, also generate mutations returning the empty version ([] or {}). Detect by return value node type.","status":"in_progress","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:18:31.525962391+07:00","created_by":"Denis Kiselev","updated_at":"2026-04-02T16:29:31.709023703+07:00","dependencies":[{"issue_id":"EV-154","depends_on_id":"EV-152","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
69
69
  {"id":"EV-155","title":"Implement pattern matching find/array pattern mutations","description":"Mutate find and array patterns: remove individual pattern elements, replace with wildcard (_). Prism find_pattern_node, array_pattern_node.","status":"in_progress","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:18:33.136069529+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-30T10:49:55.941063007+07:00","dependencies":[{"issue_id":"EV-155","depends_on_id":"EV-141","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
70
70
  {"id":"EV-156","title":"Add 'evilution session list' command","description":"Add a CLI subcommand that lists past session results with date, target, mutation count, score, and duration. Support --limit and --since filters.","status":"in_progress","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:18:35.453549801+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-24T09:01:22.324682217+07:00","dependencies":[{"issue_id":"EV-156","depends_on_id":"EV-148","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
71
- {"id":"EV-157","title":"Implement shared work queue with pipe-based IPC","description":"Create a work queue that distributes mutations to worker processes dynamically. Use pipe-based IPC (or DRb) so workers pull the next mutation when ready, rather than receiving a pre-assigned batch.","status":"open","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:18:35.963687077+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:18:35.963687077+07:00","dependencies":[{"issue_id":"EV-157","depends_on_id":"EV-153","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
72
- {"id":"EV-158","title":"Implement type-aware return mutations for scalar types","description":"When a method body returns a String, Integer, or Float literal, also generate mutations returning the zero/empty value ('', 0, 0.0). Detect by return value node type.","status":"open","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:18:43.59763546+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:18:43.59763546+07:00","dependencies":[{"issue_id":"EV-158","depends_on_id":"EV-152","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
71
+ {"id":"EV-157","title":"Implement shared work queue with pipe-based IPC","description":"Create a work queue that distributes mutations to worker processes dynamically. Use pipe-based IPC (or DRb) so workers pull the next mutation when ready, rather than receiving a pre-assigned batch.","status":"in_progress","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:18:35.963687077+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-31T00:46:53.163290251+07:00","dependencies":[{"issue_id":"EV-157","depends_on_id":"EV-153","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
72
+ {"id":"EV-158","title":"Implement type-aware return mutations for scalar types","description":"When a method body returns a String, Integer, or Float literal, also generate mutations returning the zero/empty value ('', 0, 0.0). Detect by return value node type.","status":"in_progress","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:18:43.59763546+07:00","created_by":"Denis Kiselev","updated_at":"2026-04-02T17:28:18.637758436+07:00","dependencies":[{"issue_id":"EV-158","depends_on_id":"EV-152","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
73
73
  {"id":"EV-159","title":"Add RSpec suggestion templates for pattern matching mutations","description":"Add concrete RSpec suggestion templates for survived pattern matching mutations.","status":"in_progress","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:18:45.083995741+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-30T11:33:37.260966394+07:00","dependencies":[{"issue_id":"EV-159","depends_on_id":"EV-141","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
74
74
  {"id":"EV-16","title":"Remove file-discovery logic from Integration::RSpec (GH #33)","description":"Integration::RSpec has detect_test_files, spec_file_candidates, and fallback_spec_dir that guess which specs to run. With precise targeting, agents can pass spec files directly. Simplify or remove this guessing logic, possibly adding a --spec flag.","status":"closed","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-08T19:17:27.268579626+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-09T18:13:46.899195957+07:00","closed_at":"2026-03-09T18:13:46.899195957+07:00","close_reason":"Completed via PR #38 (tracked as EV-17)"}
75
75
  {"id":"EV-160","title":"Add 'evilution session show' command","description":"Add a CLI subcommand that displays the full report for a specific past session, including all survived mutations with diffs.","status":"in_progress","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:18:45.851348485+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-24T12:24:53.120184549+07:00","dependencies":[{"issue_id":"EV-160","depends_on_id":"EV-148","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
76
- {"id":"EV-161","title":"Add work-stealing for idle workers","description":"When a worker's local queue is empty, allow it to pull work from the shared queue immediately rather than waiting. Track per-worker completion rates for monitoring.","status":"open","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:18:47.426119432+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:18:47.426119432+07:00","dependencies":[{"issue_id":"EV-161","depends_on_id":"EV-153","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
77
- {"id":"EV-162","title":"Add RSpec suggestion templates for type-aware return mutations","description":"Add concrete RSpec suggestion templates for survived type-aware return mutations to the SuggestionReporter.","status":"open","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:18:53.50501093+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:18:53.50501093+07:00","dependencies":[{"issue_id":"EV-162","depends_on_id":"EV-152","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
76
+ {"id":"EV-161","title":"Add work-stealing for idle workers","description":"When a worker's local queue is empty, allow it to pull work from the shared queue immediately rather than waiting. Track per-worker completion rates for monitoring.","status":"in_progress","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:18:47.426119432+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-31T11:40:34.186342998+07:00","dependencies":[{"issue_id":"EV-161","depends_on_id":"EV-153","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
77
+ {"id":"EV-162","title":"Add RSpec suggestion templates for type-aware return mutations","description":"Add concrete RSpec suggestion templates for survived type-aware return mutations to the SuggestionReporter.","status":"in_progress","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:18:53.50501093+07:00","created_by":"Denis Kiselev","updated_at":"2026-04-02T21:05:48.502034781+07:00","dependencies":[{"issue_id":"EV-162","depends_on_id":"EV-152","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
78
78
  {"id":"EV-163","title":"Add 'evilution session gc' command","description":"Add a CLI subcommand to garbage-collect old session results. Support --older-than flag (e.g., --older-than 30d). Default to keeping all results.","status":"in_progress","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:18:56.398453511+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-24T13:45:03.75407328+07:00","dependencies":[{"issue_id":"EV-163","depends_on_id":"EV-148","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
79
79
  {"id":"EV-164","title":"Epic: AST pattern language for ignore_patterns","description":"Implement a pattern language for ignore_patterns configuration, similar to Mutant's (e.g., send{selector=log}, send{receiver=send{selector=logger}}). Allows precise, semantic exclusion of mutations on logging, debugging, or infrastructure code without requiring file/line targeting.","status":"open","priority":2,"issue_type":"feature","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:18:56.583664516+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:18:56.583664516+07:00"}
80
- {"id":"EV-165","title":"Update Parallel::Pool to use dynamic queue","description":"Refactor Parallel::Pool to use the new dynamic work queue instead of static batch distribution. Maintain backward compatibility with the existing API (results should be identical, just better distributed).","status":"open","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:18:57.644578151+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:18:57.644578151+07:00","dependencies":[{"issue_id":"EV-165","depends_on_id":"EV-153","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
80
+ {"id":"EV-165","title":"Update Parallel::Pool to use dynamic queue","description":"Refactor Parallel::Pool to use the new dynamic work queue instead of static batch distribution. Maintain backward compatibility with the existing API (results should be identical, just better distributed).","status":"in_progress","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:18:57.644578151+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-31T12:38:19.035204686+07:00","dependencies":[{"issue_id":"EV-165","depends_on_id":"EV-153","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
81
81
  {"id":"EV-166","title":"Design AST pattern language syntax","description":"Design the pattern matching DSL syntax for ignore_patterns. Support at minimum: node type matching, attribute matching (selector, receiver), nested patterns, and wildcards. Document the syntax with examples.","design":"See docs/ast_pattern_syntax.md for full syntax spec. Key decisions: Prism-native node type names, unquoted attribute values, alternatives with |, nested patterns for structural matching, _ and ** wildcards, negation with !, AND across attributes / OR within values. Grammar in EBNF included.","status":"in_progress","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:19:04.486430975+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-30T11:45:10.017653608+07:00","dependencies":[{"issue_id":"EV-166","depends_on_id":"EV-164","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
82
- {"id":"EV-167","title":"Add efficiency metrics to summary output","description":"Add killtime/runtime efficiency percentage and mutations/second rate to the summary output. Mutant reports these. Helps users understand mutation testing overhead and optimize configuration. Calculate: efficiency = (time spent in test execution / total runtime) * 100%, rate = total_mutations / total_seconds.","status":"open","priority":3,"issue_type":"feature","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:19:10.074542778+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:19:10.074542778+07:00"}
83
- {"id":"EV-168","title":"Add parallel execution metrics","description":"Track and report per-worker mutation counts, idle time, and utilization percentage. Include in verbose output to help users tune their --jobs setting.","status":"open","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:19:11.84738201+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:19:11.84738201+07:00","dependencies":[{"issue_id":"EV-168","depends_on_id":"EV-153","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
82
+ {"id":"EV-167","title":"Add efficiency metrics to summary output","description":"Add killtime/runtime efficiency percentage and mutations/second rate to the summary output. Mutant reports these. Helps users understand mutation testing overhead and optimize configuration. Calculate: efficiency = (time spent in test execution / total runtime) * 100%, rate = total_mutations / total_seconds.","status":"in_progress","priority":3,"issue_type":"feature","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:19:10.074542778+07:00","created_by":"Denis Kiselev","updated_at":"2026-04-02T11:59:25.442023723+07:00"}
83
+ {"id":"EV-168","title":"Add parallel execution metrics","description":"Track and report per-worker mutation counts, idle time, and utilization percentage. Include in verbose output to help users tune their --jobs setting.","status":"in_progress","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:19:11.84738201+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-31T16:23:30.539924782+07:00","dependencies":[{"issue_id":"EV-168","depends_on_id":"EV-153","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
84
84
  {"id":"EV-169","title":"Implement AST pattern parser","description":"Parse the pattern language strings into a matcher object that can be evaluated against Prism AST nodes. Support: node type (send, lvar), attribute filters ({selector=log}), nested matchers.","status":"in_progress","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:19:15.548202079+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-30T12:04:08.595004056+07:00","dependencies":[{"issue_id":"EV-169","depends_on_id":"EV-164","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
85
85
  {"id":"EV-17","title":"Remove file-discovery logic from Integration::RSpec","description":"Add --spec flag, simplify RSpec integration by removing detect_test_files heuristics. GH #33","status":"closed","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-09T00:41:29.880486333+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-09T00:43:21.229172712+07:00","closed_at":"2026-03-09T00:43:21.229172712+07:00","close_reason":"Removed ~60 lines of file-discovery logic from Integration::RSpec, added --spec CLI flag, spec_files config, and wired through Runner"}
86
86
  {"id":"EV-170","title":"Environment diagnostic commands","description":"Add diagnostic/inspection commands similar to Mutant's environment tools. Helps users understand what Evilution sees before running a full mutation test.","status":"open","priority":3,"issue_type":"feature","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:19:19.537979519+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:19:19.537979519+07:00"}
87
87
  {"id":"EV-171","title":"Integrate AST pattern filter with mutation generation","description":"Before generating mutations, check if the target AST node matches any ignore_pattern. Skip matching nodes. Report skipped count in summary.","status":"open","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:19:24.909224128+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:19:24.909224128+07:00","dependencies":[{"issue_id":"EV-171","depends_on_id":"EV-164","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
88
88
  {"id":"EV-172","title":"Support # evilution:disable source comments","description":"Allow users to add # evilution:disable comments in source code to skip mutations for specific methods or lines. Mutant supports # mutant:disable for per-method opt-out. Should support: method-level (comment before def), line-level (inline comment), and block-level (disable/enable pairs).","status":"open","priority":2,"issue_type":"feature","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:19:25.957514857+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:19:25.957514857+07:00"}
89
- {"id":"EV-173","title":"Add 'evilution environment show' command","description":"Display the resolved configuration: loaded config file, CLI overrides, effective values for all settings (jobs, target, integration, etc.).","status":"open","priority":3,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:19:30.633766429+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:19:30.633766429+07:00","dependencies":[{"issue_id":"EV-173","depends_on_id":"EV-170","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
90
- {"id":"EV-174","title":"Implement comment-based disable detection","description":"Scan source files for # evilution:disable comments. Support three forms: method-level (comment on line before def), line-level (inline # evilution:disable), and range (# evilution:disable / # evilution:enable pairs). Store disabled ranges per file.","status":"open","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:19:35.174813233+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:19:35.174813233+07:00","dependencies":[{"issue_id":"EV-174","depends_on_id":"EV-172","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
89
+ {"id":"EV-173","title":"Add 'evilution environment show' command","description":"Display the resolved configuration: loaded config file, CLI overrides, effective values for all settings (jobs, target, integration, etc.).","status":"in_progress","priority":3,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:19:30.633766429+07:00","created_by":"Denis Kiselev","updated_at":"2026-04-02T12:35:49.003716036+07:00","dependencies":[{"issue_id":"EV-173","depends_on_id":"EV-170","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
90
+ {"id":"EV-174","title":"Implement comment-based disable detection","description":"Scan source files for # evilution:disable comments. Support three forms: method-level (comment on line before def), line-level (inline # evilution:disable), and range (# evilution:disable / # evilution:enable pairs). Store disabled ranges per file.","status":"in_progress","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:19:35.174813233+07:00","created_by":"Denis Kiselev","updated_at":"2026-04-02T21:38:13.512669264+07:00","dependencies":[{"issue_id":"EV-174","depends_on_id":"EV-172","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
91
91
  {"id":"EV-175","title":"Add ignore_patterns to .evilution.yml config","description":"Add ignore_patterns as a config key in .evilution.yml. Accept an array of pattern strings. Example: ignore_patterns: ['send{selector=log}', 'send{receiver=send{selector=logger}}'].","status":"in_progress","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:19:35.758598835+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-30T13:57:11.398457981+07:00","dependencies":[{"issue_id":"EV-175","depends_on_id":"EV-164","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
92
- {"id":"EV-176","title":"Add 'evilution subjects' command","description":"List all subjects (classes/methods) that would be mutated for the given target. Shows what mutations would be generated without actually running tests.","status":"open","priority":3,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:19:44.530116644+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:19:44.530116644+07:00","dependencies":[{"issue_id":"EV-176","depends_on_id":"EV-170","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
93
- {"id":"EV-177","title":"Filter mutations against disabled ranges","description":"Before generating mutations, check if the target source location falls within a disabled range. Skip mutation generation for disabled locations. Report skipped count in summary.","status":"open","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:19:46.006587202+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:19:46.006587202+07:00","dependencies":[{"issue_id":"EV-177","depends_on_id":"EV-172","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
92
+ {"id":"EV-176","title":"Add 'evilution subjects' command","description":"List all subjects (classes/methods) that would be mutated for the given target. Shows what mutations would be generated without actually running tests.","status":"in_progress","priority":3,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:19:44.530116644+07:00","created_by":"Denis Kiselev","updated_at":"2026-04-02T13:40:26.15472488+07:00","dependencies":[{"issue_id":"EV-176","depends_on_id":"EV-170","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
93
+ {"id":"EV-177","title":"Filter mutations against disabled ranges","description":"Before generating mutations, check if the target source location falls within a disabled range. Skip mutation generation for disabled locations. Report skipped count in summary.","status":"in_progress","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:19:46.006587202+07:00","created_by":"Denis Kiselev","updated_at":"2026-04-02T22:42:25.830104359+07:00","dependencies":[{"issue_id":"EV-177","depends_on_id":"EV-172","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
94
94
  {"id":"EV-178","title":"Epic: Rich subject expression language","description":"Implement a rich expression language for subject matching similar to Mutant's: namespace wildcards (Foo::Bar*), method-type selectors (Foo# for instance, Foo. for class methods), descendant matching (descendants:Foo). Currently Evilution supports method names and file paths but lacks wildcard and type selectors.","status":"open","priority":2,"issue_type":"feature","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:19:48.801608223+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:19:48.801608223+07:00"}
95
- {"id":"EV-179","title":"Add --show-disabled flag to report disabled mutations","description":"Add a CLI flag that reports which mutations were skipped due to disable comments, so users can audit their disable annotations.","status":"open","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:19:56.450400314+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:19:56.450400314+07:00","dependencies":[{"issue_id":"EV-179","depends_on_id":"EV-172","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
95
+ {"id":"EV-179","title":"Add --show-disabled flag to report disabled mutations","description":"Add a CLI flag that reports which mutations were skipped due to disable comments, so users can audit their disable annotations.","status":"in_progress","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:19:56.450400314+07:00","created_by":"Denis Kiselev","updated_at":"2026-04-02T23:19:10.347361729+07:00","dependencies":[{"issue_id":"EV-179","depends_on_id":"EV-172","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
96
96
  {"id":"EV-18","title":"Add method-name targeting (Class#method) (GH #30)","description":"Allow specifying a fully-qualified method name: evilution run Foo::Bar#calculate. Resolve name to file and line range, then mutate only that method. Lower priority since it requires name-to-file resolution which can be ambiguous with reopened classes or metaprogramming. Update README, --help, and CHANGELOG.","status":"closed","priority":3,"issue_type":"feature","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-09T23:49:31.827723147+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-16T10:11:01.311634237+07:00","closed_at":"2026-03-16T10:11:01.311634237+07:00","close_reason":"Already merged and released in v0.4.0"}
97
- {"id":"EV-180","title":"Add 'evilution tests list' command","description":"List all detected test files and test examples that would be run. Useful for verifying test discovery is working correctly.","status":"open","priority":3,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:19:56.667492485+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:19:56.667492485+07:00","dependencies":[{"issue_id":"EV-180","depends_on_id":"EV-170","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
97
+ {"id":"EV-180","title":"Add 'evilution tests list' command","description":"List all detected test files and test examples that would be run. Useful for verifying test discovery is working correctly.","status":"in_progress","priority":3,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:19:56.667492485+07:00","created_by":"Denis Kiselev","updated_at":"2026-04-02T15:56:28.450828915+07:00","dependencies":[{"issue_id":"EV-180","depends_on_id":"EV-170","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
98
98
  {"id":"EV-181","title":"Sorbet type signature awareness for mutations","description":"Detect and unwrap Sorbet type signatures (sig { ... }) before mutation. Mutant automatically skips mutations inside sig blocks and handles typed codebases without special configuration. Evilution should skip sig blocks to avoid generating useless mutations on type annotations.","status":"open","priority":3,"issue_type":"feature","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:20:07.254888519+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:20:07.254888519+07:00"}
99
- {"id":"EV-182","title":"Add 'evilution util mutation' preview command","description":"Add a utility command that previews mutations for a code snippet without running tests: evilution util mutation -e 'def foo; x + y; end'. Shows all mutations that would be generated. Mutant has this. Useful for understanding operator behavior and debugging mutation generation.","status":"open","priority":3,"issue_type":"feature","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:20:08.026842032+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:20:08.026842032+07:00"}
99
+ {"id":"EV-182","title":"Add 'evilution util mutation' preview command","description":"Add a utility command that previews mutations for a code snippet without running tests: evilution util mutation -e 'def foo; x + y; end'. Shows all mutations that would be generated. Mutant has this. Useful for understanding operator behavior and debugging mutation generation.","status":"in_progress","priority":3,"issue_type":"feature","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:20:08.026842032+07:00","created_by":"Denis Kiselev","updated_at":"2026-04-03T09:18:13.193559394+07:00"}
100
100
  {"id":"EV-183","title":"Implement namespace wildcard matching (Foo::Bar*)","description":"Support wildcard patterns in --target that match all classes/modules under a namespace. E.g., Foo::Bar* matches Foo::Bar, Foo::BarBaz, Foo::Bar::Qux.","status":"in_progress","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:20:09.50500441+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-28T23:30:28.435713182+07:00","dependencies":[{"issue_id":"EV-183","depends_on_id":"EV-178","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
101
- {"id":"EV-184","title":"Detect Sorbet sig blocks in source","description":"Identify Sorbet sig { ... } blocks (send nodes with receiver T and method sig) in source files. Store their byte ranges for exclusion.","status":"open","priority":3,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:20:18.062074984+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:20:18.062074984+07:00","dependencies":[{"issue_id":"EV-184","depends_on_id":"EV-181","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
101
+ {"id":"EV-184","title":"Detect Sorbet sig blocks in source","description":"Identify Sorbet sig { ... } blocks (send nodes with receiver T and method sig) in source files. Store their byte ranges for exclusion.","status":"in_progress","priority":3,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:20:18.062074984+07:00","created_by":"Denis Kiselev","updated_at":"2026-04-03T00:05:05.041117033+07:00","dependencies":[{"issue_id":"EV-184","depends_on_id":"EV-181","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
102
102
  {"id":"EV-185","title":"Cross-run comparison and diffing","description":"Add ability to diff between two session results to show mutation coverage changes over time. Specifically requested in comparison testing feedback. Show: new mutations, removed mutations, changed results (killed→survived or vice versa).","status":"open","priority":3,"issue_type":"feature","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:20:18.414861607+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:20:18.414861607+07:00"}
103
103
  {"id":"EV-186","title":"Implement method-type selectors (Foo#, Foo.)","description":"Support targeting all instance methods of a class (Foo#) or all class methods (Foo.) without specifying individual method names.","status":"in_progress","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:20:21.178494367+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-28T23:02:33.070915314+07:00","dependencies":[{"issue_id":"EV-186","depends_on_id":"EV-178","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
104
- {"id":"EV-187","title":"Implement session result diffing engine","description":"Create a diff engine that compares two session result JSON files and produces: new mutations (in B but not A), removed mutations (in A but not B), status changes (killed→survived, survived→killed), and score delta.","status":"open","priority":3,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:20:26.707985667+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:20:26.707985667+07:00","dependencies":[{"issue_id":"EV-187","depends_on_id":"EV-185","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
105
- {"id":"EV-188","title":"Skip mutation generation inside sig blocks","description":"Filter out any mutation whose source location falls within a Sorbet sig block. Report skipped count separately in verbose output.","status":"open","priority":3,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:20:28.716852636+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:20:28.716852636+07:00","dependencies":[{"issue_id":"EV-188","depends_on_id":"EV-181","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
104
+ {"id":"EV-187","title":"Implement session result diffing engine","description":"Create a diff engine that compares two session result JSON files and produces: new mutations (in B but not A), removed mutations (in A but not B), status changes (killed→survived, survived→killed), and score delta.","status":"in_progress","priority":3,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:20:26.707985667+07:00","created_by":"Denis Kiselev","updated_at":"2026-04-03T00:35:17.712475445+07:00","dependencies":[{"issue_id":"EV-187","depends_on_id":"EV-185","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
105
+ {"id":"EV-188","title":"Skip mutation generation inside sig blocks","description":"Filter out any mutation whose source location falls within a Sorbet sig block. Report skipped count separately in verbose output.","status":"in_progress","priority":3,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:20:28.716852636+07:00","created_by":"Denis Kiselev","updated_at":"2026-04-03T00:21:25.655821536+07:00","dependencies":[{"issue_id":"EV-188","depends_on_id":"EV-181","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
106
106
  {"id":"EV-189","title":"Implement descendant matching (descendants:Foo)","description":"Support descendants:Foo syntax to match Foo and all classes that inherit from Foo. Requires scanning the codebase for class inheritance.","status":"in_progress","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:20:30.943382606+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-28T22:39:55.192457857+07:00","dependencies":[{"issue_id":"EV-189","depends_on_id":"EV-178","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
107
107
  {"id":"EV-19","title":"Add method-name targeting (--target flag)","description":"Users can target a specific method for mutation testing via --target METHOD flag. Matches against Subject.name.","status":"closed","priority":2,"issue_type":"feature","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-10T00:09:57.091870734+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-10T00:10:02.637447023+07:00","closed_at":"2026-03-10T00:10:02.637447023+07:00","close_reason":"Implemented --target flag in CLI, Config.target? predicate, Runner.filter_by_target, README docs, and specs"}
108
- {"id":"EV-190","title":"Add 'evilution session diff' CLI command","description":"Add CLI subcommand: evilution session diff <session-a> <session-b>. Output the comparison in a readable format with color-coded changes.","status":"open","priority":3,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:20:38.753251207+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:20:38.753251207+07:00","dependencies":[{"issue_id":"EV-190","depends_on_id":"EV-185","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
108
+ {"id":"EV-190","title":"Add 'evilution session diff' CLI command","description":"Add CLI subcommand: evilution session diff <session-a> <session-b>. Output the comparison in a readable format with color-coded changes.","status":"in_progress","priority":3,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:20:38.753251207+07:00","created_by":"Denis Kiselev","updated_at":"2026-04-03T08:33:44.437112284+07:00","dependencies":[{"issue_id":"EV-190","depends_on_id":"EV-185","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
109
109
  {"id":"EV-191","title":"Verify and ensure Ruby 4.0 compatibility","description":"Test Evilution against Ruby 4.0 (when available) and fix any compatibility issues. Mutant already supports Ruby 4.0. Key areas: Prism parser compatibility with new syntax, frozen string literals by default, any deprecated API usage.","status":"closed","priority":3,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:20:39.786215101+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T17:15:21.121499298+07:00","closed_at":"2026-03-23T17:15:21.121499298+07:00","close_reason":"No action needed — Ruby 4.0 already supported and tested in CI (matrix includes 4.0.2). The gap analysis claim of 'not yet tested' was outdated."}
110
110
  {"id":"EV-192","title":"Implement source glob matching (source:lib/**/*.rb)","description":"Support source: prefix for file glob patterns in --target, matching mutant's source:lib/**/*.rb syntax.","status":"in_progress","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:20:41.326339048+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-28T22:21:33.599617614+07:00","dependencies":[{"issue_id":"EV-192","depends_on_id":"EV-178","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
111
- {"id":"EV-193","title":"Add cross-run comparison to HTML report","description":"Extend the HTML reporter to optionally include comparison data from a baseline session, highlighting regressions (newly survived mutations) in red.","status":"open","priority":3,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:20:49.187589087+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:20:49.187589087+07:00","dependencies":[{"issue_id":"EV-193","depends_on_id":"EV-185","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
111
+ {"id":"EV-193","title":"Add cross-run comparison to HTML report","description":"Extend the HTML reporter to optionally include comparison data from a baseline session, highlighting regressions (newly survived mutations) in red.","status":"in_progress","priority":3,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:20:49.187589087+07:00","created_by":"Denis Kiselev","updated_at":"2026-04-03T08:59:14.618812927+07:00","dependencies":[{"issue_id":"EV-193","depends_on_id":"EV-185","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
112
112
  {"id":"EV-194","title":"Epic: Class and module definition mutations","description":"Add mutations for class definitions, module definitions, inheritance changes, and singleton classes. Mutant mutates these; they test structural code organization.","status":"open","priority":3,"issue_type":"feature","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:20:53.918581132+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:20:53.918581132+07:00"}
113
113
  {"id":"EV-195","title":"Implement superclass removal mutation","description":"Mutate class Foo < Bar to class Foo (remove inheritance). Tests whether the superclass is actually needed. Prism class_node with superclass.","status":"in_progress","priority":3,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:21:02.559769802+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-29T00:16:40.526192467+07:00","dependencies":[{"issue_id":"EV-195","depends_on_id":"EV-194","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
114
- {"id":"EV-196","title":"Show code diffs for survived mutations in text output","description":"Show the exact code diff (original vs mutated) for each survived mutation in the text reporter output, similar to how Mutant displays survived mutants. Currently Evilution shows the mutation description but not the visual diff. This was specifically requested in comparison testing feedback as it helps users quickly understand what test is missing.","status":"open","priority":2,"issue_type":"feature","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:21:02.574157928+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:21:02.574157928+07:00"}
114
+ {"id":"EV-196","title":"Show code diffs for survived mutations in text output","description":"Show the exact code diff (original vs mutated) for each survived mutation in the text reporter output, similar to how Mutant displays survived mutants. Currently Evilution shows the mutation description but not the visual diff. This was specifically requested in comparison testing feedback as it helps users quickly understand what test is missing.","status":"in_progress","priority":2,"issue_type":"feature","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:21:02.574157928+07:00","created_by":"Denis Kiselev","updated_at":"2026-04-03T11:00:52.543373742+07:00"}
115
115
  {"id":"EV-197","title":"Implement module include/extend removal","description":"Mutate include/extend/prepend statements: remove each one individually. Tests whether the mixin is actually used.","status":"in_progress","priority":3,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:21:13.978482592+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-28T23:57:39.685072781+07:00","dependencies":[{"issue_id":"EV-197","depends_on_id":"EV-194","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
116
116
  {"id":"EV-198","title":"Add RSpec suggestion templates for class/module mutations","description":"Add concrete suggestion templates for survived class/module mutations.","status":"in_progress","priority":3,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:21:23.284834592+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-28T23:47:56.899533924+07:00","dependencies":[{"issue_id":"EV-198","depends_on_id":"EV-194","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
117
- {"id":"EV-199","title":"Implement keyword argument mutations","description":"Add mutations for keyword arguments and optional keyword argument defaults. Mutations: remove keyword arg default value, swap keyword arg with positional, remove optional keyword. Prism keyword_hash_node, keyword_rest_parameter_node.","status":"open","priority":3,"issue_type":"feature","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:21:33.74262984+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:21:33.74262984+07:00"}
117
+ {"id":"EV-199","title":"Implement keyword argument mutations","description":"Add mutations for keyword arguments and optional keyword argument defaults. Mutations: remove keyword arg default value, swap keyword arg with positional, remove optional keyword. Prism keyword_hash_node, keyword_rest_parameter_node.","status":"in_progress","priority":3,"issue_type":"feature","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:21:33.74262984+07:00","created_by":"Denis Kiselev","updated_at":"2026-04-03T11:08:55.837650562+07:00"}
118
118
  {"id":"EV-2","title":"Phase 1: Foundation — End-to-End Single Mutation","description":"Build the core pipeline: parse Ruby with Prism, generate mutations, fork-based isolation, RSpec integration, JSON reporting. Milestone: Runner.new(files: ['lib/user.rb']).call produces JSON output.","status":"closed","priority":2,"issue_type":"epic","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-02T00:04:58.737191467+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-02T11:02:00.342745637+07:00","closed_at":"2026-03-02T11:02:00.342745637+07:00","close_reason":"Phase 1 Foundation complete: Config, AST::Parser, Subject, SourceSurgeon, Mutation, Mutator::Base+Registry, ComparisonReplacement, Isolation::Fork, Integration::RSpec, Result objects, Reporter::JSON, Runner — all 13 tasks done"}
119
119
  {"id":"EV-2.1","title":"Implement Evilution::Config","description":"Immutable configuration value object. Fields: target_files, jobs (default: Etc.nprocessors), timeout (default: 10s), format (:json/:text), diff_base (nil), min_score (0.0), integration (:rspec), config_file path. Merge from defaults + YAML + CLI flags. File: lib/evilution/config.rb + spec.","status":"closed","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-02T00:05:50.275297792+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-02T10:43:14.688620834+07:00","closed_at":"2026-03-02T10:43:14.688620834+07:00","close_reason":"Closed","dependencies":[{"issue_id":"EV-2.1","depends_on_id":"EV-2","type":"parent-child","created_at":"0001-01-01T00:00:00Z"}]}
120
120
  {"id":"EV-2.10","title":"Implement Evilution::Integration::Base and RSpec adapter","description":"Base: abstract adapter with interface #call(test_files) -> {passed: bool, example_count: int, failure_count: int}. RSpec: programmatic runner using RSpec::Core::Runner.run with StringIO for capture. Auto-detects spec/ directory. Files: lib/evilution/integration/base.rb, lib/evilution/integration/rspec.rb + specs.","status":"closed","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-02T00:05:51.246990324+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-02T10:58:18.324768622+07:00","closed_at":"2026-03-02T10:58:18.324768622+07:00","close_reason":"Integration::Base and Integration::RSpec implemented with 8 passing specs","dependencies":[{"issue_id":"EV-2.10","depends_on_id":"EV-2","type":"parent-child","created_at":"0001-01-01T00:00:00Z"}]}
@@ -130,9 +130,9 @@
130
130
  {"id":"EV-2.8","title":"Implement Evilution::Result::MutationResult and Summary","description":"MutationResult: value object with fields: mutation, status (:killed/:survived/:timeout/:error), duration, killing_test (optional). Summary: aggregates MutationResult array into total/killed/survived/timed_out/errors/score/duration. Files: lib/evilution/result/mutation_result.rb, lib/evilution/result/summary.rb + specs.","status":"closed","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-02T00:05:51.022249568+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-02T10:51:08.482621898+07:00","closed_at":"2026-03-02T10:51:08.482621898+07:00","close_reason":"Closed","dependencies":[{"issue_id":"EV-2.8","depends_on_id":"EV-2","type":"parent-child","created_at":"0001-01-01T00:00:00Z"}]}
131
131
  {"id":"EV-2.9","title":"Implement Evilution::Isolation::Fork","description":"Fork-based process isolation. Method: run(mutation, test_command, timeout:) -> MutationResult. Flow: create pipe, fork child, child applies mutation via eval, child runs test command, marshal result back via pipe, parent reads with IO.select timeout, SIGKILL on deadline. File: lib/evilution/isolation/fork.rb + spec.","status":"closed","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-02T00:05:51.142167275+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-02T10:54:08.819310594+07:00","closed_at":"2026-03-02T10:54:08.819310594+07:00","close_reason":"Fork isolation implemented with 6 passing specs","dependencies":[{"issue_id":"EV-2.9","depends_on_id":"EV-2","type":"parent-child","created_at":"0001-01-01T00:00:00Z"},{"issue_id":"EV-2.9","depends_on_id":"EV-2.8","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
132
132
  {"id":"EV-20","title":"Deprecate coverage filtering","description":"With line-range and method-name targeting, coverage collection adds overhead for little benefit. Deprecate --no-coverage flag, coverage config key, and remove coverage logic from runner.","status":"closed","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-10T00:30:58.837659684+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-10T00:33:06.453669976+07:00","closed_at":"2026-03-10T00:33:06.453669976+07:00","close_reason":"Deprecated coverage filtering: CLI warns on --no-coverage, config warns on coverage key, runner no longer uses coverage logic"}
133
- {"id":"EV-200","title":"Implement multiple assignment (masgn) mutations","description":"Add mutations for destructuring/parallel assignment (a, b = 1, 2). Mutations: remove individual assignment targets, swap assignment order, reduce to single assignment. Prism multi_write_node.","status":"open","priority":3,"issue_type":"feature","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:21:44.259585319+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:21:44.259585319+07:00"}
134
- {"id":"EV-201","title":"Implement yield statement mutations","description":"Add mutations for yield statements. Mutations: remove yield, remove yield arguments, replace yield value with nil. Prism yield_node.","status":"open","priority":3,"issue_type":"feature","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:21:53.437749245+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:21:53.437749245+07:00"}
135
- {"id":"EV-202","title":"Implement splat operator mutations","description":"Add mutations for splat (*) and double-splat (**) operators. Mutations: remove splat (pass array directly), remove double-splat (pass hash directly). Prism splat_node, assoc_splat_node.","status":"open","priority":3,"issue_type":"feature","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:22:01.958187896+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:22:01.958187896+07:00"}
133
+ {"id":"EV-200","title":"Implement multiple assignment (masgn) mutations","description":"Add mutations for destructuring/parallel assignment (a, b = 1, 2). Mutations: remove individual assignment targets, swap assignment order, reduce to single assignment. Prism multi_write_node.","status":"in_progress","priority":3,"issue_type":"feature","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:21:44.259585319+07:00","created_by":"Denis Kiselev","updated_at":"2026-04-03T11:36:39.551815499+07:00"}
134
+ {"id":"EV-201","title":"Implement yield statement mutations","description":"Add mutations for yield statements. Mutations: remove yield, remove yield arguments, replace yield value with nil. Prism yield_node.","status":"in_progress","priority":3,"issue_type":"feature","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:21:53.437749245+07:00","created_by":"Denis Kiselev","updated_at":"2026-04-03T11:47:36.054086735+07:00"}
135
+ {"id":"EV-202","title":"Implement splat operator mutations","description":"Add mutations for splat (*) and double-splat (**) operators. Mutations: remove splat (pass array directly), remove double-splat (pass hash directly). Prism splat_node, assoc_splat_node.","status":"in_progress","priority":3,"issue_type":"feature","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:22:01.958187896+07:00","created_by":"Denis Kiselev","updated_at":"2026-04-03T12:15:56.890122869+07:00"}
136
136
  {"id":"EV-203","title":"Epic: Extended equivalent mutation detection","description":"Extend equivalent mutation detection with more heuristics and manual marking support. Evilution's equivalent detection is already praised in feedback; extending it further strengthens a competitive advantage.","status":"open","priority":3,"issue_type":"feature","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:22:11.400012571+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:22:11.400012571+07:00"}
137
137
  {"id":"EV-204","title":"Add more automatic equivalence heuristics","description":"Add new equivalence detection strategies: frozen string mutations (frozen strings are immutable, mutation is equivalent), private method rename (if only called internally with same signature), constant folding equivalences.","status":"in_progress","priority":3,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:22:20.07787144+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-28T21:21:19.35465527+07:00","dependencies":[{"issue_id":"EV-204","depends_on_id":"EV-203","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
138
138
  {"id":"EV-205","title":"Support # evilution:equivalent manual marking","description":"Allow users to mark specific mutations as equivalent using source comments: # evilution:equivalent. These should be excluded from the score denominator like auto-detected equivalents.","status":"in_progress","priority":3,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:22:31.543822152+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-28T22:08:20.967272294+07:00","dependencies":[{"issue_id":"EV-205","depends_on_id":"EV-203","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
@@ -141,9 +141,9 @@
141
141
  {"id":"EV-208","title":"Add cross-run diff to MCP server","description":"Add MCP tool for comparing two sessions and returning the diff. Enables AI agents to detect regressions.","status":"in_progress","priority":3,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:23:00.558002099+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-28T10:58:31.301603302+07:00","dependencies":[{"issue_id":"EV-208","depends_on_id":"EV-206","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
142
142
  {"id":"EV-209","title":"Add streaming test suggestions via MCP","description":"Stream test suggestions for survived mutations via MCP as they are generated, rather than waiting for the full run to complete.","status":"in_progress","priority":3,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:23:10.316219498+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-28T11:10:26.677490317+07:00","dependencies":[{"issue_id":"EV-209","depends_on_id":"EV-206","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
143
143
  {"id":"EV-21","title":"Epic: Speed & Performance","description":"Reduce mutation testing wall-clock time for fast agent feedback loops. Includes fail-fast, parallel execution, and per-mutation spec targeting.","status":"closed","priority":1,"issue_type":"feature","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-10T06:17:26.608316104+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-16T14:49:23.063583958+07:00","closed_at":"2026-03-16T14:49:23.063583958+07:00","close_reason":"All children complete: fail-fast, per-mutation spec targeting","dependencies":[{"issue_id":"EV-21","depends_on_id":"EV-22","type":"blocks","created_at":"0001-01-01T00:00:00Z"},{"issue_id":"EV-21","depends_on_id":"EV-23","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
144
- {"id":"EV-210","title":"Implement defined? check mutations","description":"Add mutation for defined?(expr) → true. Tests whether the defined? check is actually needed. Prism defined_node.","status":"open","priority":4,"issue_type":"feature","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:23:22.128405637+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:23:22.128405637+07:00"}
145
- {"id":"EV-211","title":"Implement regex capture reference (, ) mutations","description":"Add mutations for numbered regex capture references ($1, $2, etc.). Mutations: swap capture numbers ($1↔$2), replace with nil. Prism numbered_reference_read_node.","status":"open","priority":4,"issue_type":"feature","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:23:30.659728763+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:23:30.659728763+07:00"}
146
- {"id":"EV-212","title":"Implement self reference mutations","description":"Add mutations for self references. Mutations: remove self where it's used as an explicit receiver (self.foo → foo). Prism self_node.","status":"open","priority":4,"issue_type":"feature","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:23:42.173027795+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:23:42.173027795+07:00"}
144
+ {"id":"EV-210","title":"Implement defined? check mutations","description":"Add mutation for defined?(expr) → true. Tests whether the defined? check is actually needed. Prism defined_node.","status":"in_progress","priority":4,"issue_type":"feature","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:23:22.128405637+07:00","created_by":"Denis Kiselev","updated_at":"2026-04-03T12:41:21.72963442+07:00"}
145
+ {"id":"EV-211","title":"Implement regex capture reference (, ) mutations","description":"Add mutations for numbered regex capture references ($1, $2, etc.). Mutations: swap capture numbers ($1↔$2), replace with nil. Prism numbered_reference_read_node.","status":"in_progress","priority":4,"issue_type":"feature","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:23:30.659728763+07:00","created_by":"Denis Kiselev","updated_at":"2026-04-03T12:58:30.17449728+07:00"}
146
+ {"id":"EV-212","title":"Implement self reference mutations","description":"Add mutations for self references. Mutations: remove self where it's used as an explicit receiver (self.foo → foo). Prism self_node.","status":"closed","priority":4,"issue_type":"feature","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:23:42.173027795+07:00","created_by":"Denis Kiselev","updated_at":"2026-04-02T11:58:04.342971748+07:00","closed_at":"2026-04-02T11:58:04.342971748+07:00","close_reason":"Already implemented by ReceiverReplacement operator (self.foo → foo)"}
147
147
  {"id":"EV-213","title":"Critical: SourceSurgeon crashes on multi-byte UTF-8 source files","description":"SourceSurgeon.apply uses String#[]= with Prism byte offsets, but Ruby String#[]= interprets indices as character offsets for UTF-8 strings. This causes IndexError on files containing multi-byte characters (e.g. Cyrillic, CJK, emoji). Fix: use source.b to force ASCII-8BIT before byte-offset operations, or use byteslice-based replacement. Reported by end user on 2026-03-29 against v0.16.0.","status":"open","priority":0,"issue_type":"bug","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-29T23:19:47.803570297+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-29T23:19:47.803570297+07:00"}
148
148
  {"id":"EV-22","title":"Add --fail-fast flag with survivor threshold","description":"Add --fail-fast [N] CLI flag and fail_fast config option to stop mutation testing after N surviving mutants (default N=1 when flag given without value). Agents fix gaps iteratively, so discovering all survivors upfront is wasted work. A threshold gives control over the speed/thoroughness tradeoff: --fail-fast 1 for quick checks, --fail-fast 5 for CI gates, omit for full scans. Runner#call should stop running mutations and return a partial Summary once the threshold is reached. JSON output should include a 'truncated: true' field when fail-fast triggered.","status":"closed","priority":2,"issue_type":"feature","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-10T06:17:28.018733235+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-16T10:11:01.311500554+07:00","closed_at":"2026-03-16T10:11:01.311500554+07:00","close_reason":"Already merged and released in v0.4.0"}
149
149
  {"id":"EV-23","title":"Per-mutation spec targeting","description":"Instead of running the full spec suite for every mutation, map each mutated source file to its relevant spec file(s) using convention-based resolution (e.g. lib/foo/bar.rb -> spec/foo/bar_spec.rb) and only run those. This dramatically reduces per-mutation test time. Depends on convention-based spec file resolution being implemented first.","status":"closed","priority":2,"issue_type":"feature","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-10T06:17:28.98620973+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-16T14:49:13.616876819+07:00","closed_at":"2026-03-16T14:49:13.616876819+07:00","close_reason":"Fixed and merged","dependencies":[{"issue_id":"EV-23","depends_on_id":"EV-34","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
data/CHANGELOG.md CHANGED
@@ -1,5 +1,36 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.18.0] - 2026-04-03
4
+
5
+ ### Added
6
+
7
+ - **Disable comments** — `# evilution:disable` comments to suppress mutations on specific lines, methods, or regions; inline disable for single lines, standalone disable before `def` for entire methods, range disable/enable pairs for arbitrary regions; `--show-disabled` flag reports skipped mutations in CLI, JSON, and HTML output (#321, #323, #325)
8
+ - **Sorbet `sig` filtering** — automatically detects and excludes mutations inside Sorbet `sig { ... }` blocks; cached per file for performance (#330, #334)
9
+ - **Session diff engine** — `Evilution::Session::Diff` compares two saved sessions, reporting fixed mutations, new survivors, persistent survivors, and score delta; identity matching by `[operator, file, line, subject]` (#333)
10
+ - **`session diff` CLI command** — `evilution session diff <base> <head>` with color-coded text output (green=fixed, red=new survivors, yellow=persistent) and `--format json` support (#336)
11
+ - **HTML report baseline comparison** — `--baseline-session PATH` overlays a saved session on the HTML report, highlighting regressions with badges and showing score delta (#339)
12
+ - **`util mutation` CLI command** — `evilution util mutation [-e CODE | FILE]` previews all mutations for a source file or inline Ruby snippet; supports `--format json` (#328)
13
+ - **`subjects` CLI command** — `evilution subjects [files...]` lists all mutation subjects (methods) with file locations and mutation counts; supports `--stdin` (#322)
14
+ - **`tests list` CLI command** — `evilution tests list [files...]` lists spec files mapped to source files via `SpecResolver` (#326)
15
+ - **`environment show` CLI command** — `evilution environment show` displays runtime environment: version, Ruby version, config path, and all active settings (#319)
16
+ - **Type-aware return mutation operators** — `CollectionReturn` replaces collection return values with type-aware alternatives (`[]`, `{}`); `ScalarReturn` replaces scalar return values with type-aware alternatives (`0`, `""`, `nil`) (#300, #304)
17
+ - **Keyword argument mutations** — `KeywordArgument` operator removes default values, removes optional keywords entirely, and removes `**kwargs` rest parameters (#345)
18
+ - **Multiple assignment mutations** — `MultipleAssignment` operator removes individual assignment targets and swaps 2-element order (#346)
19
+ - **Yield statement mutations** — `YieldStatement` operator removes yield, removes yield arguments, and replaces yield value with `nil` (#347)
20
+ - **Splat operator mutations** — `SplatOperator` operator removes `*` (splat) and `**` (double-splat) from method calls and array literals (#348)
21
+ - **`defined?` check mutations** — `DefinedCheck` operator replaces `defined?(expr)` with `true` (#356)
22
+ - **Regex capture reference mutations** — `RegexCapture` operator swaps numbered capture references (`$1`↔`$2`) and replaces with `nil` (#357)
23
+ - **Suggestion templates** — concrete RSpec suggestions for `collection_return` and `scalar_return` operators (#308)
24
+ - **Efficiency metrics** — summary output includes `efficiency` (killtime/wall-clock ratio), `mutations_per_second` throughput, and `killtime` aggregate; reported in CLI, JSON, and HTML (#313)
25
+ - **Parallel execution metrics** — worker statistics tracking with `busy_time`, `wall_time`, `idle_time`, and `utilization` per worker (#314)
26
+ - **Demand-driven work distribution** — `Parallel::Pool` uses pipe-based shared work queue with demand-driven dispatch and configurable prefetch; replaces batch-based distribution (#303, #307, #311)
27
+
28
+ ### Changed
29
+
30
+ - **Operator count** — 60 operators (up from 52), with new return-type, keyword, assignment, yield, splat, defined?, and regex capture operators
31
+ - **CLI reporter** — survived mutations now include subject name and code diffs (#341)
32
+ - **Dependency updates** — Ruby 3.3.10 → 3.3.11 in CI (#447), ruby/setup-ruby 1.295.0 → 1.299.0, rubygems/release-gem 1.1.4 → 1.2.0
33
+
3
34
  ## [0.17.0] - 2026-03-30
4
35
 
5
36
  ### Added
data/README.md CHANGED
@@ -29,27 +29,42 @@ evilution [command] [options] [files...]
29
29
 
30
30
  ### Commands
31
31
 
32
- | Command | Description | Default |
33
- |-----------|------------------------------------------|---------|
34
- | `run` | Execute mutation testing against files | Yes |
35
- | `init` | Generate `.evilution.yml` config file | |
36
- | `version` | Print version string | |
32
+ | Command | Description | Default |
33
+ |----------------------|----------------------------------------------------|---------|
34
+ | `run` | Execute mutation testing against files | Yes |
35
+ | `init` | Generate `.evilution.yml` config file | |
36
+ | `version` | Print version string | |
37
+ | `subjects [files]` | List mutation subjects with locations and counts | |
38
+ | `tests list [files]` | List spec files mapped to source files | |
39
+ | `session list` | List saved session results | |
40
+ | `session show FILE` | Display detailed session results | |
41
+ | `session diff A B` | Compare two sessions (fixed/new/persistent) | |
42
+ | `session gc --older-than D` | Garbage-collect sessions older than D (e.g. 30d) | |
43
+ | `util mutation` | Preview mutations for a file or inline code | |
44
+ | `environment show` | Display runtime environment and settings | |
37
45
 
38
46
  ### Options (for `run` command)
39
47
 
40
- | Flag | Type | Default | Description |
41
- |-------------------------|---------|--------------|---------------------------------------------------|
42
- | `-t`, `--timeout N` | Integer | 10 | Per-mutation timeout in seconds. |
43
- | `-f`, `--format FORMAT` | String | `text` | Output format: `text` or `json`. |
44
- | `--target METHOD` | String | _(none)_ | Only mutate the named method (e.g. `Foo::Bar#calculate`). |
45
- | `--min-score FLOAT` | Float | 0.0 | Minimum mutation score (0.0–1.0) to pass. |
46
- | `--spec FILES` | Array | _(none)_ | Spec files to run (comma-separated). Defaults to `spec/`. |
47
- | `-j`, `--jobs N` | Integer | 1 | Number of parallel workers. Pool forks per batch; mutations run in-process inside workers. |
48
- | `--no-baseline` | Boolean | _(enabled)_ | Skip baseline test suite check. By default, a baseline run detects pre-existing failures and marks those mutations as `neutral`. |
49
- | `--fail-fast [N]` | Integer | _(none)_ | Stop after N surviving mutants (default 1 if no value given). |
50
- | `-v`, `--verbose` | Boolean | false | Verbose output with RSS memory and GC stats per phase and per mutation. |
51
- | `--suggest-tests` | Boolean | false | Generate concrete RSpec test code in suggestions instead of static descriptions. |
52
- | `-q`, `--quiet` | Boolean | false | Suppress output. |
48
+ | Flag | Type | Default | Description |
49
+ |------------------------------|---------|--------------|---------------------------------------------------|
50
+ | `-t`, `--timeout N` | Integer | 30 | Per-mutation timeout in seconds. |
51
+ | `-f`, `--format FORMAT` | String | `text` | Output format: `text`, `json`, or `html`. |
52
+ | `--target EXPR` | String | _(none)_ | Only mutate matching methods. Supports method name (`Foo::Bar#calculate`), class (`Foo`), namespace wildcards (`Foo::Bar*`), method-type selectors (`Foo#`, `Foo.`), descendants (`descendants:Foo`), and source globs (`source:lib/**/*.rb`). |
53
+ | `--min-score FLOAT` | Float | 0.0 | Minimum mutation score (0.0–1.0) to pass. |
54
+ | `--spec FILES` | Array | _(none)_ | Spec files to run (comma-separated). Defaults to `spec/`. |
55
+ | `-j`, `--jobs N` | Integer | 1 | Number of parallel workers. Uses demand-driven work distribution with pipe-based IPC. |
56
+ | `--no-baseline` | Boolean | _(enabled)_ | Skip baseline test suite check. By default, a baseline run detects pre-existing failures and marks those mutations as `neutral`. |
57
+ | `--fail-fast [N]` | Integer | _(none)_ | Stop after N surviving mutants (default 1 if no value given). |
58
+ | `-v`, `--verbose` | Boolean | false | Verbose output with RSS memory and GC stats per phase and per mutation. |
59
+ | `--suggest-tests` | Boolean | false | Generate concrete RSpec test code in suggestions instead of static descriptions. |
60
+ | `-q`, `--quiet` | Boolean | false | Suppress output. |
61
+ | `--stdin` | Boolean | false | Read target file paths from stdin (one per line). |
62
+ | `--incremental` | Boolean | false | Cache killed/timeout results; skip unchanged mutations on re-runs. |
63
+ | `--save-session` | Boolean | false | Persist results as timestamped JSON under `.evilution/results/`. |
64
+ | `--no-progress` | Boolean | _(enabled)_ | Disable the TTY progress bar. |
65
+ | `--show-disabled` | Boolean | false | Report mutations skipped by `# evilution:disable` comments. |
66
+ | `--baseline-session PATH` | String | _(none)_ | Saved session file for HTML report comparison. |
67
+ | `-e CODE`, `--eval CODE` | String | _(none)_ | Inline Ruby code for `util mutation` command. |
53
68
 
54
69
  ### Exit Codes
55
70
 
@@ -66,15 +81,43 @@ Generate default config: `bundle exec evilution init`
66
81
  Creates `.evilution.yml`:
67
82
 
68
83
  ```yaml
69
- # timeout: 10 # seconds per mutation
70
- # format: text # text | json
71
- # min_score: 0.0 # 0.0–1.0
72
- # integration: rspec # test framework
73
- # suggest_tests: false # concrete RSpec test code in suggestions
84
+ # timeout: 30 # seconds per mutation
85
+ # format: text # text | json | html
86
+ # min_score: 0.0 # 0.0–1.0
87
+ # integration: rspec # test framework
88
+ # suggest_tests: false # concrete RSpec test code in suggestions
89
+ # save_session: false # persist results under .evilution/results/
90
+ # show_disabled: false # report mutations skipped by disable comments
91
+ # baseline_session: null # path to session file for HTML comparison
92
+ # ignore_patterns: [] # AST patterns to exclude (see docs/ast_pattern_syntax.md)
93
+ # progress: true # TTY progress bar
74
94
  ```
75
95
 
76
96
  **Precedence**: CLI flags override `.evilution.yml` values.
77
97
 
98
+ ## Disable Comments
99
+
100
+ Suppress mutations on specific code with inline comments:
101
+
102
+ ```ruby
103
+ # Disable a single line
104
+ log(message) # evilution:disable
105
+
106
+ # Disable an entire method (place comment immediately before def)
107
+ # evilution:disable
108
+ def infrastructure_method
109
+ # no mutations generated for this method body
110
+ end
111
+
112
+ # Disable a region
113
+ # evilution:disable
114
+ setup_logging
115
+ configure_metrics
116
+ # evilution:enable
117
+ ```
118
+
119
+ Use `--show-disabled` to see which mutations were skipped.
120
+
78
121
  ## JSON Output Schema
79
122
 
80
123
  Use `--format json` for machine-readable output. Schema:
@@ -112,30 +155,72 @@ Use `--format json` for machine-readable output. Schema:
112
155
 
113
156
  **Key metric**: `summary.score` — the mutation score. Higher is better. 1.0 means all mutations were caught.
114
157
 
115
- ## Mutation Operators (18 total)
158
+ ## Mutation Operators (60 total)
116
159
 
117
160
  Each operator name is stable and appears in JSON output under `survived[].operator`.
118
161
 
119
- | Operator | What it does | Example |
120
- |---------------------------|-------------------------------------------|------------------------------------|
121
- | `arithmetic_replacement` | Swap arithmetic operators | `a + b` -> `a - b` |
122
- | `comparison_replacement` | Swap comparison operators | `a >= b` -> `a > b` |
123
- | `boolean_operator_replacement` | Swap `&&` / `\|\|` | `a && b` -> `a \|\| b` |
124
- | `boolean_literal_replacement` | Flip boolean literals | `true` -> `false` |
125
- | `nil_replacement` | Replace expression with `nil` | `expr` -> `nil` |
126
- | `integer_literal` | Boundary-value integer mutations | `n` -> `0`, `1`, `n+1`, `n-1` |
127
- | `float_literal` | Boundary-value float mutations | `f` -> `0.0`, `1.0` |
128
- | `string_literal` | Empty the string | `"str"` -> `""` |
129
- | `array_literal` | Empty the array | `[a, b]` -> `[]` |
130
- | `hash_literal` | Empty the hash | `{k: v}` -> `{}` |
131
- | `symbol_literal` | Replace with sentinel symbol | `:foo` -> `:__evilution_mutated__` |
132
- | `conditional_negation` | Replace condition with `true`/`false` | `if cond` -> `if true` |
133
- | `conditional_branch` | Remove if/else branch | Deletes branch body |
134
- | `statement_deletion` | Remove statements from method bodies | Deletes a statement |
135
- | `method_body_replacement` | Replace entire method body with `nil` | Method body -> `nil` |
136
- | `negation_insertion` | Negate predicate methods | `x.empty?` -> `!x.empty?` |
137
- | `return_value_removal` | Strip return values | `return x` -> `return` |
138
- | `collection_replacement` | Swap collection methods | `map` -> `each`, `select` <-> `reject` |
162
+ | Operator | What it does | Example |
163
+ |---|---|---|
164
+ | `arithmetic_replacement` | Swap arithmetic operators | `a + b` -> `a - b` |
165
+ | `comparison_replacement` | Swap comparison operators | `a >= b` -> `a > b` |
166
+ | `boolean_operator_replacement` | Swap `&&` / `\|\|` | `a && b` -> `a \|\| b` |
167
+ | `boolean_literal_replacement` | Flip boolean literals | `true` -> `false` |
168
+ | `nil_replacement` | Replace `nil` with `true`, `false`, `0`, `""` | `nil` -> `true` |
169
+ | `integer_literal` | Boundary-value integer mutations | `n` -> `0`, `1`, `n+1`, `n-1` |
170
+ | `float_literal` | Boundary-value float mutations | `f` -> `0.0`, `1.0` |
171
+ | `string_literal` | Empty the string | `"str"` -> `""` |
172
+ | `array_literal` | Empty the array | `[a, b]` -> `[]` |
173
+ | `hash_literal` | Empty the hash | `{k: v}` -> `{}` |
174
+ | `symbol_literal` | Replace with sentinel symbol | `:foo` -> `:__evilution_mutated__` |
175
+ | `conditional_negation` | Replace condition with `true`/`false` | `if cond` -> `if true` |
176
+ | `conditional_branch` | Remove if/else branch | Deletes branch body |
177
+ | `conditional_flip` | Flip `if` to `unless` and vice versa | `if cond` -> `unless cond` |
178
+ | `statement_deletion` | Remove statements from method bodies | Deletes a statement |
179
+ | `method_body_replacement` | Replace entire method body with `nil` | Method body -> `nil` |
180
+ | `negation_insertion` | Negate predicate methods | `x.empty?` -> `!x.empty?` |
181
+ | `return_value_removal` | Strip return values | `return x` -> `return` |
182
+ | `collection_replacement` | Swap collection methods | `map` -> `each`, `select` <-> `reject` |
183
+ | `collection_return` | Replace collection return values | `return [1]` -> `return []` |
184
+ | `scalar_return` | Replace scalar return values | `return 42` -> `return 0` |
185
+ | `method_call_removal` | Remove method calls, keep receiver | `obj.foo(x)` -> `obj` |
186
+ | `argument_removal` | Remove individual arguments | `foo(a, b)` -> `foo(b)` |
187
+ | `argument_nil_substitution` | Replace arguments with `nil` | `foo(a, b)` -> `foo(nil, b)` |
188
+ | `keyword_argument` | Remove keyword defaults/params | `def foo(bar: 42)` -> `def foo(bar:)` |
189
+ | `multiple_assignment` | Remove targets or swap order | `a, b = 1, 2` -> `b, a = 1, 2` |
190
+ | `block_removal` | Remove blocks from method calls | `items.map { \|x\| x * 2 }` -> `items.map` |
191
+ | `range_replacement` | Swap inclusive/exclusive ranges | `1..10` -> `1...10` |
192
+ | `regexp_mutation` | Replace regexp with always/never matching | `/pat/` -> `/a\A/` |
193
+ | `receiver_replacement` | Drop explicit `self` receiver | `self.foo` -> `foo` |
194
+ | `send_mutation` | Swap semantically related methods | `detect` -> `find`, `map` -> `flat_map` |
195
+ | `compound_assignment` | Swap compound assignment operators | `+=` -> `-=`, `&&=` -> `\|\|=` |
196
+ | `local_variable_assignment` | Replace variable assignment with `nil` | `x = expr` -> `x = nil` |
197
+ | `instance_variable_write` | Replace ivar assignment with `nil` | `@x = expr` -> `@x = nil` |
198
+ | `class_variable_write` | Replace cvar assignment with `nil` | `@@x = expr` -> `@@x = nil` |
199
+ | `global_variable_write` | Replace gvar assignment with `nil` | `$x = expr` -> `$x = nil` |
200
+ | `mixin_removal` | Remove include/extend/prepend | `include Foo` -> removed |
201
+ | `superclass_removal` | Remove class inheritance | `class Foo < Bar` -> `class Foo` |
202
+ | `rescue_removal` | Remove rescue clauses | Deletes rescue block |
203
+ | `rescue_body_replacement` | Replace rescue body with `nil` | Rescue body -> `nil` |
204
+ | `inline_rescue` | Remove inline rescue fallback | `expr rescue val` -> `expr` |
205
+ | `ensure_removal` | Remove ensure blocks | Deletes ensure block |
206
+ | `break_statement` | Remove break statements | `break` -> removed |
207
+ | `next_statement` | Remove next statements | `next` -> removed |
208
+ | `redo_statement` | Remove redo statements | `redo` -> removed |
209
+ | `bang_method` | Swap bang with non-bang methods | `sort!` -> `sort` |
210
+ | `bitwise_replacement` | Swap bitwise operators | `a & b` -> `a \| b` |
211
+ | `bitwise_complement` | Remove or swap `~` | `~x` -> `x`, `~x` -> `-x` |
212
+ | `zsuper_removal` | Replace implicit `super` with `nil` | `super` -> `nil` |
213
+ | `explicit_super_mutation` | Mutate explicit super arguments | `super(a, b)` -> `super` |
214
+ | `index_to_fetch` | Replace `[]` with `.fetch()` | `h[k]` -> `h.fetch(k)` |
215
+ | `index_to_dig` | Replace `[]` chains with `.dig()` | `h[a][b]` -> `h.dig(a, b)` |
216
+ | `index_assignment_removal` | Remove `[]=` assignments | `h[k] = v` -> removed |
217
+ | `pattern_matching_guard` | Remove/negate pattern guards | `in x if cond` -> `in x` |
218
+ | `pattern_matching_alternative` | Remove/reorder alternatives | `pat1 \| pat2` -> `pat1` |
219
+ | `pattern_matching_array` | Remove/wildcard array elements | `[a, b]` -> `[a, _]` |
220
+ | `yield_statement` | Remove yield or its arguments | `yield(x)` -> `yield` |
221
+ | `splat_operator` | Remove splat/double-splat | `foo(*args)` -> `foo(args)` |
222
+ | `defined_check` | Replace `defined?` with `true` | `defined?(x)` -> `true` |
223
+ | `regex_capture` | Swap or nil-ify capture refs | `$1` -> `$2`, `$1` -> `nil` |
139
224
 
140
225
  ## MCP Server (AI Agent Integration)
141
226
 
@@ -160,7 +245,14 @@ Create a `.mcp.json` file in your project root:
160
245
 
161
246
  If using Bundler, set the command to `bundle` and args to `["exec", "evilution", "mcp"]`.
162
247
 
163
- The server exposes an `evilution-mutate` tool that accepts target files, method targets, spec overrides, parallelism, and timeout options — returning structured JSON results directly to the agent.
248
+ The server exposes the following tools:
249
+
250
+ | Tool | Description |
251
+ |---|---|
252
+ | `evilution-mutate` | Run mutation testing on target files with structured JSON results |
253
+ | `evilution-session-list` | Browse saved session history |
254
+ | `evilution-session-show` | Display detailed session results |
255
+ | `evilution-session-diff` | Compare two sessions (fixed/new/persistent survivors, score delta) |
164
256
 
165
257
  ### Verbosity Control
166
258
 
@@ -274,11 +366,12 @@ Tests 4 paths (InProcess isolation, Fork isolation, mutation generation + stripp
274
366
 
275
367
  1. **Parse** — Prism parses Ruby files into ASTs with exact byte offsets
276
368
  2. **Extract** — Methods are identified as mutation subjects
277
- 3. **Mutate** — Operators produce text replacements at precise byte offsets (source-level surgery, no AST unparsing)
278
- 4. **Isolate** — Default isolation is in-process; `--isolation fork` uses forked child processes. Parallel mode (`--jobs N`) always uses in-process isolation inside pool workers to avoid double forking
279
- 5. **Test** — RSpec executes against the mutated source
280
- 6. **Collect** — Source strings and AST nodes are released after use to minimize memory retention
281
- 7. **Report** — Results aggregated into text or JSON, including peak memory usage
369
+ 3. **Filter** — Disable comments, Sorbet `sig` blocks, and AST ignore patterns exclude mutations before execution
370
+ 4. **Mutate** — 60 operators produce text replacements at precise byte offsets (source-level surgery, no AST unparsing)
371
+ 5. **Isolate** — Default isolation is in-process; `--isolation fork` uses forked child processes. Parallel mode (`--jobs N`) always uses in-process isolation inside pool workers to avoid double forking
372
+ 6. **Test** — RSpec executes against the mutated source
373
+ 7. **Collect** — Source strings and AST nodes are released after use to minimize memory retention
374
+ 8. **Report** — Results aggregated into text, JSON, or HTML, including efficiency metrics and peak memory usage
282
375
 
283
376
  ## Repository
284
377