evilution 0.14.0 → 0.16.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 (40) hide show
  1. checksums.yaml +4 -4
  2. data/.beads/.migration-hint-ts +1 -1
  3. data/.beads/issues.jsonl +41 -41
  4. data/CHANGELOG.md +43 -0
  5. data/lib/evilution/ast/inheritance_scanner.rb +70 -0
  6. data/lib/evilution/ast/parser.rb +10 -6
  7. data/lib/evilution/cli.rb +6 -1
  8. data/lib/evilution/config.rb +7 -1
  9. data/lib/evilution/equivalent/detector.rb +5 -1
  10. data/lib/evilution/equivalent/heuristic/alias_swap.rb +5 -2
  11. data/lib/evilution/equivalent/heuristic/arithmetic_identity.rb +30 -0
  12. data/lib/evilution/equivalent/heuristic/comment_marking.rb +21 -0
  13. data/lib/evilution/mutator/base.rb +16 -0
  14. data/lib/evilution/mutator/operator/bang_method.rb +48 -0
  15. data/lib/evilution/mutator/operator/bitwise_complement.rb +31 -0
  16. data/lib/evilution/mutator/operator/bitwise_replacement.rb +30 -0
  17. data/lib/evilution/mutator/operator/break_statement.rb +50 -0
  18. data/lib/evilution/mutator/operator/class_variable_write.rb +25 -0
  19. data/lib/evilution/mutator/operator/collection_replacement.rb +25 -1
  20. data/lib/evilution/mutator/operator/ensure_removal.rb +27 -0
  21. data/lib/evilution/mutator/operator/explicit_super_mutation.rb +47 -0
  22. data/lib/evilution/mutator/operator/global_variable_write.rb +25 -0
  23. data/lib/evilution/mutator/operator/inline_rescue.rb +39 -0
  24. data/lib/evilution/mutator/operator/instance_variable_write.rb +25 -0
  25. data/lib/evilution/mutator/operator/local_variable_assignment.rb +16 -0
  26. data/lib/evilution/mutator/operator/mixin_removal.rb +80 -0
  27. data/lib/evilution/mutator/operator/next_statement.rb +50 -0
  28. data/lib/evilution/mutator/operator/redo_statement.rb +18 -0
  29. data/lib/evilution/mutator/operator/rescue_body_replacement.rb +94 -0
  30. data/lib/evilution/mutator/operator/rescue_removal.rb +37 -0
  31. data/lib/evilution/mutator/operator/send_mutation.rb +11 -2
  32. data/lib/evilution/mutator/operator/superclass_removal.rb +65 -0
  33. data/lib/evilution/mutator/operator/zsuper_removal.rb +16 -0
  34. data/lib/evilution/mutator/registry.rb +19 -1
  35. data/lib/evilution/reporter/progress_bar.rb +84 -0
  36. data/lib/evilution/reporter/suggestion.rb +253 -1
  37. data/lib/evilution/runner.rb +105 -19
  38. data/lib/evilution/version.rb +1 -1
  39. data/lib/evilution.rb +20 -0
  40. metadata +24 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 07cd7bdd77da17dd201aa8e598707c326f4a9763ded14edfcd871a67de1ab2f5
4
- data.tar.gz: 47b0a007f57cc93f1a143555db3600c92dc38a116b58004a9ce7d1e4a0aadd5c
3
+ metadata.gz: 46fcb52d0561a5756a54aec57feea73d0879dfee69a0da9b191b4204cefc3a09
4
+ data.tar.gz: d827547c959475ca82836ad80bfa0c02bdcf129a112fd0919dbf99a7fca3542e
5
5
  SHA512:
6
- metadata.gz: ec518cde7ff3380d303ded60d7ea30b507d4b4d363d22211c06789de4cec6af8ad92e8b86e77a5a0d9551c9051cbf8afde4dc3eb261de8404260c22ada861648
7
- data.tar.gz: 2e60811f5ebe09e8958024f8edbf2c1bd825dd82b5c1e94a044e097108141ecbba4c90dcee86a9c2934b53b3bab4c0afc0bcfb2080d337e4fc26675b46140231
6
+ metadata.gz: c2169e9aec3f90c27bb7de779d7f66cc261c73a58234e356020684527918487522fb13e2ab39a1c50bf0378602ac2849fe280bd9774b934e440d0c2b525ee89f
7
+ data.tar.gz: 39da178f17461bfd29557994914e487cfd86abcc7a009cc05af0a944426b971cf39824f8a188414ce6af647f1e87989a1c313237c693c885ce75e68b61f38e77
@@ -1 +1 @@
1
- 1774634346
1
+ 1774720771
data/.beads/issues.jsonl CHANGED
@@ -8,53 +8,53 @@
8
8
  {"id":"EV-10","title":"Publish v0.1.0 gem release","description":"Gemspec is ready. Tag v0.1.0, build the gem, and publish to RubyGems. Steps: verify gemspec metadata, run rake release (or manual gem build + gem push), create GitHub release with CHANGELOG notes.","status":"closed","priority":3,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-02T16:21:53.571182801+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-06T11:44:35.748868691+07:00","closed_at":"2026-03-06T11:44:35.748868691+07:00","close_reason":"Published to RubyGems"}
9
9
  {"id":"EV-100","title":"Epic: Expand send/method dispatch mutations","description":"Add more method dispatch mutation variants to close the gap with Mutant. Specifically called out in feedback: []/fetch, bang/non-bang, enumerable reductions.","status":"open","priority":2,"issue_type":"feature","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:16:17.980288778+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:16:17.980288778+07:00"}
10
10
  {"id":"EV-101","title":"Add RSpec suggestion templates for compound assignment mutations","description":"Add concrete RSpec it-block suggestion templates for survived compound assignment mutations to the SuggestionReporter. Follow patterns from existing suggestion templates.","status":"closed","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:16:24.805269164+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T17:07:01.363637634+07:00","closed_at":"2026-03-23T17:07:01.363637634+07:00","close_reason":"PR merged. Added static and concrete RSpec suggestion templates for compound assignment mutations.","dependencies":[{"issue_id":"EV-101","depends_on_id":"EV-86","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
11
- {"id":"EV-102","title":"Implement redo statement mutator","description":"Create a mutator for redo statements. Mutations: remove redo statement entirely. Prism redo_node.","status":"open","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:16:25.879559251+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:16:25.879559251+07:00","dependencies":[{"issue_id":"EV-102","depends_on_id":"EV-91","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
12
- {"id":"EV-103","title":"Add pop/shift and push/unshift method swap pairs","description":"Add orthogonal method swap pairs: pop↔shift (remove from end vs start), push↔unshift (add to end vs start). Register in the collection method swap operator.","status":"open","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:16:26.957515204+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:16:26.957515204+07:00","dependencies":[{"issue_id":"EV-103","depends_on_id":"EV-96","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
11
+ {"id":"EV-102","title":"Implement redo statement mutator","description":"Create a mutator for redo statements. Mutations: remove redo statement entirely. Prism redo_node.","status":"in_progress","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:16:25.879559251+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-29T11:57:54.07790533+07:00","dependencies":[{"issue_id":"EV-102","depends_on_id":"EV-91","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
12
+ {"id":"EV-103","title":"Add pop/shift and push/unshift method swap pairs","description":"Add orthogonal method swap pairs: pop↔shift (remove from end vs start), push↔unshift (add to end vs start). Register in the collection method swap operator.","status":"in_progress","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:16:26.957515204+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-29T12:07:42.123537403+07:00","dependencies":[{"issue_id":"EV-103","depends_on_id":"EV-96","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
13
13
  {"id":"EV-104","title":"Implement global variable mutation","description":"Create a mutator for global variable writes ($gvar = val). Mutations: remove assignment, replace value with nil. Prism global_variable_write_node.","status":"open","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:16:27.098660867+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:16:27.098660867+07:00","dependencies":[{"issue_id":"EV-104","depends_on_id":"EV-87","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
14
14
  {"id":"EV-105","title":"Epic: Bitwise operator mutations","description":"Add mutation operators for bitwise expressions (&, |, ^, ~). Mutant supports full bitwise swaps; Evilution has none. Important for low-level Ruby code and flag/bitmask operations.","status":"open","priority":2,"issue_type":"feature","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:16:35.702212876+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T17:08:39.7050919+07:00"}
15
- {"id":"EV-106","title":"Add each_key/each_value and assoc/rassoc method swap pairs","description":"Add orthogonal method swap pairs: each_key↔each_value (iterate keys vs values), assoc↔rassoc (search by key vs value). Register in the collection method swap operator.","status":"open","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:16:38.318168048+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:16:38.318168048+07:00","dependencies":[{"issue_id":"EV-106","depends_on_id":"EV-96","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
16
- {"id":"EV-107","title":"Add RSpec suggestion templates for control flow mutations","description":"Add concrete RSpec suggestion templates for survived break/next/redo mutations to the SuggestionReporter.","status":"open","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:16:39.204347976+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:16:39.204347976+07:00","dependencies":[{"issue_id":"EV-107","depends_on_id":"EV-91","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
17
- {"id":"EV-108","title":"Add RSpec suggestion templates for variable mutations","description":"Add concrete RSpec suggestion templates for survived variable mutations to the SuggestionReporter.","status":"open","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:16:42.648616139+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:16:42.648616139+07:00","dependencies":[{"issue_id":"EV-108","depends_on_id":"EV-87","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
18
- {"id":"EV-109","title":"Implement bitwise binary operator mutator (&, |, ^)","description":"Create a new mutator that swaps bitwise binary operators (&, |, ^) with each other. Register in Mutator::Registry. These are Prism call_node operations with bitwise method names.","status":"open","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:16:44.961048186+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:16:44.961048186+07:00","dependencies":[{"issue_id":"EV-109","depends_on_id":"EV-105","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
15
+ {"id":"EV-106","title":"Add each_key/each_value and assoc/rassoc method swap pairs","description":"Add orthogonal method swap pairs: each_key↔each_value (iterate keys vs values), assoc↔rassoc (search by key vs value). Register in the collection method swap operator.","status":"in_progress","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:16:38.318168048+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-29T12:52:13.426110699+07:00","dependencies":[{"issue_id":"EV-106","depends_on_id":"EV-96","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
16
+ {"id":"EV-107","title":"Add RSpec suggestion templates for control flow mutations","description":"Add concrete RSpec suggestion templates for survived break/next/redo mutations to the SuggestionReporter.","status":"in_progress","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:16:39.204347976+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-29T12:02:40.995082091+07:00","dependencies":[{"issue_id":"EV-107","depends_on_id":"EV-91","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
17
+ {"id":"EV-108","title":"Add RSpec suggestion templates for variable mutations","description":"Add concrete RSpec suggestion templates for survived variable mutations to the SuggestionReporter.","status":"in_progress","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:16:42.648616139+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-29T01:53:09.086144843+07:00","dependencies":[{"issue_id":"EV-108","depends_on_id":"EV-87","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
18
+ {"id":"EV-109","title":"Implement bitwise binary operator mutator (&, |, ^)","description":"Create a new mutator that swaps bitwise binary operators (&, |, ^) with each other. Register in Mutator::Registry. These are Prism call_node operations with bitwise method names.","status":"in_progress","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:16:44.961048186+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-29T13:57:57.624854414+07:00","dependencies":[{"issue_id":"EV-109","depends_on_id":"EV-105","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
19
19
  {"id":"EV-11","title":"Wire coverage-based filtering into Runner","description":"Collector and TestMap exist and pass specs, but Runner never calls them. When config.coverage is true, Runner collects aggregate line-level coverage via Coverage::Collector, builds a Coverage::TestMap, and skips mutations on lines that no test exercises (marking them as survived with zero duration). Note: Ruby Coverage provides aggregate per-file line hit counts, not per-test-file tracking, so we filter out uncovered mutations rather than selecting specific test files.","status":"closed","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-04T11:52:42.607616728+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-06T11:02:25.4848637+07:00","closed_at":"2026-03-05T14:53:24.894588088+07:00","close_reason":"Coverage-based test selection wired into Runner"}
20
20
  {"id":"EV-110","title":"Epic: Hooks system for mutation lifecycle","description":"Implement a hooks system allowing users to register custom Ruby code at critical execution points. Mutant provides 8 hook points (env_infection_pre/post, setup_integration_pre/post, mutation_insert_pre/post, mutation_worker_process_start, test_worker_process_start). Essential for Rails database isolation in parallel workers, custom instrumentation, and specialized test environment setup.","status":"open","priority":2,"issue_type":"feature","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:16:46.117603755+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:16:46.117603755+07:00"}
21
- {"id":"EV-111","title":"Add grep/grep_v and take/drop method swap pairs","description":"Add orthogonal method swap pairs: grep↔grep_v (match vs non-match), take↔drop (keep first N vs remove first N). Register in the collection method swap operator.","status":"open","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:16:47.432188126+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:16:47.432188126+07:00","dependencies":[{"issue_id":"EV-111","depends_on_id":"EV-96","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
21
+ {"id":"EV-111","title":"Add grep/grep_v and take/drop method swap pairs","description":"Add orthogonal method swap pairs: grep↔grep_v (match vs non-match), take↔drop (keep first N vs remove first N). Register in the collection method swap operator.","status":"in_progress","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:16:47.432188126+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-29T12:57:53.868853745+07:00","dependencies":[{"issue_id":"EV-111","depends_on_id":"EV-96","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
22
22
  {"id":"EV-112","title":"Epic: Super call mutations","description":"Add mutations for super and zsuper (implicit super) calls. Mutant distinguishes zsuper (forwards all args) from explicit super (specific args) and mutates between them. Evilution has none.","status":"open","priority":2,"issue_type":"feature","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:16:51.249178891+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:16:51.249178891+07:00"}
23
- {"id":"EV-113","title":"Implement rescue clause removal mutator","description":"Create a mutator that removes individual rescue clauses from begin/rescue blocks. When multiple rescue clauses exist, remove each one individually. Prism rescue_node.","status":"open","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:16:53.280678046+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:16:53.280678046+07:00","dependencies":[{"issue_id":"EV-113","depends_on_id":"EV-89","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
24
- {"id":"EV-114","title":"Implement bitwise complement (~) mutator","description":"Create a mutator for the bitwise NOT/complement operator (~). Mutations: remove ~ (unwrap to operand), swap with unary minus. This is a Prism call_node with ~ as the method name and no arguments.","status":"open","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:16:55.061833915+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:16:55.061833915+07:00","dependencies":[{"issue_id":"EV-114","depends_on_id":"EV-105","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
25
- {"id":"EV-115","title":"Add min/max and min_by/max_by method swap pairs","description":"Add orthogonal method swap pairs: min↔max, min_by↔max_by. Register in the collection method swap operator.","status":"open","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:16:57.324659361+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:16:57.324659361+07:00","dependencies":[{"issue_id":"EV-115","depends_on_id":"EV-96","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
26
- {"id":"EV-116","title":"Implement zsuper removal mutator","description":"Create a mutator for implicit super calls (zsuper — super with no parens). Mutations: remove the super call entirely. Prism forwarding_super_node.","status":"open","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:17:00.030638552+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:17:00.030638552+07:00","dependencies":[{"issue_id":"EV-116","depends_on_id":"EV-112","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
27
- {"id":"EV-117","title":"Implement rescue body replacement mutator","description":"Create a mutator that replaces rescue clause bodies with nil or re-raise. Tests whether the rescue handler logic is actually tested.","status":"open","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:17:07.741756241+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:17:07.741756241+07:00","dependencies":[{"issue_id":"EV-117","depends_on_id":"EV-89","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
28
- {"id":"EV-118","title":"Add compact/flatten and zip/product method swap pairs","description":"Add method swap pairs: compact↔flatten (remove nils vs flatten nesting), zip↔product (pairwise vs cartesian). Register in the collection method swap operator.","status":"open","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:17:09.488783588+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:17:09.488783588+07:00","dependencies":[{"issue_id":"EV-118","depends_on_id":"EV-96","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
23
+ {"id":"EV-113","title":"Implement rescue clause removal mutator","description":"Create a mutator that removes individual rescue clauses from begin/rescue blocks. When multiple rescue clauses exist, remove each one individually. Prism rescue_node.","status":"in_progress","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:16:53.280678046+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-29T01:58:05.000652348+07:00","dependencies":[{"issue_id":"EV-113","depends_on_id":"EV-89","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
24
+ {"id":"EV-114","title":"Implement bitwise complement (~) mutator","description":"Create a mutator for the bitwise NOT/complement operator (~). Mutations: remove ~ (unwrap to operand), swap with unary minus. This is a Prism call_node with ~ as the method name and no arguments.","status":"in_progress","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:16:55.061833915+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-29T14:10:45.714387484+07:00","dependencies":[{"issue_id":"EV-114","depends_on_id":"EV-105","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
25
+ {"id":"EV-115","title":"Add min/max and min_by/max_by method swap pairs","description":"Add orthogonal method swap pairs: min↔max, min_by↔max_by. Register in the collection method swap operator.","status":"in_progress","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:16:57.324659361+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-29T13:03:36.13864378+07:00","dependencies":[{"issue_id":"EV-115","depends_on_id":"EV-96","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
26
+ {"id":"EV-116","title":"Implement zsuper removal mutator","description":"Create a mutator for implicit super calls (zsuper — super with no parens). Mutations: remove the super call entirely. Prism forwarding_super_node.","status":"in_progress","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:17:00.030638552+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-29T14:22:27.928183609+07:00","dependencies":[{"issue_id":"EV-116","depends_on_id":"EV-112","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
27
+ {"id":"EV-117","title":"Implement rescue body replacement mutator","description":"Create a mutator that replaces rescue clause bodies with nil or re-raise. Tests whether the rescue handler logic is actually tested.","status":"in_progress","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:17:07.741756241+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-29T09:46:31.420660224+07:00","dependencies":[{"issue_id":"EV-117","depends_on_id":"EV-89","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
28
+ {"id":"EV-118","title":"Add compact/flatten and zip/product method swap pairs","description":"Add method swap pairs: compact↔flatten (remove nils vs flatten nesting), zip↔product (pairwise vs cartesian). Register in the collection method swap operator.","status":"in_progress","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:17:09.488783588+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-29T13:07:37.800200558+07:00","dependencies":[{"issue_id":"EV-118","depends_on_id":"EV-96","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
29
29
  {"id":"EV-119","title":"Design hook registry and configuration API","description":"Design the hook system API: how hooks are registered (config file, Ruby API), what data they receive, and how errors are handled. Support at minimum: worker_process_start, mutation_insert_pre/post, and setup_integration_pre/post hook points.","status":"open","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:17:09.630400111+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:17:09.630400111+07:00","dependencies":[{"issue_id":"EV-119","depends_on_id":"EV-110","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
30
30
  {"id":"EV-12","title":"Resolve suggestion gap","description":"The workflow section instructs agents to read a suggestion field from survived[], but the JSON reporter output does not include suggestion (lib/evilution/reporter/json.rb only emits operator/file/line/status/duration/diff). Either add suggestion to the JSON output/schema or update the workflow steps to match the actual report fields. See GitHub issue #12.","status":"closed","priority":2,"issue_type":"bug","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-05T12:33:23.674094791+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-05T13:05:48.785616141+07:00","closed_at":"2026-03-05T13:05:48.785616141+07:00","close_reason":"Wired Suggestion into JSON reporter for survived mutations, updated README schema, added specs"}
31
- {"id":"EV-120","title":"Implement explicit super argument mutations","description":"Create a mutator for explicit super(args) calls. Mutations: remove arguments (super() with no args), remove individual arguments, replace super with zsuper. Prism super_node.","status":"open","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:17:10.245605293+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:17:10.245605293+07:00","dependencies":[{"issue_id":"EV-120","depends_on_id":"EV-112","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
32
- {"id":"EV-121","title":"Add RSpec suggestion templates for bitwise operator mutations","description":"Add concrete RSpec suggestion templates for survived bitwise operator mutations to the SuggestionReporter.","status":"open","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:17:12.673234672+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:17:12.673234672+07:00","dependencies":[{"issue_id":"EV-121","depends_on_id":"EV-105","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
33
- {"id":"EV-122","title":"Implement inline rescue mutation","description":"Create a mutator for inline rescue expressions (expr rescue fallback). Mutations: remove rescue (keep only expr), replace fallback with nil. Prism rescue_modifier_node.","status":"open","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:17:18.843414731+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:17:18.843414731+07:00","dependencies":[{"issue_id":"EV-122","depends_on_id":"EV-89","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
31
+ {"id":"EV-120","title":"Implement explicit super argument mutations","description":"Create a mutator for explicit super(args) calls. Mutations: remove arguments (super() with no args), remove individual arguments, replace super with zsuper. Prism super_node.","status":"in_progress","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:17:10.245605293+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-29T14:27:56.442898048+07:00","dependencies":[{"issue_id":"EV-120","depends_on_id":"EV-112","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
32
+ {"id":"EV-121","title":"Add RSpec suggestion templates for bitwise operator mutations","description":"Add concrete RSpec suggestion templates for survived bitwise operator mutations to the SuggestionReporter.","status":"in_progress","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:17:12.673234672+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-29T14:16:14.791646944+07:00","dependencies":[{"issue_id":"EV-121","depends_on_id":"EV-105","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
33
+ {"id":"EV-122","title":"Implement inline rescue mutation","description":"Create a mutator for inline rescue expressions (expr rescue fallback). Mutations: remove rescue (keep only expr), replace fallback with nil. Prism rescue_modifier_node.","status":"in_progress","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:17:18.843414731+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-29T10:05:16.865721015+07:00","dependencies":[{"issue_id":"EV-122","depends_on_id":"EV-89","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
34
34
  {"id":"EV-123","title":"Fix version mismatch between CLI and MCP JSON output","description":"CLI reports 0.12.0 but MCP JSON version field says 0.11.2. The version string in the MCP server response is hardcoded or reading from a stale source. Should read from Evilution::VERSION consistently. Identified in real-world comparison testing feedback.","status":"closed","priority":1,"issue_type":"bug","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:17:19.056996262+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:34:16.40564094+07:00","closed_at":"2026-03-23T11:34:16.40564094+07:00","close_reason":"Already fixed — all version references (MCP server, JSON reporter, HTML reporter) use Evilution::VERSION consistently. The 0.11.2 seen in feedback was likely a stale gem installation."}
35
- {"id":"EV-124","title":"Add first/last and keys/values method swap pairs","description":"Add orthogonal method swap pairs: first↔last (Array endpoints), keys↔values (Hash extraction). Register in the collection method swap operator.","status":"open","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:17:19.366299705+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:17:19.366299705+07:00","dependencies":[{"issue_id":"EV-124","depends_on_id":"EV-96","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
36
- {"id":"EV-125","title":"Add RSpec suggestion templates for super mutations","description":"Add concrete RSpec suggestion templates for survived super mutations to the SuggestionReporter.","status":"open","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:17:20.933060824+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:17:20.933060824+07:00","dependencies":[{"issue_id":"EV-125","depends_on_id":"EV-112","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
35
+ {"id":"EV-124","title":"Add first/last and keys/values method swap pairs","description":"Add orthogonal method swap pairs: first↔last (Array endpoints), keys↔values (Hash extraction). Register in the collection method swap operator.","status":"in_progress","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:17:19.366299705+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-29T13:11:43.391612732+07:00","dependencies":[{"issue_id":"EV-124","depends_on_id":"EV-96","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
36
+ {"id":"EV-125","title":"Add RSpec suggestion templates for super mutations","description":"Add concrete RSpec suggestion templates for survived super mutations to the SuggestionReporter.","status":"in_progress","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:17:20.933060824+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-29T14:36:21.649380826+07:00","dependencies":[{"issue_id":"EV-125","depends_on_id":"EV-112","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
37
37
  {"id":"EV-126","title":"Implement hook registry module","description":"Create Evilution::Hooks::Registry that stores and dispatches hook callbacks. Support registering hooks by name, running hooks with context data, and error isolation (one failing hook shouldn't crash the run).","status":"open","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:17:21.393514581+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:17:21.393514581+07:00","dependencies":[{"issue_id":"EV-126","depends_on_id":"EV-110","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
38
- {"id":"EV-127","title":"Implement ensure clause removal mutator","description":"Create a mutator that removes ensure blocks from begin/ensure expressions. Tests whether cleanup code is actually necessary. Prism ensure_node.","status":"open","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:17:27.334061542+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:17:27.334061542+07:00","dependencies":[{"issue_id":"EV-127","depends_on_id":"EV-89","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
38
+ {"id":"EV-127","title":"Implement ensure clause removal mutator","description":"Create a mutator that removes ensure blocks from begin/ensure expressions. Tests whether cleanup code is actually necessary. Prism ensure_node.","status":"in_progress","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:17:27.334061542+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-29T10:37:25.904594009+07:00","dependencies":[{"issue_id":"EV-127","depends_on_id":"EV-89","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
39
39
  {"id":"EV-128","title":"Visual progress bar for TTY execution","description":"Add a visual TTY progress bar during mutation testing showing mutation count, kills, elapsed time, and ETA. Mutant has had this since v0.14.2. Important for user experience during long-running mutation testing sessions.","status":"open","priority":2,"issue_type":"feature","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:17:30.526136549+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:17:30.526136549+07:00"}
40
- {"id":"EV-129","title":"Add bang vs non-bang method mutations","description":"Create mutations that swap bang methods with their non-bang equivalents and vice versa (e.g., save! ↔ save, sort! ↔ sort, map! ↔ map, uniq! ↔ uniq). Tests whether the in-place vs copy semantics matter.","status":"open","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:17:30.959721048+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:17:30.959721048+07:00","dependencies":[{"issue_id":"EV-129","depends_on_id":"EV-100","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
40
+ {"id":"EV-129","title":"Add bang vs non-bang method mutations","description":"Create mutations that swap bang methods with their non-bang equivalents and vice versa (e.g., save! ↔ save, sort! ↔ sort, map! ↔ map, uniq! ↔ uniq). Tests whether the in-place vs copy semantics matter.","status":"in_progress","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:17:30.959721048+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-29T13:16:36.661424217+07:00","dependencies":[{"issue_id":"EV-129","depends_on_id":"EV-100","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
41
41
  {"id":"EV-13","title":"Enable true per-mutation isolation with temp file copies","description":"Replace direct file writes with temp-dir + $LOAD_PATH isolation so multiple workers can mutate the same file in parallel. Remove per-file grouping from Pool#partition.","status":"closed","priority":2,"issue_type":"feature","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-05T13:42:04.711580397+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-05T13:44:34.779951959+07:00","closed_at":"2026-03-05T13:44:34.779951959+07:00","close_reason":"Implemented temp file isolation via $LOAD_PATH and round-robin partition"}
42
42
  {"id":"EV-130","title":"Add worker_process_start hook point","description":"Fire the worker_process_start hook when a parallel worker process starts (after fork). This is the most important hook for Rails database isolation — users need to re-establish database connections after fork.","status":"open","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:17:31.360903708+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:17:31.360903708+07:00","dependencies":[{"issue_id":"EV-130","depends_on_id":"EV-110","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
43
43
  {"id":"EV-131","title":"Epic: Index access operator mutations ([] / []=)","description":"Add mutations for index access operators. Mutant mutates [] to fetch/dig and []=. These surface real semantic differences (e.g., KeyError vs nil on missing key). Specifically called out in feedback as important.","status":"open","priority":2,"issue_type":"feature","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:17:33.13561849+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:17:33.13561849+07:00"}
44
- {"id":"EV-132","title":"Add RSpec suggestion templates for exception handling mutations","description":"Add concrete RSpec suggestion templates for survived exception handling mutations to the SuggestionReporter.","status":"open","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:17:38.53663204+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:17:38.53663204+07:00","dependencies":[{"issue_id":"EV-132","depends_on_id":"EV-89","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
45
- {"id":"EV-133","title":"Implement TTY progress bar renderer","description":"Create a progress bar component that renders to TTY showing: [=====> ] 45/100 mutations | 38 killed | 2 survived | 00:23 elapsed | ~00:28 remaining. Detect TTY vs piped output and only show in TTY mode.","status":"open","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:17:40.177839247+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:17:40.177839247+07:00","dependencies":[{"issue_id":"EV-133","depends_on_id":"EV-128","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
44
+ {"id":"EV-132","title":"Add RSpec suggestion templates for exception handling mutations","description":"Add concrete RSpec suggestion templates for survived exception handling mutations to the SuggestionReporter.","status":"in_progress","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:17:38.53663204+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-29T10:48:10.93836753+07:00","dependencies":[{"issue_id":"EV-132","depends_on_id":"EV-89","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
45
+ {"id":"EV-133","title":"Implement TTY progress bar renderer","description":"Create a progress bar component that renders to TTY showing: [=====> ] 45/100 mutations | 38 killed | 2 survived | 00:23 elapsed | ~00:28 remaining. Detect TTY vs piped output and only show in TTY mode.","status":"in_progress","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:17:40.177839247+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-29T15:05:19.015910008+07:00","dependencies":[{"issue_id":"EV-133","depends_on_id":"EV-128","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
46
46
  {"id":"EV-134","title":"Implement [] to fetch mutation","description":"Create a mutator that replaces hash/array [] access with .fetch(). This surfaces whether code handles missing keys properly. The [] vs fetch distinction was specifically called out in comparison feedback.","status":"open","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:17:42.107226515+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:17:42.107226515+07:00","dependencies":[{"issue_id":"EV-134","depends_on_id":"EV-131","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
47
- {"id":"EV-135","title":"Add enumerable reduction method swaps","description":"Add method swap mutations for enumerable reductions: sum↔inject, count↔length↔size, detect↔find, select↔filter, collect↔map. Some may already exist; add the missing ones.","status":"open","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:17:42.397830812+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:17:42.397830812+07:00","dependencies":[{"issue_id":"EV-135","depends_on_id":"EV-100","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
47
+ {"id":"EV-135","title":"Add enumerable reduction method swaps","description":"Add method swap mutations for enumerable reductions: sum↔inject, count↔length↔size, detect↔find, select↔filter, collect↔map. Some may already exist; add the missing ones.","status":"in_progress","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:17:42.397830812+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-29T13:31:17.723196272+07:00","dependencies":[{"issue_id":"EV-135","depends_on_id":"EV-100","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
48
48
  {"id":"EV-136","title":"Add mutation_insert_pre/post hook points","description":"Fire hooks before and after each mutation is inserted into source. Provides the mutation details (operator, location, original/mutated code) to the hook callback.","status":"open","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:17:44.656504163+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:17:44.656504163+07:00","dependencies":[{"issue_id":"EV-136","depends_on_id":"EV-110","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
49
- {"id":"EV-137","title":"Integrate progress bar with Runner","description":"Wire the progress bar into Runner so it updates after each mutation result. Support both sequential and parallel execution modes. Ensure it doesn't interfere with verbose output.","status":"open","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:17:50.780537596+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:17:50.780537596+07:00","dependencies":[{"issue_id":"EV-137","depends_on_id":"EV-128","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
49
+ {"id":"EV-137","title":"Integrate progress bar with Runner","description":"Wire the progress bar into Runner so it updates after each mutation result. Support both sequential and parallel execution modes. Ensure it doesn't interfere with verbose output.","status":"in_progress","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:17:50.780537596+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-29T19:24:43.716640415+07:00","dependencies":[{"issue_id":"EV-137","depends_on_id":"EV-128","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
50
50
  {"id":"EV-138","title":"Implement [] to dig mutation","description":"Create a mutator that replaces nested [] access with .dig(). Tests whether nil propagation through nested access is handled.","status":"open","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:17:50.859337664+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:17:50.859337664+07:00","dependencies":[{"issue_id":"EV-138","depends_on_id":"EV-131","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
51
- {"id":"EV-139","title":"Add to_s/to_i/to_f/to_a/to_h conversion method swaps","description":"Add mutations that swap type conversion methods with each other (e.g., to_s↔to_i, to_a↔to_h). Tests whether the correct type conversion is used.","status":"open","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:17:52.403463105+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:17:52.403463105+07:00","dependencies":[{"issue_id":"EV-139","depends_on_id":"EV-100","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
51
+ {"id":"EV-139","title":"Add to_s/to_i/to_f/to_a/to_h conversion method swaps","description":"Add mutations that swap type conversion methods with each other (e.g., to_s↔to_i, to_a↔to_h). Tests whether the correct type conversion is used.","status":"in_progress","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:17:52.403463105+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-29T13:44:39.03275591+07:00","dependencies":[{"issue_id":"EV-139","depends_on_id":"EV-100","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
52
52
  {"id":"EV-14","title":"Add changelog_uri to gemspec metadata","description":"The published gem on RubyGems is missing the Changelog link. Add changelog_uri to spec.metadata in evilution.gemspec pointing to CHANGELOG.md on master.","status":"closed","priority":2,"issue_type":"bug","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-06T11:46:12.648668594+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-06T11:47:41.23691915+07:00","closed_at":"2026-03-06T11:47:41.23691915+07:00","close_reason":"Added changelog_uri to gemspec"}
53
53
  {"id":"EV-140","title":"Add setup_integration_pre/post hook points","description":"Fire hooks before and after the test integration is set up. Allows custom environment configuration before tests run.","status":"open","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:17:53.595178841+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:17:53.595178841+07:00","dependencies":[{"issue_id":"EV-140","depends_on_id":"EV-110","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
54
54
  {"id":"EV-141","title":"Epic: Pattern matching mutations (case/in)","description":"Add mutation operators for Ruby 3.x+ pattern matching expressions (case/in). Mutant mutates guards, alternatives, and predicates in pattern matching. Important as pattern matching adoption grows.","status":"open","priority":2,"issue_type":"feature","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:18:00.138078298+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:18:00.138078298+07:00"}
55
55
  {"id":"EV-142","title":"Implement []= removal mutation","description":"Create a mutator that removes []= (index assignment) statements. Tests whether the assignment is actually necessary.","status":"open","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:18:01.34824668+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:18:01.34824668+07:00","dependencies":[{"issue_id":"EV-142","depends_on_id":"EV-131","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
56
- {"id":"EV-143","title":"Add --no-progress flag to disable progress bar","description":"Add CLI flag and config option to disable the progress bar for CI/piped environments where TTY detection might not work correctly.","status":"open","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:18:01.773000995+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:18:01.773000995+07:00","dependencies":[{"issue_id":"EV-143","depends_on_id":"EV-128","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
57
- {"id":"EV-144","title":"Add send vs public_send method swap","description":"Add a mutation that swaps send with public_send and vice versa. Tests whether the method visibility bypass is intentional.","status":"open","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:18:03.825429179+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:18:03.825429179+07:00","dependencies":[{"issue_id":"EV-144","depends_on_id":"EV-100","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
56
+ {"id":"EV-143","title":"Add --no-progress flag to disable progress bar","description":"Add CLI flag and config option to disable the progress bar for CI/piped environments where TTY detection might not work correctly.","status":"in_progress","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:18:01.773000995+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-29T19:30:09.471623389+07:00","dependencies":[{"issue_id":"EV-143","depends_on_id":"EV-128","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
57
+ {"id":"EV-144","title":"Add send vs public_send method swap","description":"Add a mutation that swaps send with public_send and vice versa. Tests whether the method visibility bypass is intentional.","status":"in_progress","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:18:03.825429179+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-29T13:54:46.379099536+07:00","dependencies":[{"issue_id":"EV-144","depends_on_id":"EV-100","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
58
58
  {"id":"EV-145","title":"Add hooks configuration to .evilution.yml","description":"Allow hooks to be specified in .evilution.yml config file. Support both inline Ruby blocks and file paths to Ruby scripts. Example: hooks: { worker_process_start: 'config/evilution_hooks.rb' }.","status":"open","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:18:04.207200619+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:18:04.207200619+07:00","dependencies":[{"issue_id":"EV-145","depends_on_id":"EV-110","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
59
59
  {"id":"EV-146","title":"Add RSpec suggestion templates for index access mutations","description":"Add concrete RSpec suggestion templates for survived index access mutations to the SuggestionReporter.","status":"open","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:18:11.229320728+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:18:11.229320728+07:00","dependencies":[{"issue_id":"EV-146","depends_on_id":"EV-131","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
60
60
  {"id":"EV-147","title":"Implement pattern matching guard mutation","description":"Mutate guard clauses in pattern matching (in pattern if guard). Mutations: remove guard (always match), negate guard. Prism in_node with guard.","status":"open","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:18:12.368560689+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:18:12.368560689+07:00","dependencies":[{"issue_id":"EV-147","depends_on_id":"EV-141","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
@@ -97,23 +97,23 @@
97
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"}]}
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
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"}
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":"open","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-23T11:20:09.50500441+07:00","dependencies":[{"issue_id":"EV-183","depends_on_id":"EV-178","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
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
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"}]}
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
- {"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":"open","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-23T11:20:21.178494367+07:00","dependencies":[{"issue_id":"EV-186","depends_on_id":"EV-178","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
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
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
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"}]}
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":"open","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-23T11:20:30.943382606+07:00","dependencies":[{"issue_id":"EV-189","depends_on_id":"EV-178","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
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
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"}]}
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
- {"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":"open","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-23T11:20:41.326339048+07:00","dependencies":[{"issue_id":"EV-192","depends_on_id":"EV-178","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
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
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"}]}
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
- {"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":"open","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-23T11:21:02.559769802+07:00","dependencies":[{"issue_id":"EV-195","depends_on_id":"EV-194","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
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
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"}
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":"open","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-23T11:21:13.978482592+07:00","dependencies":[{"issue_id":"EV-197","depends_on_id":"EV-194","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
116
- {"id":"EV-198","title":"Add RSpec suggestion templates for class/module mutations","description":"Add concrete suggestion templates for survived class/module mutations.","status":"open","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-23T11:21:23.284834592+07:00","dependencies":[{"issue_id":"EV-198","depends_on_id":"EV-194","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
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
+ {"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
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"}
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"}]}
@@ -134,8 +134,8 @@
134
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
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"}
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
- {"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":"open","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-23T11:22:20.07787144+07:00","dependencies":[{"issue_id":"EV-204","depends_on_id":"EV-203","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
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":"open","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-23T11:22:31.543822152+07:00","dependencies":[{"issue_id":"EV-205","depends_on_id":"EV-203","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
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
+ {"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"}]}
139
139
  {"id":"EV-206","title":"Epic: MCP server enhancements","description":"Enhance the MCP server with session history browsing, cross-run diffs, and test suggestion streaming. MCP integration is Evilution's unique competitive advantage — investing here widens the moat.","status":"open","priority":3,"issue_type":"feature","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:22:41.847761146+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:22:41.847761146+07:00"}
140
140
  {"id":"EV-207","title":"Add session history browsing to MCP server","description":"Add MCP tools for listing and viewing past session results. Enables AI agents to review mutation testing history without CLI.","status":"in_progress","priority":3,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:22:50.697338124+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-28T01:23:57.262720975+07:00","dependencies":[{"issue_id":"EV-207","depends_on_id":"EV-206","type":"blocks","created_at":"0001-01-01T00:00:00Z"},{"issue_id":"EV-207","depends_on_id":"EV-150","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
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"}]}
@@ -278,11 +278,11 @@
278
278
  {"id":"EV-9","title":"Add multi-Ruby CI test matrix (3.2, 3.3, 4.0)","description":"CI currently only tests Ruby 4.0.1. Add a matrix strategy testing Ruby 3.2, 3.3, and 4.0 to ensure compatibility across supported Ruby versions. Prism ships with Ruby 3.3+ so 3.2 may need the prism gem as a dependency.","status":"closed","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-02T16:21:51.239774764+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-05T12:31:51.83181612+07:00","closed_at":"2026-03-05T12:31:51.83181612+07:00","close_reason":"Closed"}
279
279
  {"id":"EV-90","title":"Implement bitwise compound assignment mutator (&=, |=, ^=, <<=, >>=)","description":"Create mutations that swap bitwise compound assignment operators with each other. These are Prism op_asgn nodes with bitwise operator tokens.","status":"closed","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:15:49.296076429+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T16:41:58.956765738+07:00","closed_at":"2026-03-23T16:41:58.956765738+07:00","close_reason":"PR merged. Added bitwise compound assignment mutations (&=, |=, ^=, <<=, >>=) to CompoundAssignment mutator.","dependencies":[{"issue_id":"EV-90","depends_on_id":"EV-86","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
280
280
  {"id":"EV-91","title":"Epic: Break/next/redo control flow mutations","description":"Add mutations for break, next, and redo statements. Mutant mutates these control flow interrupts (swap break/next, remove redo, mutate break/next values). Important for testing loop behavior. Evilution has none.","status":"open","priority":2,"issue_type":"feature","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:15:52.890173894+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:15:52.890173894+07:00"}
281
- {"id":"EV-92","title":"Implement local variable assignment removal mutator","description":"Create a mutator that removes local variable assignments (lvasgn nodes), keeping only the value expression or removing the entire statement. Follow existing statement deletion patterns.","status":"open","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:15:54.68007817+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:15:54.68007817+07:00","dependencies":[{"issue_id":"EV-92","depends_on_id":"EV-87","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
281
+ {"id":"EV-92","title":"Implement local variable assignment removal mutator","description":"Create a mutator that removes local variable assignments (lvasgn nodes), keeping only the value expression or removing the entire statement. Follow existing statement deletion patterns.","status":"in_progress","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:15:54.68007817+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-29T01:05:19.57588682+07:00","dependencies":[{"issue_id":"EV-92","depends_on_id":"EV-87","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
282
282
  {"id":"EV-93","title":"Implement logical compound assignment mutator (&&=, ||=)","description":"Create mutations that swap &&= with ||= and vice versa. These are Prism and_asgn/or_asgn nodes, distinct from op_asgn.","status":"closed","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:15:59.501149639+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T16:57:19.169563553+07:00","closed_at":"2026-03-23T16:57:19.169563553+07:00","close_reason":"PR #363 merged. Added &&= and ||= swap mutations for all variable types.","dependencies":[{"issue_id":"EV-93","depends_on_id":"EV-86","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
283
- {"id":"EV-94","title":"Implement break statement mutator","description":"Create a mutator for break statements. Mutations: remove break (let loop continue), replace break value with nil, swap break with next. Prism break_node.","status":"open","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:16:05.462729749+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:16:05.462729749+07:00","dependencies":[{"issue_id":"EV-94","depends_on_id":"EV-91","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
284
- {"id":"EV-95","title":"Implement instance variable mutation","description":"Create a mutator for instance variable writes (@ivar = val). Mutations: remove assignment, replace value with nil. Prism instance_variable_write_node.","status":"open","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:16:07.10678859+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:16:07.10678859+07:00","dependencies":[{"issue_id":"EV-95","depends_on_id":"EV-87","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
283
+ {"id":"EV-94","title":"Implement break statement mutator","description":"Create a mutator for break statements. Mutations: remove break (let loop continue), replace break value with nil, swap break with next. Prism break_node.","status":"in_progress","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:16:05.462729749+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-29T10:58:26.095710774+07:00","dependencies":[{"issue_id":"EV-94","depends_on_id":"EV-91","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
284
+ {"id":"EV-95","title":"Implement instance variable mutation","description":"Create a mutator for instance variable writes (@ivar = val). Mutations: remove assignment, replace value with nil. Prism instance_variable_write_node.","status":"in_progress","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:16:07.10678859+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-29T01:10:37.845543866+07:00","dependencies":[{"issue_id":"EV-95","depends_on_id":"EV-87","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
285
285
  {"id":"EV-96","title":"Epic: Expand collection method swap pairs","description":"Add more orthogonal method swap pairs to close the gap with Mutant's 20+ pairs. Evilution has 14 pairs; needs 6+ more covering common Ruby collection methods.","status":"open","priority":2,"issue_type":"feature","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:16:07.686812036+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:16:07.686812036+07:00"}
286
286
  {"id":"EV-97","title":"Add compound assignment to removal mutator","description":"Extend the compound assignment mutators to also generate a removal mutation (remove the entire compound assignment statement). Aligns with Mutant's statement deletion behavior.","status":"closed","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:16:15.098552795+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T17:02:39.203119113+07:00","closed_at":"2026-03-23T17:02:39.203119113+07:00","close_reason":"PR merged. Added removal mutations for all compound assignment types.","dependencies":[{"issue_id":"EV-97","depends_on_id":"EV-86","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
287
- {"id":"EV-98","title":"Implement next statement mutator","description":"Create a mutator for next statements. Mutations: remove next (let block continue), replace next value with nil, swap next with break. Prism next_node.","status":"open","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:16:16.638335477+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:16:16.638335477+07:00","dependencies":[{"issue_id":"EV-98","depends_on_id":"EV-91","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
288
- {"id":"EV-99","title":"Implement class variable mutation","description":"Create a mutator for class variable writes (@@cvar = val). Mutations: remove assignment, replace value with nil. Prism class_variable_write_node.","status":"open","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:16:15.967143759+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:16:15.967143759+07:00","dependencies":[{"issue_id":"EV-99","depends_on_id":"EV-87","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
287
+ {"id":"EV-98","title":"Implement next statement mutator","description":"Create a mutator for next statements. Mutations: remove next (let block continue), replace next value with nil, swap next with break. Prism next_node.","status":"in_progress","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:16:16.638335477+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-29T11:48:21.34281786+07:00","dependencies":[{"issue_id":"EV-98","depends_on_id":"EV-91","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
288
+ {"id":"EV-99","title":"Implement class variable mutation","description":"Create a mutator for class variable writes (@@cvar = val). Mutations: remove assignment, replace value with nil. Prism class_variable_write_node.","status":"in_progress","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:16:15.967143759+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-29T01:20:18.161043033+07:00","dependencies":[{"issue_id":"EV-99","depends_on_id":"EV-87","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
data/CHANGELOG.md CHANGED
@@ -1,5 +1,48 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.16.0] - 2026-03-29
4
+
5
+ ### Added
6
+
7
+ - **Variable mutation operators** — `LocalVariableAssignment`, `InstanceVariableWrite`, `ClassVariableWrite`, `GlobalVariableWrite` replace variable assignments with `nil` to test whether stored values are actually used (#394, #395, #396, #397)
8
+ - **Rescue/ensure mutation operators** — `RescueRemoval` removes rescue clauses, `RescueBodyReplacement` replaces rescue bodies with `nil`, `InlineRescue` removes inline `rescue` fallback values, `EnsureRemoval` removes ensure blocks (#399, #400, #401, #402)
9
+ - **Loop control mutation operators** — `BreakStatement`, `NextStatement`, `RedoStatement` remove loop control flow statements to test whether early exits and restarts are necessary (#404, #405, #406)
10
+ - **BangMethod operator** — swaps bang methods with their non-bang counterparts (`sort!` → `sort`, `map!` → `map`, etc.) to test whether in-place mutation semantics matter (#413)
11
+ - **Bitwise mutation operators** — `BitwiseReplacement` swaps `&`, `|`, `^` with each other; `BitwiseComplement` removes `~` or swaps it with unary minus (#416, #417)
12
+ - **Super call mutation operators** — `ZsuperRemoval` replaces implicit `super` with `nil`; `ExplicitSuperMutation` removes arguments, removes individual arguments, or replaces `super(args)` with implicit `super` (#419, #420)
13
+ - **CollectionReplacement expansions** — added method swap pairs: `pop`/`shift`, `push`/`unshift`, `each_key`/`each_value`, `assoc`/`rassoc`, `grep`/`grep_v`, `take`/`drop`, `min`/`max`, `min_by`/`max_by`, `compact`/`flatten`, `zip`/`product`, `first`/`last`, `keys`/`values` (#407, #408, #409, #410, #411, #412)
14
+ - **SendMutation expansions** — enumerable reduction method swaps (`reduce`/`inject`, `sum`/`count`, `tally`/`group_by`, etc.) and conversion method swaps (`to_s`/`to_i`/`to_f`/`to_a`/`to_h`) (#414, #415)
15
+ - **Suggestion templates** — concrete RSpec suggestion templates for variable mutations, rescue/ensure mutations, bitwise mutations, and super call mutations (#398, #403, #418, #421)
16
+ - **TTY progress bar** — real-time progress display showing `[=====> ] 45/100 mutations | 38 killed | 2 survived | 00:23 elapsed | ~00:28 remaining`; TTY-aware rendering (carriage return for TTY, newlines for piped output); integrated into Runner for both sequential and parallel execution (#422, #423)
17
+ - **`--no-progress` flag** — CLI flag and config option to disable the progress bar for CI/piped environments (#424)
18
+
19
+ ### Changed
20
+
21
+ - **Operator count** — 46 operators (up from 30), covering variables, rescue/ensure, loop control, bang methods, bitwise operators, and super calls
22
+ - **Runner refactoring** — extracted `notify_result` method for unified result callbacks, progress bar updates, and diagnostic logging across sequential and parallel execution modes
23
+
24
+ ## [0.15.0] - 2026-03-29
25
+
26
+ ### Added
27
+
28
+ - **SuperclassRemoval operator** — mutates `class Foo < Bar` to `class Foo` (removes inheritance) to test whether the superclass is actually needed (#342)
29
+ - **MixinRemoval operator** — removes `include`, `extend`, and `prepend` statements individually to test whether each mixin is actually used; supports both class and module scopes (#343)
30
+ - **Suggestion templates for class/module mutations** — static and concrete RSpec suggestion templates for `superclass_removal` and `mixin_removal` operators (#344)
31
+ - **Namespace wildcard matching** (`Foo::Bar*`) — `--target` now supports trailing `*` to match all classes under a namespace prefix (#329)
32
+ - **Method-type selectors** (`Foo#`, `Foo.`) — `--target` now supports `Foo#` for all instance methods and `Foo.` for all class methods; class methods (`def self.foo`) are now captured by the parser with `.` separator (#332)
33
+ - **Descendant matching** (`descendants:Foo`) — `--target` now supports inheritance-based filtering via `Evilution::AST::InheritanceScanner` Prism visitor (#335)
34
+ - **Source glob matching** (`source:lib/**/*.rb`) — `--target` now supports file glob patterns (#338)
35
+ - **CommentMarking heuristic** — `# evilution:equivalent` inline comment marks mutations as equivalent (#384)
36
+ - **ArithmeticIdentity heuristic** — detects equivalent mutations for arithmetic identity operations like `x + 0`, `x * 1`, `x ** 1` (#383)
37
+ - **AliasSwap heuristic expansion** — added `count`/`length` and `detect`/`find` alias pairs for `collection_replacement` operator (#384)
38
+
39
+ ### Changed
40
+
41
+ - **Operator count** — 30 operators (up from 28), with new structural mutation operators for class/module definitions
42
+ - **Parse tree caching** — shared parse cache on `Mutator::Base` for structural operators, cleared after each run to prevent unbounded memory growth
43
+ - **Class method support in parser** — `AST::Parser` now distinguishes instance methods (`Foo#bar`) from class methods (`Foo.bar`) via Prism's `DefNode#receiver`
44
+ - **Descendant filter** — uses `/[#.]/` split to include both instance and class methods in inheritance-based matching
45
+
3
46
  ## [0.14.0] - 2026-03-28
4
47
 
5
48
  ### Added
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "prism"
4
+
5
+ require_relative "../ast"
6
+
7
+ class Evilution::AST::InheritanceScanner < Prism::Visitor
8
+ attr_reader :inheritance
9
+
10
+ def initialize
11
+ @inheritance = {}
12
+ @context = []
13
+ super
14
+ end
15
+
16
+ def self.call(files)
17
+ scanner = new
18
+ files.each do |file|
19
+ source = File.read(file)
20
+ result = Prism.parse(source)
21
+ next if result.failure?
22
+
23
+ scanner.visit(result.value)
24
+ rescue SystemCallError
25
+ next
26
+ end
27
+ scanner.inheritance
28
+ end
29
+
30
+ def visit_class_node(node)
31
+ class_name = qualified_name(node.constant_path)
32
+
33
+ @inheritance[class_name] = (qualified_superclass(node.superclass) if node.superclass)
34
+
35
+ @context.push(constant_name(node.constant_path))
36
+ super
37
+ @context.pop
38
+ end
39
+
40
+ def visit_module_node(node)
41
+ @context.push(constant_name(node.constant_path))
42
+ super
43
+ @context.pop
44
+ end
45
+
46
+ private
47
+
48
+ def qualified_name(node)
49
+ name = constant_name(node)
50
+ @context.empty? ? name : "#{@context.join("::")}::#{name}"
51
+ end
52
+
53
+ def qualified_superclass(node)
54
+ name = constant_name(node)
55
+ return name if name.include?("::")
56
+ return name if @context.empty?
57
+
58
+ "#{@context.join("::")}::#{name}"
59
+ end
60
+
61
+ def constant_name(node)
62
+ if node.respond_to?(:full_name)
63
+ node.full_name
64
+ elsif node.respond_to?(:name)
65
+ node.name.to_s
66
+ else
67
+ node.slice
68
+ end
69
+ end
70
+ end
@@ -54,11 +54,19 @@ module Evilution::AST
54
54
  end
55
55
 
56
56
  def visit_def_node(node)
57
+ separator = node.receiver ? "." : "#"
58
+ add_subject(node, separator)
59
+ super
60
+ end
61
+
62
+ private
63
+
64
+ def add_subject(node, separator)
57
65
  scope = @context.join("::")
58
66
  name = if scope.empty?
59
- "##{node.name}"
67
+ "#{separator}#{node.name}"
60
68
  else
61
- "#{scope}##{node.name}"
69
+ "#{scope}#{separator}#{node.name}"
62
70
  end
63
71
 
64
72
  loc = node.location
@@ -71,12 +79,8 @@ module Evilution::AST
71
79
  source: method_source,
72
80
  node: node
73
81
  )
74
-
75
- super
76
82
  end
77
83
 
78
- private
79
-
80
84
  def constant_name(node)
81
85
  if node.respond_to?(:full_name)
82
86
  node.full_name
data/lib/evilution/cli.rb CHANGED
@@ -146,7 +146,11 @@ class Evilution::CLI
146
146
  def add_filter_options(opts)
147
147
  opts.on("--min-score FLOAT", Float, "Minimum mutation score to pass") { |s| @options[:min_score] = s }
148
148
  opts.on("--spec FILES", Array, "Spec files to run (comma-separated)") { |f| @options[:spec_files] = f }
149
- opts.on("--target METHOD", "Only mutate the named method (e.g. Foo::Bar#calculate)") { |m| @options[:target] = m }
149
+ opts.on("--target EXPR",
150
+ "Filter: method (Foo#bar), type (Foo#/Foo.), namespace (Foo*),",
151
+ "class (Foo), glob (source:**/*.rb), hierarchy (descendants:Foo)") do |m|
152
+ @options[:target] = m
153
+ end
150
154
  end
151
155
 
152
156
  def add_flag_options(opts)
@@ -157,6 +161,7 @@ class Evilution::CLI
157
161
  opts.on("--isolation STRATEGY", "Isolation: auto, fork, in_process (default: auto)") { |s| @options[:isolation] = s }
158
162
  opts.on("--stdin", "Read target file paths from stdin (one per line)") { @options[:stdin] = true }
159
163
  opts.on("--suggest-tests", "Generate concrete RSpec test code in suggestions") { @options[:suggest_tests] = true }
164
+ opts.on("--no-progress", "Disable progress bar") { @options[:progress] = false }
160
165
  opts.on("--save-session", "Save session results to .evilution/results/") { @options[:save_session] = true }
161
166
  opts.on("-v", "--verbose", "Verbose output") { @options[:verbose] = true }
162
167
  opts.on("-q", "--quiet", "Suppress output") { @options[:quiet] = true }
@@ -19,6 +19,7 @@ class Evilution::Config
19
19
  isolation: :auto,
20
20
  incremental: false,
21
21
  suggest_tests: false,
22
+ progress: true,
22
23
  save_session: false,
23
24
  line_ranges: {},
24
25
  spec_files: []
@@ -27,7 +28,7 @@ class Evilution::Config
27
28
  attr_reader :target_files, :timeout, :format,
28
29
  :target, :min_score, :integration, :verbose, :quiet,
29
30
  :jobs, :fail_fast, :baseline, :isolation, :incremental, :suggest_tests,
30
- :save_session, :line_ranges, :spec_files
31
+ :progress, :save_session, :line_ranges, :spec_files
31
32
 
32
33
  def initialize(**options)
33
34
  file_options = options.delete(:skip_config_file) ? {} : load_config_file
@@ -72,6 +73,10 @@ class Evilution::Config
72
73
  suggest_tests
73
74
  end
74
75
 
76
+ def progress?
77
+ progress
78
+ end
79
+
75
80
  def save_session?
76
81
  save_session
77
82
  end
@@ -148,6 +153,7 @@ class Evilution::Config
148
153
  @isolation = validate_isolation(merged[:isolation])
149
154
  @incremental = merged[:incremental]
150
155
  @suggest_tests = merged[:suggest_tests]
156
+ @progress = merged[:progress]
151
157
  @save_session = merged[:save_session]
152
158
  @line_ranges = merged[:line_ranges] || {}
153
159
  @spec_files = Array(merged[:spec_files])