evilution 0.12.0 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 66bf48cbfe57daab8f06f98ace9a49b733e0143ae9c3e5e4c5fb516f465b30d7
4
- data.tar.gz: d021601a2e2256e1c846f55c355845aaacfb8435116873f3c1d74c0e5d7dda33
3
+ metadata.gz: 36f21d98f9e9e791ae8876b416b88ecc55ac6f2503ab1841591f528a5901a463
4
+ data.tar.gz: b9a32a1147ae03ad7cc0b81ad3b10cfee74376de195dbd67170e50aa484c8992
5
5
  SHA512:
6
- metadata.gz: 731b85019e5571ddfd8d72904a8303f231c8ba6d5dac1c27782e1dbf11943d55be4d8796382e3bb49b20a719755b0690e2305076b9a42dfe7080103ac88252f0
7
- data.tar.gz: e5d61aa19eeea415a19f7ab4ea98e09682de65a7694315a82a2989e31d874f176c22e58103a462055c5a73ed29f5f82d5136e26134cc74907cbbc5151dee0541
6
+ metadata.gz: eb819003413795c1cc25a257ef93a505cdf0f5975059340fd85ab228eb13e94e63f75e856179d17bbc264a04e93044d265454156518d7121cab26faed67c14ae
7
+ data.tar.gz: 3e5991bbb1c4b3b6f0c94105ba78a6c01ea74561f9c3cb7757ffae52682a414af8369598e919825203e824f538a9055721df4d8072f59977259e08a1080a28b4
@@ -1 +1 @@
1
- 1774149286
1
+ 1774239252
data/.beads/issues.jsonl CHANGED
@@ -6,15 +6,115 @@
6
6
  {"id":"EV-1.5","title":"Update gemspec metadata","description":"Fill in summary, description, homepage, source_code_uri, changelog_uri. Add runtime dependency: diff-lcs (>= 1.5, < 3). Set allowed_push_host to rubygems.org.","status":"closed","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-02T00:05:17.756448433+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-02T10:41:47.168270415+07:00","closed_at":"2026-03-02T10:41:47.168270415+07:00","close_reason":"Closed","dependencies":[{"issue_id":"EV-1.5","depends_on_id":"EV-1","type":"parent-child","created_at":"0001-01-01T00:00:00Z"}]}
7
7
  {"id":"EV-1.6","title":"Update .rubocop.yml for gem conventions","description":"Configure rubocop for gem: enable NewCops, set reasonable line length, exclude spec fixtures.","status":"closed","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-02T00:05:17.855784448+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-02T10:42:03.456572349+07:00","closed_at":"2026-03-02T10:42:03.456572349+07:00","close_reason":"Closed","dependencies":[{"issue_id":"EV-1.6","depends_on_id":"EV-1","type":"parent-child","created_at":"0001-01-01T00:00:00Z"}]}
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
+ {"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
+ {"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"}]}
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
+ {"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"}]}
9
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
+ {"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"}]}
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"}]}
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"}]}
10
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"}]}
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"}]}
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"}]}
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"}]}
11
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
+ {"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
+ {"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"}]}
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"}]}
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"}]}
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"}]}
12
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
+ {"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
+ {"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
+ {"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"}]}
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
+ {"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
+ {"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"}]}
61
+ {"id":"EV-148","title":"Session recording and history","description":"Store JSON results per run in .evilution/results/ with CLI commands to list, show, and garbage-collect past sessions. Mutant v1.0.0 has this. Enables trend analysis and regression detection across runs.","status":"open","priority":2,"issue_type":"feature","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:18:13.658761141+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:18:13.658761141+07:00"}
62
+ {"id":"EV-149","title":"Add RSpec tests for hooks system","description":"Comprehensive test coverage for the hooks system: registration, dispatch, error isolation, configuration loading, all hook points firing at correct times.","status":"open","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:18:16.004153638+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:18:16.004153638+07:00","dependencies":[{"issue_id":"EV-149","depends_on_id":"EV-110","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
13
63
  {"id":"EV-15","title":"Add line-range targeting (file:line-line syntax)","description":"Parse line-range syntax in CLI, store in Config, filter subjects in Runner. GH #29.","status":"closed","priority":2,"issue_type":"feature","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-08T00:36:29.164188342+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-08T00:38:02.739833414+07:00","closed_at":"2026-03-08T00:38:02.739833414+07:00","close_reason":"Implemented line-range targeting in CLI, Config, and Runner with full test coverage"}
64
+ {"id":"EV-150","title":"Implement session result storage","description":"After each mutation run, save a JSON file to .evilution/results/<timestamp>-<hash>.json containing: run configuration, all mutation results, summary statistics, duration, and git context (branch, commit SHA).","status":"open","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:18:23.433170933+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:18:23.433170933+07:00","dependencies":[{"issue_id":"EV-150","depends_on_id":"EV-148","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
65
+ {"id":"EV-151","title":"Implement pattern matching alternative mutation","description":"Mutate pattern alternatives (in pat1 | pat2). Mutations: remove each alternative individually, swap order. Prism alternation_pattern_node.","status":"open","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:18:23.447046732+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:18:23.447046732+07:00","dependencies":[{"issue_id":"EV-151","depends_on_id":"EV-141","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
66
+ {"id":"EV-152","title":"Epic: Type-aware return value mutations","description":"Add mutations that replace return values with type-appropriate empty/zero values: Array→[], Hash→{}, String→\"\", Integer→0, Float→0.0, true→false. Mutant does this extensively; Evilution only does body→nil.","status":"open","priority":2,"issue_type":"feature","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:18:23.546834696+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:18:23.546834696+07:00"}
67
+ {"id":"EV-153","title":"Epic: Dynamic work allocation for parallel execution","description":"Replace static batch-based work distribution with a shared work queue for dynamic load balancing. Mutant uses a shared queue where workers pull the next mutation as they complete work. Evilution's current static batching can lead to uneven utilization when mutation execution times vary.","status":"open","priority":2,"issue_type":"feature","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:18:26.946371704+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:18:26.946371704+07:00"}
68
+ {"id":"EV-154","title":"Implement type-aware return mutations for collection types","description":"When a method body returns an Array literal or Hash literal, also generate mutations returning the empty version ([] or {}). Detect by return value node type.","status":"open","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:18:31.525962391+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:18:31.525962391+07:00","dependencies":[{"issue_id":"EV-154","depends_on_id":"EV-152","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
69
+ {"id":"EV-155","title":"Implement pattern matching find/array pattern mutations","description":"Mutate find and array patterns: remove individual pattern elements, replace with wildcard (_). Prism find_pattern_node, array_pattern_node.","status":"open","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:18:33.136069529+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:18:33.136069529+07:00","dependencies":[{"issue_id":"EV-155","depends_on_id":"EV-141","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
70
+ {"id":"EV-156","title":"Add 'evilution session list' command","description":"Add a CLI subcommand that lists past session results with date, target, mutation count, score, and duration. Support --limit and --since filters.","status":"open","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:18:35.453549801+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:18:35.453549801+07:00","dependencies":[{"issue_id":"EV-156","depends_on_id":"EV-148","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
71
+ {"id":"EV-157","title":"Implement shared work queue with pipe-based IPC","description":"Create a work queue that distributes mutations to worker processes dynamically. Use pipe-based IPC (or DRb) so workers pull the next mutation when ready, rather than receiving a pre-assigned batch.","status":"open","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:18:35.963687077+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:18:35.963687077+07:00","dependencies":[{"issue_id":"EV-157","depends_on_id":"EV-153","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
72
+ {"id":"EV-158","title":"Implement type-aware return mutations for scalar types","description":"When a method body returns a String, Integer, or Float literal, also generate mutations returning the zero/empty value ('', 0, 0.0). Detect by return value node type.","status":"open","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:18:43.59763546+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:18:43.59763546+07:00","dependencies":[{"issue_id":"EV-158","depends_on_id":"EV-152","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
73
+ {"id":"EV-159","title":"Add RSpec suggestion templates for pattern matching mutations","description":"Add concrete RSpec suggestion templates for survived pattern matching mutations.","status":"open","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:18:45.083995741+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:18:45.083995741+07:00","dependencies":[{"issue_id":"EV-159","depends_on_id":"EV-141","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
14
74
  {"id":"EV-16","title":"Remove file-discovery logic from Integration::RSpec (GH #33)","description":"Integration::RSpec has detect_test_files, spec_file_candidates, and fallback_spec_dir that guess which specs to run. With precise targeting, agents can pass spec files directly. Simplify or remove this guessing logic, possibly adding a --spec flag.","status":"closed","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-08T19:17:27.268579626+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-09T18:13:46.899195957+07:00","closed_at":"2026-03-09T18:13:46.899195957+07:00","close_reason":"Completed via PR #38 (tracked as EV-17)"}
75
+ {"id":"EV-160","title":"Add 'evilution session show' command","description":"Add a CLI subcommand that displays the full report for a specific past session, including all survived mutations with diffs.","status":"open","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:18:45.851348485+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:18:45.851348485+07:00","dependencies":[{"issue_id":"EV-160","depends_on_id":"EV-148","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
76
+ {"id":"EV-161","title":"Add work-stealing for idle workers","description":"When a worker's local queue is empty, allow it to pull work from the shared queue immediately rather than waiting. Track per-worker completion rates for monitoring.","status":"open","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:18:47.426119432+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:18:47.426119432+07:00","dependencies":[{"issue_id":"EV-161","depends_on_id":"EV-153","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
77
+ {"id":"EV-162","title":"Add RSpec suggestion templates for type-aware return mutations","description":"Add concrete RSpec suggestion templates for survived type-aware return mutations to the SuggestionReporter.","status":"open","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:18:53.50501093+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:18:53.50501093+07:00","dependencies":[{"issue_id":"EV-162","depends_on_id":"EV-152","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
78
+ {"id":"EV-163","title":"Add 'evilution session gc' command","description":"Add a CLI subcommand to garbage-collect old session results. Support --older-than flag (e.g., --older-than 30d). Default to keeping all results.","status":"open","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:18:56.398453511+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:18:56.398453511+07:00","dependencies":[{"issue_id":"EV-163","depends_on_id":"EV-148","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
79
+ {"id":"EV-164","title":"Epic: AST pattern language for ignore_patterns","description":"Implement a pattern language for ignore_patterns configuration, similar to Mutant's (e.g., send{selector=log}, send{receiver=send{selector=logger}}). Allows precise, semantic exclusion of mutations on logging, debugging, or infrastructure code without requiring file/line targeting.","status":"open","priority":2,"issue_type":"feature","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:18:56.583664516+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:18:56.583664516+07:00"}
80
+ {"id":"EV-165","title":"Update Parallel::Pool to use dynamic queue","description":"Refactor Parallel::Pool to use the new dynamic work queue instead of static batch distribution. Maintain backward compatibility with the existing API (results should be identical, just better distributed).","status":"open","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:18:57.644578151+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:18:57.644578151+07:00","dependencies":[{"issue_id":"EV-165","depends_on_id":"EV-153","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
81
+ {"id":"EV-166","title":"Design AST pattern language syntax","description":"Design the pattern matching DSL syntax for ignore_patterns. Support at minimum: node type matching, attribute matching (selector, receiver), nested patterns, and wildcards. Document the syntax with examples.","status":"open","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:19:04.486430975+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:19:04.486430975+07:00","dependencies":[{"issue_id":"EV-166","depends_on_id":"EV-164","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
82
+ {"id":"EV-167","title":"Add efficiency metrics to summary output","description":"Add killtime/runtime efficiency percentage and mutations/second rate to the summary output. Mutant reports these. Helps users understand mutation testing overhead and optimize configuration. Calculate: efficiency = (time spent in test execution / total runtime) * 100%, rate = total_mutations / total_seconds.","status":"open","priority":3,"issue_type":"feature","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:19:10.074542778+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:19:10.074542778+07:00"}
83
+ {"id":"EV-168","title":"Add parallel execution metrics","description":"Track and report per-worker mutation counts, idle time, and utilization percentage. Include in verbose output to help users tune their --jobs setting.","status":"open","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:19:11.84738201+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:19:11.84738201+07:00","dependencies":[{"issue_id":"EV-168","depends_on_id":"EV-153","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
84
+ {"id":"EV-169","title":"Implement AST pattern parser","description":"Parse the pattern language strings into a matcher object that can be evaluated against Prism AST nodes. Support: node type (send, lvar), attribute filters ({selector=log}), nested matchers.","status":"open","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:19:15.548202079+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:19:15.548202079+07:00","dependencies":[{"issue_id":"EV-169","depends_on_id":"EV-164","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
15
85
  {"id":"EV-17","title":"Remove file-discovery logic from Integration::RSpec","description":"Add --spec flag, simplify RSpec integration by removing detect_test_files heuristics. GH #33","status":"closed","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-09T00:41:29.880486333+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-09T00:43:21.229172712+07:00","closed_at":"2026-03-09T00:43:21.229172712+07:00","close_reason":"Removed ~60 lines of file-discovery logic from Integration::RSpec, added --spec CLI flag, spec_files config, and wired through Runner"}
86
+ {"id":"EV-170","title":"Environment diagnostic commands","description":"Add diagnostic/inspection commands similar to Mutant's environment tools. Helps users understand what Evilution sees before running a full mutation test.","status":"open","priority":3,"issue_type":"feature","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:19:19.537979519+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:19:19.537979519+07:00"}
87
+ {"id":"EV-171","title":"Integrate AST pattern filter with mutation generation","description":"Before generating mutations, check if the target AST node matches any ignore_pattern. Skip matching nodes. Report skipped count in summary.","status":"open","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:19:24.909224128+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:19:24.909224128+07:00","dependencies":[{"issue_id":"EV-171","depends_on_id":"EV-164","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
88
+ {"id":"EV-172","title":"Support # evilution:disable source comments","description":"Allow users to add # evilution:disable comments in source code to skip mutations for specific methods or lines. Mutant supports # mutant:disable for per-method opt-out. Should support: method-level (comment before def), line-level (inline comment), and block-level (disable/enable pairs).","status":"open","priority":2,"issue_type":"feature","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:19:25.957514857+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:19:25.957514857+07:00"}
89
+ {"id":"EV-173","title":"Add 'evilution environment show' command","description":"Display the resolved configuration: loaded config file, CLI overrides, effective values for all settings (jobs, target, integration, etc.).","status":"open","priority":3,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:19:30.633766429+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:19:30.633766429+07:00","dependencies":[{"issue_id":"EV-173","depends_on_id":"EV-170","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
90
+ {"id":"EV-174","title":"Implement comment-based disable detection","description":"Scan source files for # evilution:disable comments. Support three forms: method-level (comment on line before def), line-level (inline # evilution:disable), and range (# evilution:disable / # evilution:enable pairs). Store disabled ranges per file.","status":"open","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:19:35.174813233+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:19:35.174813233+07:00","dependencies":[{"issue_id":"EV-174","depends_on_id":"EV-172","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
91
+ {"id":"EV-175","title":"Add ignore_patterns to .evilution.yml config","description":"Add ignore_patterns as a config key in .evilution.yml. Accept an array of pattern strings. Example: ignore_patterns: ['send{selector=log}', 'send{receiver=send{selector=logger}}'].","status":"open","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:19:35.758598835+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:19:35.758598835+07:00","dependencies":[{"issue_id":"EV-175","depends_on_id":"EV-164","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
92
+ {"id":"EV-176","title":"Add 'evilution subjects' command","description":"List all subjects (classes/methods) that would be mutated for the given target. Shows what mutations would be generated without actually running tests.","status":"open","priority":3,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:19:44.530116644+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:19:44.530116644+07:00","dependencies":[{"issue_id":"EV-176","depends_on_id":"EV-170","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
93
+ {"id":"EV-177","title":"Filter mutations against disabled ranges","description":"Before generating mutations, check if the target source location falls within a disabled range. Skip mutation generation for disabled locations. Report skipped count in summary.","status":"open","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:19:46.006587202+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:19:46.006587202+07:00","dependencies":[{"issue_id":"EV-177","depends_on_id":"EV-172","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
94
+ {"id":"EV-178","title":"Epic: Rich subject expression language","description":"Implement a rich expression language for subject matching similar to Mutant's: namespace wildcards (Foo::Bar*), method-type selectors (Foo# for instance, Foo. for class methods), descendant matching (descendants:Foo). Currently Evilution supports method names and file paths but lacks wildcard and type selectors.","status":"open","priority":2,"issue_type":"feature","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:19:48.801608223+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:19:48.801608223+07:00"}
95
+ {"id":"EV-179","title":"Add --show-disabled flag to report disabled mutations","description":"Add a CLI flag that reports which mutations were skipped due to disable comments, so users can audit their disable annotations.","status":"open","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:19:56.450400314+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:19:56.450400314+07:00","dependencies":[{"issue_id":"EV-179","depends_on_id":"EV-172","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
16
96
  {"id":"EV-18","title":"Add method-name targeting (Class#method) (GH #30)","description":"Allow specifying a fully-qualified method name: evilution run Foo::Bar#calculate. Resolve name to file and line range, then mutate only that method. Lower priority since it requires name-to-file resolution which can be ambiguous with reopened classes or metaprogramming. Update README, --help, and CHANGELOG.","status":"closed","priority":3,"issue_type":"feature","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-09T23:49:31.827723147+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-16T10:11:01.311634237+07:00","closed_at":"2026-03-16T10:11:01.311634237+07:00","close_reason":"Already merged and released in v0.4.0"}
97
+ {"id":"EV-180","title":"Add 'evilution tests list' command","description":"List all detected test files and test examples that would be run. Useful for verifying test discovery is working correctly.","status":"open","priority":3,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:19:56.667492485+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:19:56.667492485+07:00","dependencies":[{"issue_id":"EV-180","depends_on_id":"EV-170","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
98
+ {"id":"EV-181","title":"Sorbet type signature awareness for mutations","description":"Detect and unwrap Sorbet type signatures (sig { ... }) before mutation. Mutant automatically skips mutations inside sig blocks and handles typed codebases without special configuration. Evilution should skip sig blocks to avoid generating useless mutations on type annotations.","status":"open","priority":3,"issue_type":"feature","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:20:07.254888519+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:20:07.254888519+07:00"}
99
+ {"id":"EV-182","title":"Add 'evilution util mutation' preview command","description":"Add a utility command that previews mutations for a code snippet without running tests: evilution util mutation -e 'def foo; x + y; end'. Shows all mutations that would be generated. Mutant has this. Useful for understanding operator behavior and debugging mutation generation.","status":"open","priority":3,"issue_type":"feature","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:20:08.026842032+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:20:08.026842032+07:00"}
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"}]}
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
+ {"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"}]}
104
+ {"id":"EV-187","title":"Implement session result diffing engine","description":"Create a diff engine that compares two session result JSON files and produces: new mutations (in B but not A), removed mutations (in A but not B), status changes (killed→survived, survived→killed), and score delta.","status":"open","priority":3,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:20:26.707985667+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:20:26.707985667+07:00","dependencies":[{"issue_id":"EV-187","depends_on_id":"EV-185","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
105
+ {"id":"EV-188","title":"Skip mutation generation inside sig blocks","description":"Filter out any mutation whose source location falls within a Sorbet sig block. Report skipped count separately in verbose output.","status":"open","priority":3,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:20:28.716852636+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:20:28.716852636+07:00","dependencies":[{"issue_id":"EV-188","depends_on_id":"EV-181","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
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"}]}
17
107
  {"id":"EV-19","title":"Add method-name targeting (--target flag)","description":"Users can target a specific method for mutation testing via --target METHOD flag. Matches against Subject.name.","status":"closed","priority":2,"issue_type":"feature","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-10T00:09:57.091870734+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-10T00:10:02.637447023+07:00","closed_at":"2026-03-10T00:10:02.637447023+07:00","close_reason":"Implemented --target flag in CLI, Config.target? predicate, Runner.filter_by_target, README docs, and specs"}
108
+ {"id":"EV-190","title":"Add 'evilution session diff' CLI command","description":"Add CLI subcommand: evilution session diff <session-a> <session-b>. Output the comparison in a readable format with color-coded changes.","status":"open","priority":3,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:20:38.753251207+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:20:38.753251207+07:00","dependencies":[{"issue_id":"EV-190","depends_on_id":"EV-185","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
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"}]}
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
+ {"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"}]}
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"}]}
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"}
18
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"}
19
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"}]}
20
120
  {"id":"EV-2.10","title":"Implement Evilution::Integration::Base and RSpec adapter","description":"Base: abstract adapter with interface #call(test_files) -> {passed: bool, example_count: int, failure_count: int}. RSpec: programmatic runner using RSpec::Core::Runner.run with StringIO for capture. Auto-detects spec/ directory. Files: lib/evilution/integration/base.rb, lib/evilution/integration/rspec.rb + specs.","status":"closed","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-02T00:05:51.246990324+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-02T10:58:18.324768622+07:00","closed_at":"2026-03-02T10:58:18.324768622+07:00","close_reason":"Integration::Base and Integration::RSpec implemented with 8 passing specs","dependencies":[{"issue_id":"EV-2.10","depends_on_id":"EV-2","type":"parent-child","created_at":"0001-01-01T00:00:00Z"}]}
@@ -30,7 +130,20 @@
30
130
  {"id":"EV-2.8","title":"Implement Evilution::Result::MutationResult and Summary","description":"MutationResult: value object with fields: mutation, status (:killed/:survived/:timeout/:error), duration, killing_test (optional). Summary: aggregates MutationResult array into total/killed/survived/timed_out/errors/score/duration. Files: lib/evilution/result/mutation_result.rb, lib/evilution/result/summary.rb + specs.","status":"closed","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-02T00:05:51.022249568+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-02T10:51:08.482621898+07:00","closed_at":"2026-03-02T10:51:08.482621898+07:00","close_reason":"Closed","dependencies":[{"issue_id":"EV-2.8","depends_on_id":"EV-2","type":"parent-child","created_at":"0001-01-01T00:00:00Z"}]}
31
131
  {"id":"EV-2.9","title":"Implement Evilution::Isolation::Fork","description":"Fork-based process isolation. Method: run(mutation, test_command, timeout:) -> MutationResult. Flow: create pipe, fork child, child applies mutation via eval, child runs test command, marshal result back via pipe, parent reads with IO.select timeout, SIGKILL on deadline. File: lib/evilution/isolation/fork.rb + spec.","status":"closed","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-02T00:05:51.142167275+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-02T10:54:08.819310594+07:00","closed_at":"2026-03-02T10:54:08.819310594+07:00","close_reason":"Fork isolation implemented with 6 passing specs","dependencies":[{"issue_id":"EV-2.9","depends_on_id":"EV-2","type":"parent-child","created_at":"0001-01-01T00:00:00Z"},{"issue_id":"EV-2.9","depends_on_id":"EV-2.8","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
32
132
  {"id":"EV-20","title":"Deprecate coverage filtering","description":"With line-range and method-name targeting, coverage collection adds overhead for little benefit. Deprecate --no-coverage flag, coverage config key, and remove coverage logic from runner.","status":"closed","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-10T00:30:58.837659684+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-10T00:33:06.453669976+07:00","closed_at":"2026-03-10T00:33:06.453669976+07:00","close_reason":"Deprecated coverage filtering: CLI warns on --no-coverage, config warns on coverage key, runner no longer uses coverage logic"}
133
+ {"id":"EV-200","title":"Implement multiple assignment (masgn) mutations","description":"Add mutations for destructuring/parallel assignment (a, b = 1, 2). Mutations: remove individual assignment targets, swap assignment order, reduce to single assignment. Prism multi_write_node.","status":"open","priority":3,"issue_type":"feature","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:21:44.259585319+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:21:44.259585319+07:00"}
134
+ {"id":"EV-201","title":"Implement yield statement mutations","description":"Add mutations for yield statements. Mutations: remove yield, remove yield arguments, replace yield value with nil. Prism yield_node.","status":"open","priority":3,"issue_type":"feature","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:21:53.437749245+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:21:53.437749245+07:00"}
135
+ {"id":"EV-202","title":"Implement splat operator mutations","description":"Add mutations for splat (*) and double-splat (**) operators. Mutations: remove splat (pass array directly), remove double-splat (pass hash directly). Prism splat_node, assoc_splat_node.","status":"open","priority":3,"issue_type":"feature","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:22:01.958187896+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:22:01.958187896+07:00"}
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"}]}
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
+ {"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":"open","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-23T11:22:50.697338124+07:00","dependencies":[{"issue_id":"EV-207","depends_on_id":"EV-206","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
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":"open","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-23T11:23:00.558002099+07:00","dependencies":[{"issue_id":"EV-208","depends_on_id":"EV-206","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
142
+ {"id":"EV-209","title":"Add streaming test suggestions via MCP","description":"Stream test suggestions for survived mutations via MCP as they are generated, rather than waiting for the full run to complete.","status":"open","priority":3,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:23:10.316219498+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:23:10.316219498+07:00","dependencies":[{"issue_id":"EV-209","depends_on_id":"EV-206","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
33
143
  {"id":"EV-21","title":"Epic: Speed & Performance","description":"Reduce mutation testing wall-clock time for fast agent feedback loops. Includes fail-fast, parallel execution, and per-mutation spec targeting.","status":"closed","priority":1,"issue_type":"feature","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-10T06:17:26.608316104+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-16T14:49:23.063583958+07:00","closed_at":"2026-03-16T14:49:23.063583958+07:00","close_reason":"All children complete: fail-fast, per-mutation spec targeting","dependencies":[{"issue_id":"EV-21","depends_on_id":"EV-22","type":"blocks","created_at":"0001-01-01T00:00:00Z"},{"issue_id":"EV-21","depends_on_id":"EV-23","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
144
+ {"id":"EV-210","title":"Implement defined? check mutations","description":"Add mutation for defined?(expr) → true. Tests whether the defined? check is actually needed. Prism defined_node.","status":"open","priority":4,"issue_type":"feature","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:23:22.128405637+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:23:22.128405637+07:00"}
145
+ {"id":"EV-211","title":"Implement regex capture reference (, ) mutations","description":"Add mutations for numbered regex capture references ($1, $2, etc.). Mutations: swap capture numbers ($1↔$2), replace with nil. Prism numbered_reference_read_node.","status":"open","priority":4,"issue_type":"feature","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:23:30.659728763+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:23:30.659728763+07:00"}
146
+ {"id":"EV-212","title":"Implement self reference mutations","description":"Add mutations for self references. Mutations: remove self where it's used as an explicit receiver (self.foo → foo). Prism self_node.","status":"open","priority":4,"issue_type":"feature","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:23:42.173027795+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:23:42.173027795+07:00"}
34
147
  {"id":"EV-22","title":"Add --fail-fast flag with survivor threshold","description":"Add --fail-fast [N] CLI flag and fail_fast config option to stop mutation testing after N surviving mutants (default N=1 when flag given without value). Agents fix gaps iteratively, so discovering all survivors upfront is wasted work. A threshold gives control over the speed/thoroughness tradeoff: --fail-fast 1 for quick checks, --fail-fast 5 for CI gates, omit for full scans. Runner#call should stop running mutations and return a partial Summary once the threshold is reached. JSON output should include a 'truncated: true' field when fail-fast triggered.","status":"closed","priority":2,"issue_type":"feature","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-10T06:17:28.018733235+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-16T10:11:01.311500554+07:00","closed_at":"2026-03-16T10:11:01.311500554+07:00","close_reason":"Already merged and released in v0.4.0"}
35
148
  {"id":"EV-23","title":"Per-mutation spec targeting","description":"Instead of running the full spec suite for every mutation, map each mutated source file to its relevant spec file(s) using convention-based resolution (e.g. lib/foo/bar.rb -> spec/foo/bar_spec.rb) and only run those. This dramatically reduces per-mutation test time. Depends on convention-based spec file resolution being implemented first.","status":"closed","priority":2,"issue_type":"feature","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-10T06:17:28.98620973+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-16T14:49:13.616876819+07:00","closed_at":"2026-03-16T14:49:13.616876819+07:00","close_reason":"Fixed and merged","dependencies":[{"issue_id":"EV-23","depends_on_id":"EV-34","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
36
149
  {"id":"EV-24","title":"Epic: JSON Output Improvements","description":"Make JSON output fully machine-parseable in all scenarios, including errors. Add diagnostic fields that help agents debug failures.","status":"closed","priority":1,"issue_type":"feature","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-10T06:17:37.450686472+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-16T11:15:24.900944562+07:00","closed_at":"2026-03-16T11:15:24.900944562+07:00","close_reason":"All children complete: structured errors, test_command in JSON, noise suppression","dependencies":[{"issue_id":"EV-24","depends_on_id":"EV-25","type":"blocks","created_at":"0001-01-01T00:00:00Z"},{"issue_id":"EV-24","depends_on_id":"EV-26","type":"blocks","created_at":"0001-01-01T00:00:00Z"},{"issue_id":"EV-24","depends_on_id":"EV-40","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
@@ -158,4 +271,18 @@
158
271
  {"id":"EV-83","title":"Plugin-based runner dispatch for test integrations","description":"Runner currently uses a case statement with only 'when :rspec'. Refactor to a registry/plugin mechanism that resolves the integration class from config.integration. Also update module loading in evilution.rb to conditionally require integrations.","notes":"GitHub issue: #228","status":"open","priority":3,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-22T17:28:40.5256819+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-22T17:28:54.689064249+07:00","dependencies":[{"issue_id":"EV-83","depends_on_id":"EV-69","type":"blocks","created_at":"0001-01-01T00:00:00Z"},{"issue_id":"EV-83","depends_on_id":"EV-78","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
159
272
  {"id":"EV-84","title":"Minitest concrete suggestion templates","description":"All 16 CONCRETE_TEMPLATES in Reporter::Suggestion generate RSpec it/expect blocks. Add parallel Minitest templates using assert_equal style. suggestion_for should select the right template set based on the configured integration.","notes":"GitHub issue: #229","status":"open","priority":3,"issue_type":"feature","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-22T17:28:41.5343649+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-22T17:28:59.242395265+07:00","dependencies":[{"issue_id":"EV-84","depends_on_id":"EV-69","type":"blocks","created_at":"0001-01-01T00:00:00Z"},{"issue_id":"EV-84","depends_on_id":"EV-79","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
160
273
  {"id":"EV-85","title":"Update documentation for Minitest support","description":"Update CLI help text, MCP tool descriptions, and README to reflect Minitest as a supported integration. Currently --suggest-tests and MCP tool explicitly say 'RSpec'. Make descriptions framework-aware or generic.","notes":"GitHub issue: #230","status":"open","priority":3,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-22T17:28:51.219728494+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-22T17:29:06.644497418+07:00","dependencies":[{"issue_id":"EV-85","depends_on_id":"EV-69","type":"blocks","created_at":"0001-01-01T00:00:00Z"},{"issue_id":"EV-85","depends_on_id":"EV-79","type":"blocks","created_at":"0001-01-01T00:00:00Z"},{"issue_id":"EV-85","depends_on_id":"EV-82","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
274
+ {"id":"EV-86","title":"Epic: Compound assignment operator mutations","description":"Add mutation operators for compound assignment expressions (+=, -=, *=, /=, %=, **=, &=, |=, ^=, <<=, >>=, &&=, ||=). Mutant supports all 12+ swaps; Evilution has none. This is the highest-impact missing operator category.","status":"closed","priority":2,"issue_type":"feature","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:15:23.191166178+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T17:07:23.690634548+07:00","closed_at":"2026-03-23T17:07:23.690634548+07:00","close_reason":"All 5 sub-issues complete. Compound assignment operator fully implemented with arithmetic, bitwise, logical swaps, removal mutations, and suggestion templates."}
275
+ {"id":"EV-87","title":"Epic: Variable mutations","description":"Add mutation operators for variable assignments and references (local, instance, class, global variables). Mutant mutates variable assignments (remove, swap values) and references (swap with other variables of same type in scope). Evilution has none.","status":"open","priority":2,"issue_type":"feature","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:15:33.213204188+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:15:33.213204188+07:00"}
276
+ {"id":"EV-88","title":"Implement arithmetic compound assignment mutator (+=, -=, *=, /=, %=, **=)","description":"Create a new mutator that swaps arithmetic compound assignment operators with each other (e.g., += becomes -=, *=, /=). Register in Mutator::Registry. Follow existing operator patterns like BinaryOperatorSwap.","status":"closed","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:15:37.132942691+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T14:27:41.923799202+07:00","closed_at":"2026-03-23T12:02:13.019996743+07:00","close_reason":"PR #361 merged. Implemented CompoundAssignment mutator for +=, -=, *=, /=, %=, **= across all variable types. 15 specs, 100% mutation score.","dependencies":[{"issue_id":"EV-88","depends_on_id":"EV-86","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
277
+ {"id":"EV-89","title":"Epic: Exception handling mutations","description":"Add mutation operators for rescue/ensure blocks. Mutant removes rescue clauses, mutates inline rescue, and removes ensure blocks. These are important for testing error handling paths. Evilution has none.","status":"open","priority":2,"issue_type":"feature","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-23T11:15:44.503025925+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-23T11:15:44.503025925+07:00"}
161
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
+ {"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
+ {"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"}]}
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"}]}
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
+ {"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"}]}
data/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.13.0] - 2026-03-23
4
+
5
+ ### Added
6
+
7
+ - **CompoundAssignment operator** — new mutation operator for compound assignment expressions; swaps arithmetic (`+=` ↔ `-=`, `*=` ↔ `/=`, `%=` → `*=`, `**=` → `*=`), bitwise (`&=` ↔ `|=`/`^=`, `<<=` ↔ `>>=`), and logical (`&&=` ↔ `||=`) compound assignments; also generates removal mutations (statement → `nil`); covers local, instance, class, and global variables (#234, #236, #239, #243)
8
+ - **Compound assignment suggestion templates** — concrete RSpec `it`-block suggestions for survived compound assignment mutations via `--suggest-tests` (#247)
9
+
10
+ ### Changed
11
+
12
+ - **Operator count** — 28 operators (up from 27), increasing mutation density for real-world Ruby code
13
+ - **Refactored IntegerLiteral mutation logic** and updated RuboCop configuration (#360)
14
+
3
15
  ## [0.12.0] - 2026-03-22
4
16
 
5
17
  ### Added
@@ -0,0 +1,123 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Evilution
4
+ module Mutator
5
+ module Operator
6
+ class CompoundAssignment < Base
7
+ REPLACEMENTS = {
8
+ :+ => %i[- *],
9
+ :- => [:+],
10
+ :* => [:/],
11
+ :/ => [:*],
12
+ :% => [:*],
13
+ :** => [:*],
14
+ :& => %i[| ^],
15
+ :| => [:&],
16
+ :^ => [:&],
17
+ :<< => [:>>],
18
+ :>> => [:<<]
19
+ }.freeze
20
+
21
+ def visit_local_variable_operator_write_node(node)
22
+ mutate_operator_write(node)
23
+ super
24
+ end
25
+
26
+ def visit_instance_variable_operator_write_node(node)
27
+ mutate_operator_write(node)
28
+ super
29
+ end
30
+
31
+ def visit_class_variable_operator_write_node(node)
32
+ mutate_operator_write(node)
33
+ super
34
+ end
35
+
36
+ def visit_global_variable_operator_write_node(node)
37
+ mutate_operator_write(node)
38
+ super
39
+ end
40
+
41
+ def visit_local_variable_and_write_node(node)
42
+ mutate_logical_write(node, "||=")
43
+ super
44
+ end
45
+
46
+ def visit_local_variable_or_write_node(node)
47
+ mutate_logical_write(node, "&&=")
48
+ super
49
+ end
50
+
51
+ def visit_instance_variable_and_write_node(node)
52
+ mutate_logical_write(node, "||=")
53
+ super
54
+ end
55
+
56
+ def visit_instance_variable_or_write_node(node)
57
+ mutate_logical_write(node, "&&=")
58
+ super
59
+ end
60
+
61
+ def visit_class_variable_and_write_node(node)
62
+ mutate_logical_write(node, "||=")
63
+ super
64
+ end
65
+
66
+ def visit_class_variable_or_write_node(node)
67
+ mutate_logical_write(node, "&&=")
68
+ super
69
+ end
70
+
71
+ def visit_global_variable_and_write_node(node)
72
+ mutate_logical_write(node, "||=")
73
+ super
74
+ end
75
+
76
+ def visit_global_variable_or_write_node(node)
77
+ mutate_logical_write(node, "&&=")
78
+ super
79
+ end
80
+
81
+ private
82
+
83
+ def mutate_logical_write(node, replacement)
84
+ loc = node.operator_loc
85
+ add_mutation(
86
+ offset: loc.start_offset,
87
+ length: loc.length,
88
+ replacement: replacement,
89
+ node: node
90
+ )
91
+ remove_statement(node)
92
+ end
93
+
94
+ def mutate_operator_write(node)
95
+ replacements = REPLACEMENTS[node.binary_operator]
96
+ return unless replacements
97
+
98
+ loc = node.binary_operator_loc
99
+
100
+ replacements.each do |replacement|
101
+ replacement_str = "#{replacement}="
102
+ add_mutation(
103
+ offset: loc.start_offset,
104
+ length: loc.length,
105
+ replacement: replacement_str,
106
+ node: node
107
+ )
108
+ end
109
+ remove_statement(node)
110
+ end
111
+
112
+ def remove_statement(node)
113
+ add_mutation(
114
+ offset: node.location.start_offset,
115
+ length: node.location.length,
116
+ replacement: "nil",
117
+ node: node
118
+ )
119
+ end
120
+ end
121
+ end
122
+ end
123
+ end
@@ -1,52 +1,24 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Evilution
4
- module Mutator
5
- module Operator
6
- class IntegerLiteral < Base
7
- def visit_integer_node(node)
8
- value = node.value
3
+ class Evilution::Mutator::Operator::IntegerLiteral < Evilution::Mutator::Base
4
+ def visit_integer_node(node)
5
+ if node.value.zero?
6
+ add_mutation_with_replacement(node, "1")
7
+ elsif node.value == 1
8
+ add_mutation_with_replacement(node, "0")
9
+ else
10
+ add_mutation_with_replacement(node, "0")
11
+ add_mutation_with_replacement(node, (node.value + 1).to_s)
12
+ end
9
13
 
10
- if value.zero?
11
- add_mutation(
12
- offset: node.location.start_offset,
13
- length: node.location.length,
14
- replacement: "1",
15
- node: node
16
- )
17
- elsif value == 1
18
- add_mutation(
19
- offset: node.location.start_offset,
20
- length: node.location.length,
21
- replacement: "0",
22
- node: node
23
- )
24
- else
25
- add_mutation(
26
- offset: node.location.start_offset,
27
- length: node.location.length,
28
- replacement: "0",
29
- node: node
30
- )
14
+ add_mutation_with_replacement(node, "nil")
31
15
 
32
- add_mutation(
33
- offset: node.location.start_offset,
34
- length: node.location.length,
35
- replacement: (node.value + 1).to_s,
36
- node: node
37
- )
38
- end
16
+ super
17
+ end
39
18
 
40
- add_mutation(
41
- offset: node.location.start_offset,
42
- length: node.location.length,
43
- replacement: "nil",
44
- node: node
45
- )
19
+ private
46
20
 
47
- super
48
- end
49
- end
50
- end
21
+ def add_mutation_with_replacement(node, replacement)
22
+ add_mutation(offset: node.location.start_offset, length: node.location.length, replacement:, node:)
51
23
  end
52
24
  end
@@ -32,7 +32,8 @@ module Evilution
32
32
  Operator::RegexpMutation,
33
33
  Operator::ReceiverReplacement,
34
34
  Operator::SendMutation,
35
- Operator::ArgumentNilSubstitution
35
+ Operator::ArgumentNilSubstitution,
36
+ Operator::CompoundAssignment
36
37
  ].each { |op| registry.register(op) }
37
38
  registry
38
39
  end
@@ -23,7 +23,8 @@ module Evilution
23
23
  "return_value_removal" => "Add a test that uses the return value of this method",
24
24
  "collection_replacement" => "Add a test that checks the return value of the collection operation, not just side effects",
25
25
  "method_call_removal" => "Add a test that depends on the return value or side effect of this method call",
26
- "argument_removal" => "Add a test that verifies the correct arguments are passed to this method call"
26
+ "argument_removal" => "Add a test that verifies the correct arguments are passed to this method call",
27
+ "compound_assignment" => "Add a test that verifies the side effect of this compound assignment (the accumulated value matters)"
27
28
  }.freeze
28
29
 
29
30
  CONCRETE_TEMPLATES = {
@@ -262,6 +263,20 @@ module Evilution
262
263
  end
263
264
  RSPEC
264
265
  },
266
+ "compound_assignment" => lambda { |mutation|
267
+ method_name = parse_method_name(mutation.subject.name)
268
+ original_line, mutated_line = extract_diff_lines(mutation.diff)
269
+ <<~RSPEC.strip
270
+ # Mutation: changed `#{original_line}` to `#{mutated_line}` in #{mutation.subject.name}
271
+ # #{mutation.file_path}:#{mutation.line}
272
+ it 'verifies the compound assignment side effect in ##{method_name}' do
273
+ # Assert the accumulated value after the compound assignment
274
+ # The mutation changes the operator, so the final value will differ
275
+ subject.#{method_name}(input_value)
276
+ expect(observable_side_effect).to eq(expected)
277
+ end
278
+ RSPEC
279
+ },
265
280
  "nil_replacement" => lambda { |mutation|
266
281
  method_name = parse_method_name(mutation.subject.name)
267
282
  original_line, mutated_line = extract_diff_lines(mutation.diff)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Evilution
4
- VERSION = "0.12.0"
4
+ VERSION = "0.13.0"
5
5
  end
data/lib/evilution.rb CHANGED
@@ -35,6 +35,7 @@ require_relative "evilution/mutator/operator/regexp_mutation"
35
35
  require_relative "evilution/mutator/operator/receiver_replacement"
36
36
  require_relative "evilution/mutator/operator/send_mutation"
37
37
  require_relative "evilution/mutator/operator/argument_nil_substitution"
38
+ require_relative "evilution/mutator/operator/compound_assignment"
38
39
  require_relative "evilution/mutator/registry"
39
40
  require_relative "evilution/equivalent/detector"
40
41
  require_relative "evilution/isolation/fork"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: evilution
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.12.0
4
+ version: 0.13.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Denis Kiselev
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-03-22 00:00:00.000000000 Z
11
+ date: 2026-03-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: diff-lcs
@@ -109,6 +109,7 @@ files:
109
109
  - lib/evilution/mutator/operator/boolean_operator_replacement.rb
110
110
  - lib/evilution/mutator/operator/collection_replacement.rb
111
111
  - lib/evilution/mutator/operator/comparison_replacement.rb
112
+ - lib/evilution/mutator/operator/compound_assignment.rb
112
113
  - lib/evilution/mutator/operator/conditional_branch.rb
113
114
  - lib/evilution/mutator/operator/conditional_flip.rb
114
115
  - lib/evilution/mutator/operator/conditional_negation.rb