evilution 1.2.0 → 1.4.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 +4 -4
- data/.beads/interactions.jsonl +100 -0
- data/.rubocop_todo.yml +14 -0
- data/CHANGELOG.md +124 -0
- data/README.md +142 -28
- data/docs/architecture.md +123 -9
- data/docs/ast_pattern_syntax.md +50 -5
- data/docs/isolation.md +39 -2
- data/docs/migration-from-mutant.md +1 -1
- data/lib/evilution/ast/aasm_declaration.rb +133 -0
- data/lib/evilution/ast/callback_declaration.rb +91 -0
- data/lib/evilution/ast/included_block.rb +27 -0
- data/lib/evilution/ast/literal_callable.rb +21 -0
- data/lib/evilution/ast/parser.rb +120 -16
- data/lib/evilution/ast/pattern/filter.rb +1 -0
- data/lib/evilution/ast/pattern/method_name.rb +63 -0
- data/lib/evilution/ast/pattern/parser.rb +15 -15
- data/lib/evilution/ast/pattern.rb +2 -0
- data/lib/evilution/ast/regexp_pattern.rb +104 -0
- data/lib/evilution/ast/scope_declaration.rb +45 -0
- data/lib/evilution/ast/sorbet_sig_detector.rb +1 -0
- data/lib/evilution/ast/uncovered_code.rb +88 -0
- data/lib/evilution/ast/value_object_definition.rb +25 -0
- data/lib/evilution/baseline/failure_formatter.rb +27 -0
- data/lib/evilution/baseline/report.rb +66 -0
- data/lib/evilution/baseline/spec_failure.rb +38 -0
- data/lib/evilution/baseline.rb +101 -42
- data/lib/evilution/child_output.rb +1 -1
- data/lib/evilution/cli/command.rb +1 -0
- data/lib/evilution/cli/commands/tests_list.rb +4 -3
- data/lib/evilution/cli/commands.rb +2 -0
- data/lib/evilution/cli/dispatcher.rb +2 -0
- data/lib/evilution/cli/exit_guard.rb +2 -0
- data/lib/evilution/cli/parsed_args.rb +2 -0
- data/lib/evilution/cli/parser/command_extractor.rb +2 -0
- data/lib/evilution/cli/parser/file_args.rb +4 -1
- data/lib/evilution/cli/parser/options_builder.rb +4 -1
- data/lib/evilution/cli/parser/stdin_reader.rb +1 -0
- data/lib/evilution/cli/parser.rb +1 -0
- data/lib/evilution/cli/printers/tests_list.rb +5 -4
- data/lib/evilution/cli/printers.rb +2 -0
- data/lib/evilution/cli/result.rb +2 -0
- data/lib/evilution/cli.rb +8 -2
- data/lib/evilution/config/builders.rb +2 -0
- data/lib/evilution/config/env_loader.rb +2 -0
- data/lib/evilution/config/file_loader.rb +1 -0
- data/lib/evilution/config/sources.rb +1 -0
- data/lib/evilution/config/validators/example_targeting_cache.rb +1 -0
- data/lib/evilution/config/validators/example_targeting_fallback.rb +1 -0
- data/lib/evilution/config/validators/example_targeting_strategy.rb +1 -0
- data/lib/evilution/config/validators/fail_fast.rb +1 -0
- data/lib/evilution/config/validators/hooks.rb +1 -0
- data/lib/evilution/config/validators/ignore_patterns.rb +1 -0
- data/lib/evilution/config/validators/integration.rb +1 -0
- data/lib/evilution/config/validators/isolation.rb +1 -0
- data/lib/evilution/config/validators/jobs.rb +1 -0
- data/lib/evilution/config/validators/preload.rb +1 -0
- data/lib/evilution/config/validators/profile.rb +1 -0
- data/lib/evilution/config/validators/spec_mappings.rb +3 -1
- data/lib/evilution/config/validators/spec_pattern.rb +1 -0
- data/lib/evilution/config/validators/warmup.rb +17 -0
- data/lib/evilution/config/validators.rb +2 -0
- data/lib/evilution/config.rb +7 -5
- data/lib/evilution/coverage.rb +1 -1
- data/lib/evilution/coverage_example_filter.rb +1 -1
- data/lib/evilution/diagnostic.rb +1 -1
- data/lib/evilution/equivalent/detector.rb +3 -1
- data/lib/evilution/equivalent/heuristic/guarded_index_fetch/condition.rb +66 -0
- data/lib/evilution/equivalent/heuristic/guarded_index_fetch/disturbance.rb +54 -0
- data/lib/evilution/equivalent/heuristic/guarded_index_fetch/early_exit.rb +73 -0
- data/lib/evilution/equivalent/heuristic/guarded_index_fetch/guard.rb +36 -0
- data/lib/evilution/equivalent/heuristic/guarded_index_fetch/index_read.rb +82 -0
- data/lib/evilution/equivalent/heuristic/guarded_index_fetch/node_path.rb +43 -0
- data/lib/evilution/equivalent/heuristic/guarded_index_fetch.rb +65 -0
- data/lib/evilution/example_filter.rb +46 -1
- data/lib/evilution/hooks/registry.rb +2 -1
- data/lib/evilution/integration/base.rb +2 -0
- data/lib/evilution/integration/known_failures.rb +26 -0
- data/lib/evilution/integration/loading/body_call_neutralizer.rb +139 -12
- data/lib/evilution/integration/loading/callback_redeclaration.rb +186 -0
- data/lib/evilution/integration/loading/concern_redeclaration.rb +61 -0
- data/lib/evilution/integration/loading/concern_state_cleaner.rb +19 -12
- data/lib/evilution/integration/loading/mutation_applier.rb +16 -0
- data/lib/evilution/integration/loading/test_class_cache.rb +46 -0
- data/lib/evilution/integration/loading/test_load_path.rb +21 -13
- data/lib/evilution/integration/minitest/test_ids.rb +21 -0
- data/lib/evilution/integration/minitest.rb +45 -6
- data/lib/evilution/integration/rspec/baseline_runner.rb +47 -3
- data/lib/evilution/integration/rspec/example_ids.rb +35 -0
- data/lib/evilution/integration/rspec/result_builder.rb +6 -1
- data/lib/evilution/integration/rspec/state_guard/anonymous_example_group_examples.rb +36 -0
- data/lib/evilution/integration/rspec/state_guard/configuration_state.rb +1 -0
- data/lib/evilution/integration/rspec/state_guard/configuration_streams.rb +1 -0
- data/lib/evilution/integration/rspec/state_guard/example_groups_constants.rb +1 -2
- data/lib/evilution/integration/rspec/state_guard/internals.rb +1 -2
- data/lib/evilution/integration/rspec/state_guard/object_space_example_groups.rb +1 -2
- data/lib/evilution/integration/rspec/state_guard/reporter_arrays.rb +1 -0
- data/lib/evilution/integration/rspec/state_guard/world_example_groups.rb +1 -0
- data/lib/evilution/integration/rspec/state_guard/world_filtered_examples.rb +1 -0
- data/lib/evilution/integration/rspec/state_guard/world_sources_by_path.rb +1 -0
- data/lib/evilution/integration/rspec/state_guard.rb +10 -1
- data/lib/evilution/integration/rspec.rb +22 -4
- data/lib/evilution/integration/test_unit/result_builder.rb +6 -0
- data/lib/evilution/integration/test_unit/test_ids.rb +18 -0
- data/lib/evilution/integration/test_unit.rb +37 -9
- data/lib/evilution/isolation/fork.rb +2 -1
- data/lib/evilution/isolation/in_process.rb +21 -4
- data/lib/evilution/mcp/info_tool/actions/environment.rb +1 -0
- data/lib/evilution/mcp/info_tool/actions/feedback.rb +1 -0
- data/lib/evilution/mcp/info_tool/actions/statuses.rb +1 -0
- data/lib/evilution/mcp/info_tool/actions/subjects.rb +1 -0
- data/lib/evilution/mcp/info_tool/actions/tests.rb +1 -0
- data/lib/evilution/mcp/info_tool/status_glossary.rb +2 -2
- data/lib/evilution/mcp/mutate_tool/progress_streamer.rb +2 -1
- data/lib/evilution/memory/leak_check.rb +27 -3
- data/lib/evilution/mutation.rb +8 -3
- data/lib/evilution/mutator/base.rb +49 -5
- data/lib/evilution/mutator/operator/alias_removal.rb +126 -0
- data/lib/evilution/mutator/operator/argument_list_removal.rb +52 -0
- data/lib/evilution/mutator/operator/argument_order_permutation.rb +101 -0
- data/lib/evilution/mutator/operator/argument_propagation.rb +54 -0
- data/lib/evilution/mutator/operator/argument_removal.rb +9 -1
- data/lib/evilution/mutator/operator/array_coercion_to_literal.rb +34 -0
- data/lib/evilution/mutator/operator/attribute_write_to_read.rb +34 -0
- data/lib/evilution/mutator/operator/bang_method.rb +11 -3
- data/lib/evilution/mutator/operator/binary_operand_promotion.rb +63 -0
- data/lib/evilution/mutator/operator/block_body_promotion.rb +45 -0
- data/lib/evilution/mutator/operator/block_body_to_nil.rb +52 -0
- data/lib/evilution/mutator/operator/block_body_to_raise.rb +34 -0
- data/lib/evilution/mutator/operator/call_to_nil.rb +34 -0
- data/lib/evilution/mutator/operator/coercion_emptying.rb +60 -0
- data/lib/evilution/mutator/operator/collection_replacement.rb +19 -9
- data/lib/evilution/mutator/operator/comparison_operand_swap.rb +54 -0
- data/lib/evilution/mutator/operator/comparison_replacement.rb +37 -12
- data/lib/evilution/mutator/operator/const_get_to_constant_path.rb +50 -0
- data/lib/evilution/mutator/operator/data_struct_member.rb +82 -0
- data/lib/evilution/mutator/operator/dig_to_fetch_chain.rb +45 -0
- data/lib/evilution/mutator/operator/double_negation_removal.rb +22 -0
- data/lib/evilution/mutator/operator/dynamic_dispatch_resolution.rb +79 -0
- data/lib/evilution/mutator/operator/exception_swallow.rb +84 -0
- data/lib/evilution/mutator/operator/format_specifier_swap.rb +100 -0
- data/lib/evilution/mutator/operator/forwarded_argument_drop.rb +142 -0
- data/lib/evilution/mutator/operator/inequality_to_negated_identity.rb +43 -0
- data/lib/evilution/mutator/operator/integer_division_to_fdiv.rb +62 -0
- data/lib/evilution/mutator/operator/keyword_argument.rb +25 -2
- data/lib/evilution/mutator/operator/keyword_argument_removal.rb +47 -0
- data/lib/evilution/mutator/operator/keyword_value_swap.rb +75 -0
- data/lib/evilution/mutator/operator/no_matching_pattern_else.rb +47 -0
- data/lib/evilution/mutator/operator/numbered_parameter_swap.rb +78 -0
- data/lib/evilution/mutator/operator/off_by_one_boundary.rb +68 -0
- data/lib/evilution/mutator/operator/optional_parameter_to_required.rb +14 -3
- data/lib/evilution/mutator/operator/pattern_matching_array.rb +12 -1
- data/lib/evilution/mutator/operator/pattern_wildcard_widening.rb +117 -0
- data/lib/evilution/mutator/operator/pin_operator_removal.rb +48 -0
- data/lib/evilution/mutator/operator/proc_to_lambda.rb +43 -0
- data/lib/evilution/mutator/operator/receiver_constructor_swap.rb +51 -0
- data/lib/evilution/mutator/operator/reduce_to_sum.rb +58 -0
- data/lib/evilution/mutator/operator/regex_simplification.rb +53 -132
- data/lib/evilution/mutator/operator/regexp_alternation_branch_deletion.rb +54 -0
- data/lib/evilution/mutator/operator/regexp_anchor_promotion.rb +43 -0
- data/lib/evilution/mutator/operator/regexp_anchor_to_predicate.rb +136 -0
- data/lib/evilution/mutator/operator/regexp_capture_to_passive.rb +61 -0
- data/lib/evilution/mutator/operator/regexp_character_type_complement.rb +54 -0
- data/lib/evilution/mutator/operator/regexp_named_group_rename.rb +106 -0
- data/lib/evilution/mutator/operator/regexp_option_removal.rb +51 -0
- data/lib/evilution/mutator/operator/regexp_quantifier_minimum_swap.rb +45 -0
- data/lib/evilution/mutator/operator/rescue_else_concatenation.rb +62 -0
- data/lib/evilution/mutator/operator/rescue_handler_concatenation.rb +69 -0
- data/lib/evilution/mutator/operator/rescue_handler_promotion.rb +65 -0
- data/lib/evilution/mutator/operator/return_keyword_removal.rb +79 -0
- data/lib/evilution/mutator/operator/rightward_assignment.rb +46 -0
- data/lib/evilution/mutator/operator/safe_navigation_removal.rb +67 -0
- data/lib/evilution/mutator/operator/send_mutation.rb +44 -6
- data/lib/evilution/mutator/operator/splat_operator.rb +38 -13
- data/lib/evilution/mutator/operator/statement_reorder.rb +153 -0
- data/lib/evilution/mutator/operator/symbol_to_proc_replacement.rb +59 -0
- data/lib/evilution/mutator/operator/to_i_to_integer.rb +38 -0
- data/lib/evilution/mutator/primitives.rb +25 -0
- data/lib/evilution/mutator/registry.rb +54 -2
- data/lib/evilution/mutator/rescue_handlers.rb +81 -0
- data/lib/evilution/parallel/pool.rb +1 -0
- data/lib/evilution/parallel_db_warning.rb +1 -1
- data/lib/evilution/process_supervisor.rb +3 -2
- data/lib/evilution/rails_warmup.rb +61 -0
- data/lib/evilution/reporter/cli/line_formatters/baseline_neutralized_notice.rb +55 -0
- data/lib/evilution/reporter/cli/metrics_block.rb +2 -0
- data/lib/evilution/reporter/html/report.rb +1 -0
- data/lib/evilution/reporter/json/baseline.rb +15 -0
- data/lib/evilution/reporter/json.rb +7 -2
- data/lib/evilution/result/baseline_neutralization.rb +10 -0
- data/lib/evilution/result/coverage_gap_grouper.rb +1 -0
- data/lib/evilution/result/mutation_result.rb +9 -1
- data/lib/evilution/result/subject_scorer.rb +1 -0
- data/lib/evilution/result/summary.rb +42 -2
- data/lib/evilution/runner/baseline_runner.rb +26 -11
- data/lib/evilution/runner/canary.rb +2 -57
- data/lib/evilution/runner/canary_failure_message.rb +101 -0
- data/lib/evilution/runner/isolation_resolver.rb +23 -2
- data/lib/evilution/runner/mutation_executor/neutralizer/baseline_failed.rb +35 -14
- data/lib/evilution/runner/mutation_executor/result_cache.rb +3 -0
- data/lib/evilution/runner/mutation_executor/result_packer.rb +4 -2
- data/lib/evilution/runner/mutation_executor.rb +1 -1
- data/lib/evilution/runner/mutation_planner.rb +11 -2
- data/lib/evilution/runner/report_publisher.rb +3 -2
- data/lib/evilution/runner/subject_pipeline.rb +46 -1
- data/lib/evilution/runner.rb +4 -1
- data/lib/evilution/source_ast_cache.rb +1 -1
- data/lib/evilution/spec_ast_cache.rb +1 -1
- data/lib/evilution/subject.rb +8 -2
- data/lib/evilution/version.rb +1 -1
- data/lib/evilution.rb +51 -0
- data/script/memory_check +62 -16
- metadata +108 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 12d6c2e2e3a5da3abf68a795d1537e103f3156c52df6709fd7543968efca73a9
|
|
4
|
+
data.tar.gz: c072227e0cb2d7ea933ad818853e51adbd21c90268308ce527a8670b8fdbfc23
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a90a01e42b93bc3409e8aa730df657eba157510078a338b87f96c255bbe89b5a01d74c8dd1561880c7b094c9c32fc50c22a78cd78b2e66537b7996db49de206e
|
|
7
|
+
data.tar.gz: 8c886d18f0c2acecc1c9673f540823860d3e40e41937ce1477f4f52578b549dade9c0e2ce019a94c4249bdc81d9cfaf7c9ffcc30381b8a5d7d4788844b3f6c2b
|
data/.beads/interactions.jsonl
CHANGED
|
@@ -489,3 +489,103 @@
|
|
|
489
489
|
{"id":"int-9a7df3ab","kind":"field_change","created_at":"2026-09-21T07:43:13.101312655Z","actor":"Denis Kiselev","issue_id":"EV-5pob","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Closed"}}
|
|
490
490
|
{"id":"int-6c08ef8f","kind":"field_change","created_at":"2026-09-21T08:47:57.19015326Z","actor":"Denis Kiselev","issue_id":"EV-f8h3","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Closed"}}
|
|
491
491
|
{"id":"int-41e28161","kind":"field_change","created_at":"2026-09-21T09:13:10.822154641Z","actor":"Denis Kiselev","issue_id":"EV-vk1f","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Closed"}}
|
|
492
|
+
{"id":"int-a85e9307","kind":"field_change","created_at":"2026-09-24T08:59:06.431936036Z","actor":"Denis Kiselev","issue_id":"EV-tsi4.1","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Closed"}}
|
|
493
|
+
{"id":"int-0146928b","kind":"field_change","created_at":"2026-09-24T08:59:57.400402587Z","actor":"Denis Kiselev","issue_id":"EV-tsi4.2","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Won't do: self. insertion is equivalent on Ruby >= 2.7 (private calls with literal self allowed); gem requires >= 3.3"}}
|
|
494
|
+
{"id":"int-d13277bb","kind":"field_change","created_at":"2026-09-24T10:11:27.25351867Z","actor":"Denis Kiselev","issue_id":"EV-tsi4.3","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Closed"}}
|
|
495
|
+
{"id":"int-98f94055","kind":"field_change","created_at":"2026-09-24T11:09:10.574795113Z","actor":"Denis Kiselev","issue_id":"EV-tsi4.4","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Closed"}}
|
|
496
|
+
{"id":"int-cfc17855","kind":"field_change","created_at":"2026-09-25T04:10:24.329240246Z","actor":"Denis Kiselev","issue_id":"EV-tsi4.5","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Closed"}}
|
|
497
|
+
{"id":"int-ff65a252","kind":"field_change","created_at":"2026-09-25T06:05:35.905280887Z","actor":"Denis Kiselev","issue_id":"EV-tsi4.6","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Closed"}}
|
|
498
|
+
{"id":"int-005be0d5","kind":"field_change","created_at":"2026-09-25T06:05:41.780650066Z","actor":"Denis Kiselev","issue_id":"EV-tsi4.7","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Covered by argument_list_removal (EV-tsi4.6, PR #1639)"}}
|
|
499
|
+
{"id":"int-99b3d64d","kind":"field_change","created_at":"2026-09-25T09:43:15.271882913Z","actor":"Denis Kiselev","issue_id":"EV-tsi4.28","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Closed"}}
|
|
500
|
+
{"id":"int-f94cb5b9","kind":"field_change","created_at":"2026-09-25T10:05:26.030418343Z","actor":"Denis Kiselev","issue_id":"EV-tsi4.15","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Closed"}}
|
|
501
|
+
{"id":"int-ab93e0ea","kind":"field_change","created_at":"2026-09-25T11:09:58.712099704Z","actor":"Denis Kiselev","issue_id":"EV-tsi4.8","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Closed"}}
|
|
502
|
+
{"id":"int-f54216bc","kind":"field_change","created_at":"2026-09-25T11:28:25.015240322Z","actor":"Denis Kiselev","issue_id":"EV-tsi4.9","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Closed"}}
|
|
503
|
+
{"id":"int-78532509","kind":"field_change","created_at":"2026-09-25T12:03:26.712050666Z","actor":"Denis Kiselev","issue_id":"EV-tsi4.10","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Closed"}}
|
|
504
|
+
{"id":"int-b04e4ada","kind":"field_change","created_at":"2026-09-25T12:35:14.598132892Z","actor":"Denis Kiselev","issue_id":"EV-tsi4.27","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Closed"}}
|
|
505
|
+
{"id":"int-878aed06","kind":"field_change","created_at":"2026-09-25T16:34:22.646996954Z","actor":"Denis Kiselev","issue_id":"EV-tsi4.11","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Closed"}}
|
|
506
|
+
{"id":"int-a5be78a4","kind":"field_change","created_at":"2026-09-25T17:15:19.778644918Z","actor":"Denis Kiselev","issue_id":"EV-tsi4.12","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Closed"}}
|
|
507
|
+
{"id":"int-b5b54c8c","kind":"field_change","created_at":"2026-09-25T17:47:12.91754374Z","actor":"Denis Kiselev","issue_id":"EV-tsi4.13","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Closed"}}
|
|
508
|
+
{"id":"int-0915250f","kind":"field_change","created_at":"2026-09-26T03:50:18.7581253Z","actor":"Denis Kiselev","issue_id":"EV-tsi4.26","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Closed"}}
|
|
509
|
+
{"id":"int-01656f0a","kind":"field_change","created_at":"2026-09-26T04:02:44.194731168Z","actor":"Denis Kiselev","issue_id":"EV-tsi4.14","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Closed"}}
|
|
510
|
+
{"id":"int-f5cfcd38","kind":"field_change","created_at":"2026-09-26T04:18:06.728081454Z","actor":"Denis Kiselev","issue_id":"EV-tsi4.25","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Closed"}}
|
|
511
|
+
{"id":"int-f611c7c0","kind":"field_change","created_at":"2026-09-26T06:33:30.975279097Z","actor":"Denis Kiselev","issue_id":"EV-tsi4.16","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Closed"}}
|
|
512
|
+
{"id":"int-dbccf56c","kind":"field_change","created_at":"2026-09-26T06:52:37.666559599Z","actor":"Denis Kiselev","issue_id":"EV-tsi4.17","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Closed"}}
|
|
513
|
+
{"id":"int-3ace0c73","kind":"field_change","created_at":"2026-09-26T07:07:52.345696388Z","actor":"Denis Kiselev","issue_id":"EV-tsi4.18","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Closed"}}
|
|
514
|
+
{"id":"int-df7a3ad8","kind":"field_change","created_at":"2026-09-26T07:19:58.301755963Z","actor":"Denis Kiselev","issue_id":"EV-tsi4.24","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Closed"}}
|
|
515
|
+
{"id":"int-ec1508f5","kind":"field_change","created_at":"2026-09-26T07:41:16.328539681Z","actor":"Denis Kiselev","issue_id":"EV-tsi4.19","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Closed"}}
|
|
516
|
+
{"id":"int-4fb31878","kind":"field_change","created_at":"2026-09-26T08:00:27.677084584Z","actor":"Denis Kiselev","issue_id":"EV-tsi4.20","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Closed"}}
|
|
517
|
+
{"id":"int-451c79e2","kind":"field_change","created_at":"2026-09-26T17:48:34.137710758Z","actor":"Denis Kiselev","issue_id":"EV-tsi4.21","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Closed"}}
|
|
518
|
+
{"id":"int-b243b5f3","kind":"field_change","created_at":"2026-09-27T04:19:10.37017749Z","actor":"Denis Kiselev","issue_id":"EV-tsi4.22","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Closed"}}
|
|
519
|
+
{"id":"int-561a3e6f","kind":"field_change","created_at":"2026-09-27T04:37:48.03229929Z","actor":"Denis Kiselev","issue_id":"EV-tsi4.23","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Closed"}}
|
|
520
|
+
{"id":"int-180ba042","kind":"field_change","created_at":"2026-09-27T05:10:45.908206414Z","actor":"Denis Kiselev","issue_id":"EV-27v9.1","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Closed"}}
|
|
521
|
+
{"id":"int-854c1949","kind":"field_change","created_at":"2026-09-27T05:27:27.19234994Z","actor":"Denis Kiselev","issue_id":"EV-27v9.2","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Closed"}}
|
|
522
|
+
{"id":"int-d09d6377","kind":"field_change","created_at":"2026-09-27T10:40:02.318630878Z","actor":"Denis Kiselev","issue_id":"EV-27v9.3","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Closed"}}
|
|
523
|
+
{"id":"int-5bb755e9","kind":"field_change","created_at":"2026-09-27T10:43:06.788713181Z","actor":"Denis Kiselev","issue_id":"EV-27v9.4","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Won't do: hoist yields NoMethodError (killed by execution) or duplicates block_body_promotion; signal covered by EV-27v9.3"}}
|
|
524
|
+
{"id":"int-1344bddb","kind":"field_change","created_at":"2026-09-27T10:54:21.511979983Z","actor":"Denis Kiselev","issue_id":"EV-27v9.5","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Closed"}}
|
|
525
|
+
{"id":"int-8d4fd88a","kind":"field_change","created_at":"2026-09-27T15:12:53.603922398Z","actor":"Denis Kiselev","issue_id":"EV-03as","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Closed"}}
|
|
526
|
+
{"id":"int-e2c0e5da","kind":"field_change","created_at":"2026-09-27T16:02:46.866587228Z","actor":"Denis Kiselev","issue_id":"EV-e9ni","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Closed"}}
|
|
527
|
+
{"id":"int-356e6b7a","kind":"field_change","created_at":"2026-09-28T02:59:40.442681333Z","actor":"Denis Kiselev","issue_id":"EV-ae7u","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Closed"}}
|
|
528
|
+
{"id":"int-a15bfc29","kind":"field_change","created_at":"2026-09-28T03:35:22.865923943Z","actor":"Denis Kiselev","issue_id":"EV-ziy0","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Closed"}}
|
|
529
|
+
{"id":"int-c4c3b0ee","kind":"field_change","created_at":"2026-09-28T05:00:30.703915081Z","actor":"Denis Kiselev","issue_id":"EV-qj40","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Closed"}}
|
|
530
|
+
{"id":"int-6b262792","kind":"field_change","created_at":"2026-10-02T07:16:11.010581665Z","actor":"Denis Kiselev","issue_id":"EV-in17.1","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Endless defs already covered by MethodBodyReplacement + MethodBodyToRaise; regression specs added instead of a new operator"}}
|
|
531
|
+
{"id":"int-20d9d25f","kind":"field_change","created_at":"2026-10-02T08:01:02.739469298Z","actor":"Denis Kiselev","issue_id":"EV-in17.2","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Merged: DataStructMember operator (drop + adjacent swap), ArgumentRemoval skips member lists"}}
|
|
532
|
+
{"id":"int-b844f06a","kind":"field_change","created_at":"2026-10-02T08:55:07.467612422Z","actor":"Denis Kiselev","issue_id":"EV-in17.3","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Merged: PinOperatorRemoval operator"}}
|
|
533
|
+
{"id":"int-813d5c0f","kind":"field_change","created_at":"2026-10-02T11:26:04.587491311Z","actor":"Denis Kiselev","issue_id":"EV-in17.4","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Merged: RightwardAssignment operator"}}
|
|
534
|
+
{"id":"int-d795672b","kind":"field_change","created_at":"2026-10-02T11:53:57.423520962Z","actor":"Denis Kiselev","issue_id":"EV-in17.5","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Merged: NumberedParameterSwap operator (re-scoped from ImplicitBlockParam)"}}
|
|
535
|
+
{"id":"int-3548d60e","kind":"field_change","created_at":"2026-10-02T12:26:03.455515136Z","actor":"Denis Kiselev","issue_id":"EV-in17.6","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Merged: ForwardedArgumentDrop operator (re-scoped from ArgumentForwarding)"}}
|
|
536
|
+
{"id":"int-97a35172","kind":"field_change","created_at":"2026-10-02T15:11:30.435617553Z","actor":"Denis Kiselev","issue_id":"EV-in17.7","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Merged: PatternWildcardWidening operator"}}
|
|
537
|
+
{"id":"int-80bc2182","kind":"field_change","created_at":"2026-10-02T15:36:15.078727262Z","actor":"Denis Kiselev","issue_id":"EV-in17.8","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Merged: NoMatchingPatternElse operator (else insertion; removal already in case_in)"}}
|
|
538
|
+
{"id":"int-074659be","kind":"field_change","created_at":"2026-10-02T15:51:58.478518221Z","actor":"Denis Kiselev","issue_id":"EV-gw8w","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Merged via PR #1693: constant and delimiters preserved in array/find pattern mutations"}}
|
|
539
|
+
{"id":"int-cf36f2ea","kind":"field_change","created_at":"2026-10-03T02:50:23.790936748Z","actor":"Denis Kiselev","issue_id":"EV-p7l7","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Merged: keyword_argument keeps an anonymous ** the body uses"}}
|
|
540
|
+
{"id":"int-c78705e8","kind":"field_change","created_at":"2026-10-03T03:34:56.023536028Z","actor":"Denis Kiselev","issue_id":"EV-wuwz","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Merged: delimiters helper replaces safe navigation in PatternMatchingArray"}}
|
|
541
|
+
{"id":"int-d742aa8a","kind":"field_change","created_at":"2026-10-03T04:11:14.742547553Z","actor":"Denis Kiselev","issue_id":"EV-a508","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Merged: diff-lcs capped < 2, canary names gem activation conflicts, README defaults MCP to bundle exec"}}
|
|
542
|
+
{"id":"int-5015cfd3","kind":"field_change","created_at":"2026-10-03T05:16:17.707344911Z","actor":"Denis Kiselev","issue_id":"EV-70lx.1","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Merged: ArgumentOrderPermutation operator with order-free skip list"}}
|
|
543
|
+
{"id":"int-2b6321e3","kind":"field_change","created_at":"2026-10-03T05:46:41.353299041Z","actor":"Denis Kiselev","issue_id":"EV-70lx.2","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Merged: KeywordValueSwap operator"}}
|
|
544
|
+
{"id":"int-ac550ceb","kind":"field_change","created_at":"2026-10-03T06:08:06.145495467Z","actor":"Denis Kiselev","issue_id":"EV-70lx.3","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Merged: covered by block_body_promotion; regression specs added"}}
|
|
545
|
+
{"id":"int-cb212c6d","kind":"field_change","created_at":"2026-10-03T11:26:40.545576039Z","actor":"Denis Kiselev","issue_id":"EV-70lx.4","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Merged: covered by method_call_removal; regression specs added"}}
|
|
546
|
+
{"id":"int-db265ed7","kind":"field_change","created_at":"2026-10-03T12:19:57.106972968Z","actor":"Denis Kiselev","issue_id":"EV-70lx.5","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Merged: ComparisonOperandSwap for <=>; between?/clamp covered by argument_order_permutation"}}
|
|
547
|
+
{"id":"int-a75daaf2","kind":"field_change","created_at":"2026-10-03T12:54:36.679091996Z","actor":"Denis Kiselev","issue_id":"EV-70lx.6","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Merged: round/truncate swaps in send_mutation, new integer_division_to_fdiv; half: mode split to EV-qt7f"}}
|
|
548
|
+
{"id":"int-7f131376","kind":"field_change","created_at":"2026-10-03T15:01:33.349965452Z","actor":"Denis Kiselev","issue_id":"EV-70lx.7","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Merged: OffByOneBoundary operator"}}
|
|
549
|
+
{"id":"int-ba54b5af","kind":"field_change","created_at":"2026-10-03T15:46:31.592677693Z","actor":"Denis Kiselev","issue_id":"EV-70lx.8","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Merged: FormatSpecifierSwap operator; argument_order_permutation skips format methods"}}
|
|
550
|
+
{"id":"int-d2496545","kind":"field_change","created_at":"2026-10-03T16:55:37.885963941Z","actor":"Denis Kiselev","issue_id":"EV-70lx.9","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Merged: ExceptionSwallow in strict profile; ignore_patterns grammar split to EV-a6ey"}}
|
|
551
|
+
{"id":"int-dc691f35","kind":"field_change","created_at":"2026-10-04T02:07:48.713969725Z","actor":"Denis Kiselev","issue_id":"EV-70lx.10","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Merged: StatementReorder in strict profile"}}
|
|
552
|
+
{"id":"int-e47209dc","kind":"field_change","created_at":"2026-10-04T02:22:56.861285181Z","actor":"Denis Kiselev","issue_id":"EV-70lx.11","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Won't do: measured on evilution's lib/ (409 files, true -> false, whole spec file per mutant): 384 survived, 18 killed, of which 17 were self-run artefacts (a no-op control mutant was killed on the same 17 files) and 1 real (status_glossary_spec asserts frozen strings). One real signal in 409 does not justify a file-level emission path."}}
|
|
553
|
+
{"id":"int-6259aee3","kind":"field_change","created_at":"2026-10-04T03:01:50.164062208Z","actor":"Denis Kiselev","issue_id":"EV-70lx.12","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Merged: AliasRemoval operator; shared attribution refactor split to EV-u9rq"}}
|
|
554
|
+
{"id":"int-55084cba","kind":"field_change","created_at":"2026-10-04T04:36:27.295973647Z","actor":"Denis Kiselev","issue_id":"EV-ib1c.1","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Decision: regexp_parser as runtime dependency, edit by offsets, compile-check every mutant. Evidence posted on #1524. Foundation work split to EV-ib1c.9."}}
|
|
555
|
+
{"id":"int-fc063d48","kind":"field_change","created_at":"2026-10-04T11:06:20.183354321Z","actor":"Denis Kiselev","issue_id":"EV-ib1c.9","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Merged: regexp_parser runtime dependency and Evilution::AST::RegexpPattern helper"}}
|
|
556
|
+
{"id":"int-135695f4","kind":"field_change","created_at":"2026-10-04T11:37:04.708217274Z","actor":"Denis Kiselev","issue_id":"EV-spob","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Merged: regex_simplification moved onto RegexpPattern"}}
|
|
557
|
+
{"id":"int-474f5d9c","kind":"field_change","created_at":"2026-10-04T12:01:54.857943644Z","actor":"Denis Kiselev","issue_id":"EV-ib1c.2","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Merged: RegexpCharacterTypeComplement operator"}}
|
|
558
|
+
{"id":"int-8f7efc39","kind":"field_change","created_at":"2026-10-04T12:20:59.73456011Z","actor":"Denis Kiselev","issue_id":"EV-ib1c.3","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Merged: RegexpAnchorPromotion operator"}}
|
|
559
|
+
{"id":"int-e092039b","kind":"field_change","created_at":"2026-10-04T12:44:08.732168047Z","actor":"Denis Kiselev","issue_id":"EV-ib1c.4","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Merged: RegexpAlternationBranchDeletion operator, capped at 10 branches"}}
|
|
560
|
+
{"id":"int-89a03141","kind":"field_change","created_at":"2026-10-04T13:55:56.95130631Z","actor":"Denis Kiselev","issue_id":"EV-ib1c.5","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Merged: RegexpQuantifierMinimumSwap operator"}}
|
|
561
|
+
{"id":"int-90e07229","kind":"field_change","created_at":"2026-10-04T14:26:18.913357911Z","actor":"Denis Kiselev","issue_id":"EV-ib1c.6","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Merged: RegexpCaptureToPassive operator"}}
|
|
562
|
+
{"id":"int-c6376ed4","kind":"field_change","created_at":"2026-10-04T15:23:59.584161061Z","actor":"Denis Kiselev","issue_id":"EV-ib1c.7","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Merged: RegexpNamedGroupRename operator"}}
|
|
563
|
+
{"id":"int-f45f11c3","kind":"field_change","created_at":"2026-10-04T15:51:06.656516074Z","actor":"Denis Kiselev","issue_id":"EV-ib1c.8","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Merged: RegexpOptionRemoval operator"}}
|
|
564
|
+
{"id":"int-f74a65f3","kind":"field_change","created_at":"2026-10-05T01:59:49.116216501Z","actor":"Denis Kiselev","issue_id":"EV-waxv.1","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Merged: RescueHandlerPromotion operator"}}
|
|
565
|
+
{"id":"int-086b8b8f","kind":"field_change","created_at":"2026-10-05T02:25:10.675826812Z","actor":"Denis Kiselev","issue_id":"EV-waxv.2","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Merged: RescueHandlerConcatenation operator (keeps the rescue)"}}
|
|
566
|
+
{"id":"int-8504c32b","kind":"field_change","created_at":"2026-10-05T03:09:46.042410063Z","actor":"Denis Kiselev","issue_id":"EV-waxv.3","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Merged: RescueElseConcatenation operator (broad rescues only)"}}
|
|
567
|
+
{"id":"int-1a680abd","kind":"field_change","created_at":"2026-10-05T03:45:51.492632284Z","actor":"Denis Kiselev","issue_id":"EV-waxv.4","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Merged: ReturnKeywordRemoval operator"}}
|
|
568
|
+
{"id":"int-6be631a1","kind":"field_change","created_at":"2026-10-05T03:53:41.798959331Z","actor":"Denis Kiselev","issue_id":"EV-waxv.5","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Merged: covered by existing operators; cross-operator regression spec added"}}
|
|
569
|
+
{"id":"int-e7ea4f25","kind":"field_change","created_at":"2026-10-05T04:35:10.212440677Z","actor":"Denis Kiselev","issue_id":"EV-a6ey","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Closed"}}
|
|
570
|
+
{"id":"int-a9f620b2","kind":"field_change","created_at":"2026-10-05T05:20:43.639066857Z","actor":"Denis Kiselev","issue_id":"EV-8lcr","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Closed"}}
|
|
571
|
+
{"id":"int-3b99b201","kind":"field_change","created_at":"2026-10-05T06:16:47.160706383Z","actor":"Denis Kiselev","issue_id":"EV-8gzw","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Closed"}}
|
|
572
|
+
{"id":"int-72b4a08c","kind":"field_change","created_at":"2026-10-05T09:41:56.709809764Z","actor":"Denis Kiselev","issue_id":"EV-h3ir","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Closed"}}
|
|
573
|
+
{"id":"int-49f7ebbb","kind":"field_change","created_at":"2026-10-05T11:53:56.598210615Z","actor":"Denis Kiselev","issue_id":"EV-hoki","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Closed"}}
|
|
574
|
+
{"id":"int-34d1379a","kind":"field_change","created_at":"2026-10-05T14:22:47.087299042Z","actor":"Denis Kiselev","issue_id":"EV-56hj","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Closed"}}
|
|
575
|
+
{"id":"int-6e4bcbc4","kind":"field_change","created_at":"2026-10-06T05:17:58.928359175Z","actor":"Denis Kiselev","issue_id":"EV-mrfr","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Closed"}}
|
|
576
|
+
{"id":"int-f8e7bd2e","kind":"field_change","created_at":"2026-10-06T06:34:59.884610002Z","actor":"Denis Kiselev","issue_id":"EV-8ngq","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Closed"}}
|
|
577
|
+
{"id":"int-b1698bc2","kind":"field_change","created_at":"2026-10-06T07:20:23.824889017Z","actor":"Denis Kiselev","issue_id":"EV-vqw1","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Closed"}}
|
|
578
|
+
{"id":"int-a6a57a8d","kind":"field_change","created_at":"2026-10-06T08:34:34.810437348Z","actor":"Denis Kiselev","issue_id":"EV-z6y1","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Closed"}}
|
|
579
|
+
{"id":"int-a7b8436b","kind":"field_change","created_at":"2026-10-06T11:37:21.379002004Z","actor":"Denis Kiselev","issue_id":"EV-pvau","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Closed"}}
|
|
580
|
+
{"id":"int-316ed97b","kind":"field_change","created_at":"2026-10-06T11:37:21.692481188Z","actor":"Denis Kiselev","issue_id":"EV-e380","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Closed"}}
|
|
581
|
+
{"id":"int-deca8540","kind":"field_change","created_at":"2026-10-06T15:23:09.145528907Z","actor":"Denis Kiselev","issue_id":"EV-z4m2","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Closed"}}
|
|
582
|
+
{"id":"int-36097126","kind":"field_change","created_at":"2026-10-06T14:41:05.739141414Z","actor":"Denis Kiselev","issue_id":"EV-84gq","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Closed"}}
|
|
583
|
+
{"id":"int-61e3037a","kind":"field_change","created_at":"2026-10-06T17:43:49.128023228Z","actor":"Denis Kiselev","issue_id":"EV-feu9","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Closed"}}
|
|
584
|
+
{"id":"int-6c0d6f1f","kind":"field_change","created_at":"2026-10-07T02:23:54.251384914Z","actor":"Denis Kiselev","issue_id":"EV-lgk8","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Closed"}}
|
|
585
|
+
{"id":"int-08fd2997","kind":"field_change","created_at":"2026-10-07T10:43:53.874903719Z","actor":"Denis Kiselev","issue_id":"EV-rm8v","extra":{"field":"status","new_value":"in_progress","old_value":"open"}}
|
|
586
|
+
{"id":"int-35f8d0ca","kind":"field_change","created_at":"2026-10-07T12:55:20.009979823Z","actor":"Denis Kiselev","issue_id":"EV-rm8v","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Closed"}}
|
|
587
|
+
{"id":"int-fa03cb81","kind":"field_change","created_at":"2026-10-07T13:07:12.57941145Z","actor":"Denis Kiselev","issue_id":"EV-wk0w","extra":{"field":"status","new_value":"in_progress","old_value":"open"}}
|
|
588
|
+
{"id":"int-e6956eaa","kind":"field_change","created_at":"2026-10-07T16:15:46.858274377Z","actor":"Denis Kiselev","issue_id":"EV-wk0w","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Closed"}}
|
|
589
|
+
{"id":"int-995cf63f","kind":"field_change","created_at":"2026-10-07T16:18:39.396678188Z","actor":"Denis Kiselev","issue_id":"EV-s06e","extra":{"field":"status","new_value":"in_progress","old_value":"open"}}
|
|
590
|
+
{"id":"int-f1fa1ab6","kind":"field_change","created_at":"2026-10-07T17:32:04.485879419Z","actor":"Denis Kiselev","issue_id":"EV-s06e","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Closed"}}
|
|
591
|
+
{"id":"int-5c22155e","kind":"field_change","created_at":"2026-10-07T17:32:39.183171753Z","actor":"Denis Kiselev","issue_id":"EV-0s4b","extra":{"field":"status","new_value":"in_progress","old_value":"open"}}
|
data/.rubocop_todo.yml
CHANGED
|
@@ -16,7 +16,21 @@ Metrics/ClassLength:
|
|
|
16
16
|
- "lib/evilution/runner/isolation_resolver.rb"
|
|
17
17
|
- "lib/evilution/cli/parser/options_builder.rb"
|
|
18
18
|
- "lib/evilution/spec_resolver.rb"
|
|
19
|
+
- "lib/evilution/mutator/registry.rb"
|
|
19
20
|
|
|
20
21
|
Metrics/MethodLength:
|
|
21
22
|
Exclude:
|
|
22
23
|
- "lib/evilution/runner.rb"
|
|
24
|
+
|
|
25
|
+
# The empty forward declaration (`class Evilution::CLI; end`) that lets the
|
|
26
|
+
# children nest under the namespace before the full definition counts as a
|
|
27
|
+
# second top-level class. See "Require conventions" in docs/architecture.md.
|
|
28
|
+
Style/OneClassPerFile:
|
|
29
|
+
Exclude:
|
|
30
|
+
- "lib/evilution/cli.rb"
|
|
31
|
+
- "lib/evilution/integration/rspec/state_guard.rb"
|
|
32
|
+
|
|
33
|
+
Metrics/ParameterLists:
|
|
34
|
+
Exclude:
|
|
35
|
+
- "lib/evilution/result/summary.rb"
|
|
36
|
+
- "lib/evilution/result/mutation_result.rb"
|
data/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,130 @@
|
|
|
2
2
|
|
|
3
3
|
Versioning policy: see [docs/versioning.md](docs/versioning.md).
|
|
4
4
|
|
|
5
|
+
## [1.4.0] - 2026-10-07
|
|
6
|
+
|
|
7
|
+
Two things in this release. Code that lives in a class body rather than in a method — scopes, AASM guards, callback conditions, value-object definitions — is now mutated, where a run aimed at it used to report `0 mutations`. And the `default` profile grows from 111 to 136 operators, with two more in `strict`. Mutation scores will move on both counts — every new subject and every new operator produces mutants your suite has never been measured against. Pin the gem version and the operator profile if you need a stable score across runs.
|
|
8
|
+
|
|
9
|
+
A red baseline also means something different now: it no longer hides survivors, and it no longer lets an already-failing example count as a kill. See "Changed".
|
|
10
|
+
|
|
11
|
+
Most of the subject and baseline work comes from a field report on a Rails application running 1.3.0 (GH #1740–#1744).
|
|
12
|
+
|
|
13
|
+
### Added
|
|
14
|
+
|
|
15
|
+
- **Subjects outside `def`** — subjects were methods only, so a file or a line range holding nothing but class-body code got no mutations at all:
|
|
16
|
+
- **Value-object definitions** — `Point = Data.define(:x, :y)` and `class Coord < Struct.new(:lat, :lng)` outside any method are subjects of their own, named after the constant and mutated by the operators that apply to them. `--target Foo` matches a value-object constant named `Foo` (PR #1738, GH #1683)
|
|
17
|
+
- **ActiveRecord scopes** — `scope :recent, -> { where(recent: true) }` with a literal body is a subject named after the class method it defines (`Order.recent`) and mutated like a method body (PR #1747, GH #1742)
|
|
18
|
+
- **AASM guards and callbacks** — lambdas and blocks written out inside an `event` or `state` declaration, named after the method the declaration defines (`Order#ship`, `Order#paid?`) (PR #1755, GH #1750)
|
|
19
|
+
- **Callback and validation declarations** — the conditions and bodies of `validate :credit_limit, if: -> { paid? }`, `before_save { ... }`, `before_action ..., unless: -> { ... }`, named the way the declaration reads (`Order.validate(:credit_limit)`, `Order.before_save`). The mutated declaration takes the place of the original in its callback chain, so the two do not sit side by side and mask each other (PR #1759, GH #1749)
|
|
20
|
+
- **The same three inside a concern's `included do ... end` block**, named after the concern (`Publishable.published`, `Shippable#ship`, `Publishable.validates(:title)`) and re-declared on every class that already includes it (PRs #1757, #1764, #1766; GH #1748, #1756, #1758)
|
|
21
|
+
- **A warning when targeted lines hold code no subject covers** — a line range, or a whole file with no subject at all, that contains class-body code outside every subject (DSL calls, constant lists) now says so on stderr and in JSON as `summary.uncovered_code` (`[{ file, lines: ["2-4", "9"] }]`), instead of a bare `0 mutations` that reads as "nothing to test here" (PR #1746, GH #1741)
|
|
22
|
+
- **Seven operators for modern syntax (`default` profile)** — pattern matching, anonymous arguments and `Data` / `Struct` (epic GH #1428):
|
|
23
|
+
- **`data_struct_member`** — drops a member, or swaps adjacent members, of a `Data.define` / `Struct.new` definition (PR #1685, GH #1543)
|
|
24
|
+
- **`pin_operator_removal`** — `in ^expected` to `in expected`: the pattern captures instead of comparing (PR #1686, GH #1544)
|
|
25
|
+
- **`rightward_assignment`** — `value => [a, b]` to `value in [a, b]`: a mismatch returns `false` instead of raising (PR #1687, GH #1545)
|
|
26
|
+
- **`numbered_parameter_swap`** — `pairs.map { _1 - _2 }` to `pairs.map { _2 - _1 }` (PR #1688, GH #1546)
|
|
27
|
+
- **`forwarded_argument_drop`** — `g(*, **, &)` to `g(**, &)`; a `...` signature is spelled out so one part can be left out (PR #1690, GH #1547)
|
|
28
|
+
- **`pattern_wildcard_widening`** — `in [a, b]` to `in [a, b, *]`, `in { age: Integer }` to `in { age: _ }`: the pattern accepts shapes it rejected (PR #1692, GH #1548)
|
|
29
|
+
- **`no_matching_pattern_else`** — adds an empty `else` to a `case/in` that has none, so an unmatched value yields `nil` instead of raising (PR #1694, GH #1549)
|
|
30
|
+
- **Seven operators for arguments, numbers and declarations (`default` profile)** (epic GH #1429):
|
|
31
|
+
- **`argument_order_permutation`** — `compute(a, b)` to `compute(b, a)` for calls, `super` and `yield`. Calls that take arguments in any order, such as `OptionParser#on`, can be silenced with `ignore_patterns` (PR #1706, GH #1550)
|
|
32
|
+
- **`keyword_value_swap`** — `compute(x: a, y: b)` to `compute(x: b, y: a)`, keeping the keys (PR #1707, GH #1551)
|
|
33
|
+
- **`comparison_operand_swap`** — `x.age <=> y.age` to `y.age <=> x.age`: reverses a sort block or a custom ordering (PR #1710, GH #1554)
|
|
34
|
+
- **`integer_division_to_fdiv`** — `a / b` to `a.fdiv(b)`: integer division keeps its remainder (PR #1712, GH #1555)
|
|
35
|
+
- **`off_by_one_boundary`** — `n.times` to `(n - 1).times`, `items.first(n)` to `items.first(n - 1)`, for counts held in a variable (PR #1713, GH #1556)
|
|
36
|
+
- **`format_specifier_swap`** — `format("%05d", n)` to `format("%d", n)`, `"%.2f"` to `"%f"` / `"%s"` (PR #1714, GH #1557)
|
|
37
|
+
- **`alias_removal`** — drops an `alias` or `alias_method` declaration (PR #1719, GH #1561)
|
|
38
|
+
- **Seven structural regexp operators (`default` profile)** — built on `regexp_parser`, so each edits one token of the pattern rather than one byte (epic GH #1426; PR #1722, GH #1721):
|
|
39
|
+
- **`regexp_character_type_complement`** — `/\d+/` to `/\D+/`, `/\bword/` to `/\Bword/` (PR #1725, GH #1525)
|
|
40
|
+
- **`regexp_anchor_promotion`** — `^` to `\A`, `$` and `\Z` to `\z`: the pattern stops matching around newlines (PR #1726, GH #1526)
|
|
41
|
+
- **`regexp_alternation_branch_deletion`** — `/cat|dog/` to `/dog/` and `/cat/` (PR #1727, GH #1527)
|
|
42
|
+
- **`regexp_quantifier_minimum_swap`** — `*` to `+` and back, keeping lazy and possessive markers, so only the empty case changes (PR #1728, GH #1528)
|
|
43
|
+
- **`regexp_capture_to_passive`** — `/id=(\d+)/` to `/id=(?:\d+)/`: `$1` and `m[1]` lose their value (PR #1729, GH #1529)
|
|
44
|
+
- **`regexp_named_group_rename`** — `/(?<user>\w+)@/` to `/(?<_user>\w+)@/`: `m[:user]` no longer finds it (PR #1730, GH #1530)
|
|
45
|
+
- **`regexp_option_removal`** — drops `i` or `m` where it changes what the pattern matches (PR #1731, GH #1531)
|
|
46
|
+
- **Four operators for `rescue` and `return` (`default` profile)** (epic GH #1425):
|
|
47
|
+
- **`rescue_handler_promotion`** — runs a rescue handler instead of the code it protects, so the happy path never runs (PR #1732, GH #1519)
|
|
48
|
+
- **`rescue_handler_concatenation`** — runs the handler after the protected code as well, so a successful run also does what the handler does (PR #1733, GH #1520)
|
|
49
|
+
- **`rescue_else_concatenation`** — moves the `else` body into the protected code, so an error it raises is now rescued (PR #1734, GH #1521)
|
|
50
|
+
- **`return_keyword_removal`** — `return :neg if x.negative?` to `:neg if x.negative?`: control flow continues past a guard clause (PR #1735, GH #1522)
|
|
51
|
+
- **Two operators in the `strict` profile**:
|
|
52
|
+
- **`exception_swallow`** — `record.save!` to `record.save! rescue nil`, for statements that raise by convention: a survivor means no test makes it fail and checks the error comes out (PR #1716, GH #1558)
|
|
53
|
+
- **`statement_reorder`** — swaps two adjacent statements that both act, to surface side effects whose order is never asserted (PR #1717, GH #1559)
|
|
54
|
+
- **`ignore_patterns` accepts every method name** — names ending in `?`, `!` or `=` and operator methods are written as they are (`call{name=valid?|save!}`, `call{name=<=>}`); names made of reserved characters go in quotes (`call{name='|'}`). They used to raise `ConfigError`, which left the new operators' noisiest call sites impossible to silence. See `docs/ast_pattern_syntax.md` (PR #1737, GH #1715)
|
|
55
|
+
- **`index_to_fetch` under a guard on the same key is equivalent** — `config.fetch(:size)` cannot raise inside `if config[:size]`, nor after `return unless config[:size]`; both forms are now reported `equivalent` instead of surviving on every run (PRs #1754, #1763; GH #1744, #1753)
|
|
56
|
+
- **A red baseline says why it was red** — the failing examples with their first error line, or the error that stopped the file before any example ran (load error, timeout, a baseline process that died), on stderr once the baseline finishes, under the score line, and in JSON as `summary.baseline_failures`. The baseline used to report pass or fail and nothing else (PR #1752, GH #1743)
|
|
57
|
+
|
|
58
|
+
### Changed
|
|
59
|
+
|
|
60
|
+
- **A red baseline no longer hides survivors, and no longer counts as a kill** — every survivor covered by a spec file that was red in the baseline used to be recorded `neutral`, although its tests had passed: real gaps disappeared behind full marks. And where the red example failed again in the mutation run, every mutation it ran against was reported `killed`. Now a survivor stays a survivor whatever the baseline did, and a mutation is `neutral` only when its tests failed on nothing but examples that were already failing. `summary.baseline_neutralized` counts those. Expect a lower score on a project with a red or flaky spec file — the earlier one was wrong in both directions (PR #1762, GH #1751)
|
|
61
|
+
- **The same under Minitest and Test::Unit** — tests are named `Class#test` and `test(Class)` in the baseline and in a mutation run alike (PR #1768, GH #1761)
|
|
62
|
+
- **`send_mutation` swaps rounding modes** — `round` to `floor` and `ceil` (PR #1712, GH #1555)
|
|
63
|
+
- **Dependencies** — `regexp_parser` (`>= 2.9, < 3`, the range RuboCop uses) is a new runtime dependency. `diff-lcs` is capped below 2 while `rspec-expectations` requires `< 2.0` (PRs #1722, #1704)
|
|
64
|
+
- **Run the MCP server through `bundle exec`** — the README setup now shows `"command": "bundle", "args": ["exec", "evilution", "mcp"]`, so the project's `Gemfile.lock` decides which gem versions are loaded (PR #1704, GH #1684)
|
|
65
|
+
|
|
66
|
+
### Fixed
|
|
67
|
+
|
|
68
|
+
- **Methods inside `class << self` are named as class methods** — they were listed as `Gateway#create_group`, so `--target Gateway.create_group` matched nothing and `Gateway.` / `Gateway#` selected the wrong set (PR #1745, GH #1740)
|
|
69
|
+
- **`regex_simplification` no longer mutates group syntax as if it were a quantifier or an anchor** — `/(?:ab)+/` became `/(:ab)+/`, a lookahead became a capture of `=a`, and anchors inside a `(?#comment)` were "removed", producing mutants that could never be killed (PR #1723, GH #1720)
|
|
70
|
+
- **`pattern_matching_array` keeps the constant of a deconstruct pattern** — mutating `Point[x, y]` also removed the `Point` check, and parenthesized, qualified and find patterns lost their shape (PR #1693, GH #1691; fix by [@mikamikasuki](https://github.com/mikamikasuki))
|
|
71
|
+
- **`keyword_argument` no longer removes an anonymous `**` the body forwards** — `def call(*, **, &)` forwarding `target.call(*, **, &)` produced a mutant Ruby rejects (PR #1695, GH #1689)
|
|
72
|
+
- **A gem activation conflict is reported as one** — with the MCP server started outside Bundler, RubyGems activated `diff-lcs` 2.0 and RSpec then refused to load; the run stopped at the proof-of-life canary with a message about the canary. It now names the conflict and the fix (PR #1704, GH #1684)
|
|
73
|
+
- **Eight more advisory messages can no longer be turned into errors** — a project that raises on warnings promoted evilution's own notices ("HTML report written to …", "coverage targeting unavailable", …) to exceptions; they now go through `Evilution::Diagnostic` like the rest (PR #1739, GH #1591)
|
|
74
|
+
- **In-process RSpec runs no longer keep about 1 MB per mutation** — each run with a suite hook left its examples reachable through `RSpec::Core::AnonymousExampleGroup` for the life of the process (65 MB to 220 MB over 150 runs, flat after the fix) (PR #1765; fix by [@gipcompany](https://github.com/gipcompany))
|
|
75
|
+
- **`in_process` isolation runs every mutation's tests under Minitest and Test::Unit** — only the first mutation got its tests run; each later one was an error (`no Minitest tests executed (0 test methods ran)`), and since errors are left out of the score the report read as 100% on one mutation. A test file is now loaded once per process and its classes are dispatched again for every mutation. A suite that builds tests at load time from the code under test still needs `--isolation fork`; see [docs/isolation.md](docs/isolation.md) (PR #1775, GH #1767)
|
|
76
|
+
- **A looping mutant no longer hangs an `in_process` run** — the per-mutation timeout raised `Timeout::Error` once; the test framework recorded one failed test and moved on to the next, which reached the same loop with no timer left. The timeout now raises a `SignalException` that ends the whole test run, and the mutation is reported `timed_out` (PR #1777, GH #1776)
|
|
77
|
+
- **The uncovered-code warning no longer names lines that were mutated, or top-level `require`s** — it listed an `alias_method` line the same run had mutated, and `require` / `require_relative` lines that hold nothing to mutate (PR #1773, GH #1770)
|
|
78
|
+
- **`optional_parameter_to_required` no longer emits mutants Ruby rejects** — optional parameters must be contiguous, so dropping the default of one that sits between two others (`def f(a = nil, b = nil, c = nil)` to `def f(a = nil, b, c = nil)`) is a syntax error. Of several optional parameters only the first is mutated, and the last unless a `*rest` parameter follows (PR #1779, GH #1771)
|
|
79
|
+
- **`splat_operator` leaves the rest of a pattern alone** — `x => { key:, **opts }` became `x => { key:, opts }`, which does not parse. The rest of an array or find pattern (`in [a, *rest]`) is no longer mutated either, although that mutant parsed: expect fewer `splat_operator` mutants in code that uses them (PR #1778, GH #1772; fix by [@gipcompany](https://github.com/gipcompany))
|
|
80
|
+
- **`splat_operator` no longer demotes a `**` that follows another `**`** — `bar(**a, **b)` became `bar(**a, b)`, a positional argument after a keyword splat (PR #1782, GH #1780)
|
|
81
|
+
|
|
82
|
+
## [1.3.0] - 2026-09-28
|
|
83
|
+
|
|
84
|
+
Operator expansion release: the `default` profile grows from 88 to 111 operators, mostly around call sites and blocks, and several existing operators gain new replacements. Mutation scores will move — every new operator produces mutants your suite has never been measured against. Pin the gem version and the operator profile if you need a stable score across runs.
|
|
85
|
+
|
|
86
|
+
The fixes come from a field report by [@rubdttcom](https://github.com/rubdttcom) on a Rails 8 / Minitest application (GH #1596–#1599); two of them landed as their own commits.
|
|
87
|
+
|
|
88
|
+
### Added
|
|
89
|
+
|
|
90
|
+
- **Nineteen new operators for call sites and message sends (`default` profile)** — call nodes were mutated only by selector swaps, receiver stripping and argument nil-substitution (epic GH #1420):
|
|
91
|
+
- **`call_to_nil`** — a call to `nil`, the broadest value-level probe. Skips calls whose value is discarded, receivers of another call and attribute writes, where the result is noise (PR #1635, GH #1455)
|
|
92
|
+
- **`safe_navigation_removal`** — `a&.b` to `a.b`. A survivor means no test reaches the call with a nil receiver. Skips `self` and literal receivers, which are never nil (PR #1636, GH #1457)
|
|
93
|
+
- **`attribute_write_to_read`** — `a.foo = b` to `a.foo`, and `a[i] = b` to `a[i]`: proves the write is observed (PR #1637, GH #1458)
|
|
94
|
+
- **`argument_propagation`** — `normalize(value)` to `value`: proves the method transforms its input (PR #1638, GH #1459)
|
|
95
|
+
- **`argument_list_removal`** — `foo(a, b)` to `foo`, every argument kind at once; also covers the single-argument case `argument_removal` never reached (PR #1639, GH #1460, #1461)
|
|
96
|
+
- **`keyword_argument_removal`** — drops one `key: value` pair at a call site, which no operator touched before (PR #1642, GH #1462)
|
|
97
|
+
- **`double_negation_removal`** — `!!x` to `x`: distinguishes a truthy object from `true` (PR #1643, GH #1463)
|
|
98
|
+
- **`regexp_anchor_to_predicate`** — `x =~ /^foo/` to `x.start_with?("foo")`, and `$` / `\Z` to `end_with?`. Line anchors also match after a newline, so a survivor means no test feeds multi-line input, or the anchor should have been `\A` / `\z` (PR #1644, GH #1464)
|
|
99
|
+
- **`reduce_to_sum`** — `reduce(:+)` to `sum`: differs on empty collections, non-numeric elements and float precision (PR #1646, GH #1465)
|
|
100
|
+
- **`array_coercion_to_literal`** — `Array(x)` to `[x]`: differs for `nil`, arrays and hashes (PR #1647, GH #1466)
|
|
101
|
+
- **`to_i_to_integer`** — `x.to_i` to `Integer(x)`: `Integer()` rejects malformed input and honours radix prefixes (`"0x1A"`, `"012"`) (PR #1648, GH #1467)
|
|
102
|
+
- **`coercion_emptying`** — `to_a` / `to_h` / `to_s` (and `to_ary` / `to_hash` / `to_str`) to `[]` / `{}` / `""`: proves the content is asserted, not just the type (PR #1650, GH #1468)
|
|
103
|
+
- **`dynamic_dispatch_resolution`** — `obj.send(:m)` to `obj.m`, emitted only where visibility checks can differ (PR #1641, GH #1469)
|
|
104
|
+
- **`const_get_to_constant_path`** — `X.const_get(:Y)` to `X::Y`: differs on top-level and private constants and `inherit = false` (PR #1652, GH #1470)
|
|
105
|
+
- **`proc_to_lambda`** — `proc { }` / `Proc.new { }` to `lambda { }`: arity checks, array auto-splat and `return` semantics (PR #1653, GH #1471)
|
|
106
|
+
- **`dig_to_fetch_chain`** — `x.dig(a, b)` to `x.fetch(a).dig(b)` (PR #1654, GH #1472)
|
|
107
|
+
- **`inequality_to_negated_identity`** — `a != b` to `!a.eql?(b)` and `!a.equal?(b)`; skips `nil`, boolean and symbol literals, where all three agree (PR #1656, GH #1473)
|
|
108
|
+
- **`binary_operand_promotion`** — `a + b` to `a` and `b` for arithmetic and bitwise operators, skipping integer identities such as `a + 0` (PR #1657, GH #1474)
|
|
109
|
+
- **`receiver_constructor_swap`** — `Date` / `DateTime` / `Time.parse` to a stricter sibling (`iso8601`, `strptime`, …), keyed on receiver and selector (PR #1658, GH #1475)
|
|
110
|
+
- **`symbol_to_proc_replacement`** — applies the `send_mutation` and `collection_replacement` selector tables to `&:sym` arguments, which previously got only removal (PR #1640, GH #1482)
|
|
111
|
+
- **Three new operators for blocks** — blocks were only ever removed wholesale (epic GH #1421):
|
|
112
|
+
- **`block_body_to_nil`** — the block body to `nil`, keeping the iteration. Skips `loop` and endless `cycle`, which would never terminate (PR #1661, GH #1483)
|
|
113
|
+
- **`block_body_to_raise`** — the block body to `raise`: a survivor means the block is never invoked. Skips bodies with a `rescue` clause, which would swallow it (PR #1662, GH #1484)
|
|
114
|
+
- **`block_body_promotion`** — `Base.transaction { save! }` to `save!` for parameter-less blocks: exposes wrappers whose effect is never tested, such as transactions whose rollback nothing triggers (PR #1663, GH #1485)
|
|
115
|
+
- **`warmup: rails` / `--warmup rails`** — after `--preload`, warms Rails state that otherwise initialises on each fork's first request (I18n, routes, asset paths, templates when `actionview_precompiler` is installed). Every step is side-effect free and skipped with a note if it does not apply. See "Warming up Rails before forking" in the README (PR #1671, GH #1599)
|
|
116
|
+
|
|
117
|
+
### Changed
|
|
118
|
+
|
|
119
|
+
- **Larger selector tables** — new swaps in `send_mutation` (`bytes`/`chars`, `start_with?`/`end_with?`, `ceil`/`floor`, `to_s` -> `to_str` and the other implicit conversions, `even?`/`odd?`, `pred`/`succ`, `is_a?` -> `instance_of?`, `obj.method(:m)` -> `public_method`, …), `collection_replacement` (`any?` -> `empty?`/`none?`, `find` / `max` / `min` -> `first`/`last`, `fetch` -> `key?`, `delete_if` -> `reject`, `each_with_index` -> `each`, …) and `comparison_replacement` (ordering comparisons to `eql?` / `equal?`, `=~` -> `match?`) (PRs #1649, #1651, #1655, #1659, #1660; GH #1476–#1480)
|
|
120
|
+
- **`bang_method` knows every standard-library bang pair** — the list grew from a 24-name sample to every String, Array, Hash and Set method with an in-place twin (PR #1645, GH #1481)
|
|
121
|
+
|
|
122
|
+
### Fixed
|
|
123
|
+
|
|
124
|
+
- **`tests list` resolves specs the way `run` does** — it always used the RSpec layout, so Minitest and Test::Unit projects saw `(no spec found)` for every source, and it ignored `spec_mappings` and `spec_pattern`. A source mapped to several spec files now lists each (PR #1667, GH #1596; fix by @rubdttcom)
|
|
125
|
+
- **A preload outside `test/` or `spec/` no longer shadows gems** — the preload's own directory went onto `$LOAD_PATH`, so `--preload config/evilution_preload.rb` made `require "puma"` load the app's `config/puma.rb` (PR #1668, GH #1597; fix by @rubdttcom)
|
|
126
|
+
- **The baseline follows `fallback_to_full_suite` and `spec_mappings`** — for a source with no resolved test it ran the whole test directory even with the fallback off, and printed "running full suite"; in a real Rails suite that run timed out silently. A source declared only through `spec_mappings` also fell back to the directory, and its survivors were then reported `neutral` against a mapped test that passes. The baseline now uses the same spec selection as `run`, skips unresolved sources unless the run falls back, and reports a timed-out baseline explicitly (PR #1669, GH #1598)
|
|
127
|
+
- **Projects that raise on warnings no longer error every mutation of a file with a neutralized class-body call** — before re-evaluating a mutated file, evilution replaces non-idempotent class-body calls such as `deprecate :lift, :coerce` with `nil`, which Ruby flags under `-w` as "possibly useless use of nil in void context". A suite that raises on warnings (dry-monads) then scored 545 of 546 mutations of `maybe.rb` as errors; the replacement is now `()` (GH #1673)
|
|
128
|
+
|
|
5
129
|
## [1.2.0] - 2026-09-21
|
|
6
130
|
|
|
7
131
|
Reporting honesty release. A run now says what it did **not** measure instead of letting the headline score speak for the whole target set: files that resolved to no spec fail the run, subjects nothing reached are named, neutral results record why, and the printed verdict and the exit code finally share one threshold. The `default` profile also grows from 80 to 88 operators, so mutation scores will move — every new operator produces mutants your suite has never been measured against. Pin the gem version and the operator profile if you need a stable score across runs.
|