evilution 0.28.0 → 0.30.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (112) hide show
  1. checksums.yaml +4 -4
  2. data/.beads/interactions.jsonl +106 -0
  3. data/.rubocop_todo.yml +7 -0
  4. data/CHANGELOG.md +49 -0
  5. data/README.md +194 -8
  6. data/docs/versioning.md +53 -0
  7. data/lib/evilution/ast/constant_names.rb +28 -11
  8. data/lib/evilution/ast/heredoc_span.rb +99 -0
  9. data/lib/evilution/ast/pattern/parser.rb +29 -17
  10. data/lib/evilution/baseline.rb +15 -2
  11. data/lib/evilution/cli/commands/compare.rb +13 -0
  12. data/lib/evilution/cli/commands/session_diff.rb +6 -4
  13. data/lib/evilution/cli/commands/subjects.rb +6 -3
  14. data/lib/evilution/cli/commands/util_mutation.rb +24 -19
  15. data/lib/evilution/cli/parser/command_extractor.rb +12 -12
  16. data/lib/evilution/cli/parser/file_args.rb +3 -1
  17. data/lib/evilution/cli/parser/options_builder.rb +31 -3
  18. data/lib/evilution/cli/parser/stdin_reader.rb +2 -2
  19. data/lib/evilution/cli/parser.rb +18 -20
  20. data/lib/evilution/cli/printers/environment.rb +19 -19
  21. data/lib/evilution/cli/printers/session_diff.rb +8 -8
  22. data/lib/evilution/compare/normalizer.rb +10 -5
  23. data/lib/evilution/config/file_loader.rb +40 -1
  24. data/lib/evilution/config.rb +21 -11
  25. data/lib/evilution/disable_comment.rb +21 -12
  26. data/lib/evilution/equivalent/heuristic/dead_code.rb +8 -1
  27. data/lib/evilution/feedback/setup_warning.rb +79 -0
  28. data/lib/evilution/gem_detector.rb +132 -0
  29. data/lib/evilution/integration/loading/body_call_neutralizer.rb +190 -0
  30. data/lib/evilution/integration/loading/mutation_applier.rb +35 -15
  31. data/lib/evilution/integration/loading/redefinition_recovery.rb +58 -1
  32. data/lib/evilution/integration/minitest.rb +60 -16
  33. data/lib/evilution/integration/rspec/result_builder.rb +20 -1
  34. data/lib/evilution/integration/rspec.rb +20 -1
  35. data/lib/evilution/isolation/fork.rb +104 -27
  36. data/lib/evilution/mcp/info_tool/actions/subjects.rb +32 -23
  37. data/lib/evilution/mcp/info_tool/actions/tests.rb +22 -12
  38. data/lib/evilution/mcp/info_tool/request_parser.rb +3 -1
  39. data/lib/evilution/mcp/info_tool/response_formatter.rb +14 -1
  40. data/lib/evilution/mcp/info_tool.rb +10 -2
  41. data/lib/evilution/mcp/mutate_tool/option_parser.rb +4 -2
  42. data/lib/evilution/mcp/mutate_tool/report_trimmer.rb +58 -1
  43. data/lib/evilution/mcp/mutate_tool/survived_enricher.rb +19 -9
  44. data/lib/evilution/mcp/mutate_tool.rb +49 -17
  45. data/lib/evilution/mcp/session_tool.rb +34 -22
  46. data/lib/evilution/mcp.rb +6 -0
  47. data/lib/evilution/mutation.rb +26 -16
  48. data/lib/evilution/mutator/base.rb +66 -16
  49. data/lib/evilution/mutator/operator/argument_method_call_replacement.rb +59 -0
  50. data/lib/evilution/mutator/operator/argument_nil_substitution.rb +11 -14
  51. data/lib/evilution/mutator/operator/argument_removal.rb +11 -14
  52. data/lib/evilution/mutator/operator/begin_unwrap.rb +17 -5
  53. data/lib/evilution/mutator/operator/bitwise_complement.rb +26 -19
  54. data/lib/evilution/mutator/operator/block_param_removal.rb +50 -8
  55. data/lib/evilution/mutator/operator/block_pass_removal.rb +19 -15
  56. data/lib/evilution/mutator/operator/case_when.rb +7 -5
  57. data/lib/evilution/mutator/operator/conditional_branch.rb +22 -22
  58. data/lib/evilution/mutator/operator/equality_to_identity.rb +8 -3
  59. data/lib/evilution/mutator/operator/explicit_super_mutation.rb +36 -14
  60. data/lib/evilution/mutator/operator/index_to_at.rb +18 -5
  61. data/lib/evilution/mutator/operator/index_to_dig.rb +12 -6
  62. data/lib/evilution/mutator/operator/index_to_fetch.rb +5 -4
  63. data/lib/evilution/mutator/operator/keyword_argument.rb +30 -25
  64. data/lib/evilution/mutator/operator/last_expression_removal.rb +46 -0
  65. data/lib/evilution/mutator/operator/mixin_removal.rb +20 -14
  66. data/lib/evilution/mutator/operator/multiple_assignment.rb +12 -13
  67. data/lib/evilution/mutator/operator/receiver_replacement.rb +38 -7
  68. data/lib/evilution/mutator/operator/regex_simplification.rb +62 -67
  69. data/lib/evilution/mutator/operator/rescue_body_replacement.rb +9 -8
  70. data/lib/evilution/mutator/operator/rescue_removal.rb +58 -12
  71. data/lib/evilution/mutator/operator/splat_operator.rb +28 -1
  72. data/lib/evilution/mutator/operator/string_literal.rb +83 -6
  73. data/lib/evilution/mutator/operator/superclass_removal.rb +21 -15
  74. data/lib/evilution/mutator/registry.rb +2 -0
  75. data/lib/evilution/parallel/work_queue/dispatcher.rb +15 -8
  76. data/lib/evilution/parallel/work_queue/worker.rb +10 -7
  77. data/lib/evilution/parallel/work_queue.rb +35 -18
  78. data/lib/evilution/reporter/cli/item_formatters/coverage_gap.rb +13 -8
  79. data/lib/evilution/reporter/cli/line_formatters/error_rate_warning.rb +29 -0
  80. data/lib/evilution/reporter/cli/line_formatters/mutations.rb +17 -8
  81. data/lib/evilution/reporter/cli/metrics_block.rb +2 -0
  82. data/lib/evilution/reporter/json.rb +54 -18
  83. data/lib/evilution/reporter/suggestion/diff_helpers.rb +0 -13
  84. data/lib/evilution/reporter/suggestion/diff_lines.rb +28 -0
  85. data/lib/evilution/reporter/suggestion/templates/minitest.rb +20 -14
  86. data/lib/evilution/reporter/suggestion/templates/rspec.rb +19 -13
  87. data/lib/evilution/result/mutation_result.rb +12 -6
  88. data/lib/evilution/runner/baseline_runner.rb +20 -9
  89. data/lib/evilution/runner/diagnostics.rb +13 -9
  90. data/lib/evilution/runner/isolation_resolver.rb +75 -12
  91. data/lib/evilution/runner/mutation_executor/result_cache.rb +3 -1
  92. data/lib/evilution/runner/mutation_executor/strategy/parallel.rb +32 -10
  93. data/lib/evilution/runner/mutation_executor/strategy/sequential.rb +1 -1
  94. data/lib/evilution/runner/mutation_executor.rb +2 -0
  95. data/lib/evilution/runner/mutation_planner.rb +53 -16
  96. data/lib/evilution/runner/subject_pipeline.rb +21 -11
  97. data/lib/evilution/runner.rb +3 -3
  98. data/lib/evilution/session/diff.rb +15 -6
  99. data/lib/evilution/session/schema.rb +44 -0
  100. data/lib/evilution/session/store.rb +5 -1
  101. data/lib/evilution/spec_ast_cache.rb +26 -12
  102. data/lib/evilution/version.rb +1 -1
  103. data/lib/evilution.rb +2 -0
  104. data/schema/evilution.config.schema.json +205 -0
  105. data/script/build_runtime_snapshot +88 -0
  106. data/script/memory_check +11 -5
  107. data/script/run_self_baseline +79 -0
  108. data/script/run_self_validation +54 -0
  109. data/scripts/benchmark_density +10 -9
  110. data/scripts/compare_mutations +38 -21
  111. data/scripts/mutant_json_adapter +7 -4
  112. metadata +16 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: dda90ba09660e134411bad5df79ba56075ed9661f8e94aa3b366478cc3191755
4
- data.tar.gz: c1c5606e0a2c082dd1d7ec24738f0558b7cc94bfc3632cd4c2fdd200d5ad5e11
3
+ metadata.gz: 34bc612e6537f856f98a6b1911989ddb89d5211bca426ebd1a08f8dddfe4eade
4
+ data.tar.gz: c6875ae71bb4092184df2c7a05f3efccca97a9db57c91c85e09f6bbf20c3c8d9
5
5
  SHA512:
6
- metadata.gz: 30d4d7dcdcb9d88615fa5d37205bd02a307f32b6150a7ee7fa55b8397b677d40dd26e5777043fb6dfeeddf2559c8e79ae23276574ede65627ccf95f9effcd31e
7
- data.tar.gz: a657c55edcffd46c6883c4146cd97471db4c51940def54027a49f01ff89a29e7fd6fd4c28e758d9d7207623d664c320ccc22a9a01430abd5d26574afb1142932
6
+ metadata.gz: 46d8c283c0fef3758c0369533a00a8db31337b263119d182133ad5d86d2dab7c2d60d2baa3ffcc53f87d7e605a84c880be2f9f9692a1bdef63642b670a50cb57
7
+ data.tar.gz: 7f492bfbff46d333d68e271b63b1ac10f1b9adf97a9d38a20f1255b77f3ada298ae92bad102a8835797432450130b179009129ce826a622a33b5346f9bfac58b
@@ -258,3 +258,109 @@
258
258
  {"id":"int-b9cb7738","kind":"field_change","created_at":"2026-05-01T18:06:39.17748775Z","actor":"Denis Kiselev","issue_id":"EV-gffv","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"merged"}}
259
259
  {"id":"int-983c2fe6","kind":"field_change","created_at":"2026-05-02T02:47:27.113692488Z","actor":"Denis Kiselev","issue_id":"EV-3t8l","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Audit confirmed feature already fully implemented in current master: --fail-fast CLI flag, .evilution.yml key, FailFast validator, ResultNotifier trips at threshold, sequential+parallel strategies short-circuit, summary.truncated? indicator, reporter notices (CLI/HTML/JSON), full spec coverage across notifier/sequential/parallel/runner/parser. CI signal available via summary.truncated? in reports."}}
260
260
  {"id":"int-1790a8b7","kind":"field_change","created_at":"2026-05-02T17:53:56.73309749Z","actor":"Denis Kiselev","issue_id":"EV-2gpj","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Audit confirmed refactor already done: ProcessCleanup.safe_kill / safe_wait helpers extracted to lib/evilution/process_cleanup.rb (lines 8-18), used by baseline.rb (lines 85,93,94) and parallel/work_queue/worker.rb. No Style/RescueModifier disables remain anywhere in lib/. bundle exec rubocop lib/evilution/baseline.rb clean. Existing specs pass."}}
261
+ {"id":"int-a4ad60a6","kind":"field_change","created_at":"2026-05-06T03:30:34.744627494Z","actor":"Denis Kiselev","issue_id":"EV-s24s","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Closed"}}
262
+ {"id":"int-076a3c83","kind":"field_change","created_at":"2026-05-06T03:30:41.864846348Z","actor":"Denis Kiselev","issue_id":"EV-s24s","extra":{"field":"status","new_value":"in_progress","old_value":"closed"}}
263
+ {"id":"int-01566863","kind":"field_change","created_at":"2026-05-06T07:19:50.242235949Z","actor":"Denis Kiselev","issue_id":"EV-y27w","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Obsolete: methods refactored on master (commit c6177ee). Rubocop ABC clean for these files."}}
264
+ {"id":"int-2ead0736","kind":"field_change","created_at":"2026-05-06T07:19:50.702277885Z","actor":"Denis Kiselev","issue_id":"EV-2luk","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Obsolete: methods refactored on master (commit c6177ee). Rubocop ABC clean for these files."}}
265
+ {"id":"int-57a7f7bd","kind":"field_change","created_at":"2026-05-06T07:19:51.207502619Z","actor":"Denis Kiselev","issue_id":"EV-6pj3","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Obsolete: methods refactored on master (commit c6177ee). Rubocop ABC clean for these files."}}
266
+ {"id":"int-6c362b36","kind":"field_change","created_at":"2026-05-06T07:19:51.688513357Z","actor":"Denis Kiselev","issue_id":"EV-675y","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Obsolete: methods refactored on master (commit c6177ee). Rubocop ABC clean for these files."}}
267
+ {"id":"int-5debf846","kind":"field_change","created_at":"2026-05-06T07:19:52.17818897Z","actor":"Denis Kiselev","issue_id":"EV-g8pq","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Obsolete: methods refactored on master (commit c6177ee). Rubocop ABC clean for these files."}}
268
+ {"id":"int-53e2ac7d","kind":"field_change","created_at":"2026-05-06T07:19:52.618140112Z","actor":"Denis Kiselev","issue_id":"EV-7wi7","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Obsolete: methods refactored on master (commit c6177ee). Rubocop ABC clean for these files."}}
269
+ {"id":"int-dccffc47","kind":"field_change","created_at":"2026-05-06T07:19:53.069605194Z","actor":"Denis Kiselev","issue_id":"EV-cz6e","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Obsolete: methods refactored on master (commit c6177ee). Rubocop ABC clean for these files."}}
270
+ {"id":"int-58d8260f","kind":"field_change","created_at":"2026-05-06T07:19:53.543437653Z","actor":"Denis Kiselev","issue_id":"EV-rmzx","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Obsolete: methods refactored on master (commit c6177ee). Rubocop ABC clean for these files."}}
271
+ {"id":"int-789dee22","kind":"field_change","created_at":"2026-05-06T07:19:53.965510546Z","actor":"Denis Kiselev","issue_id":"EV-5qg6","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Obsolete: methods refactored on master (commit c6177ee). Rubocop ABC clean for these files."}}
272
+ {"id":"int-85fdbe1f","kind":"field_change","created_at":"2026-05-06T07:19:54.37777323Z","actor":"Denis Kiselev","issue_id":"EV-pfz5","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Obsolete: methods refactored on master (commit c6177ee). Rubocop ABC clean for these files."}}
273
+ {"id":"int-c61f5bf7","kind":"field_change","created_at":"2026-05-06T07:19:54.831384506Z","actor":"Denis Kiselev","issue_id":"EV-ynvi","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Obsolete: methods refactored on master (commit c6177ee). Rubocop ABC clean for these files."}}
274
+ {"id":"int-f66ee100","kind":"field_change","created_at":"2026-05-06T07:19:55.253094559Z","actor":"Denis Kiselev","issue_id":"EV-ltmi","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Obsolete: methods refactored on master (commit c6177ee). Rubocop ABC clean for these files."}}
275
+ {"id":"int-d0d38103","kind":"field_change","created_at":"2026-05-06T07:19:55.730451387Z","actor":"Denis Kiselev","issue_id":"EV-dha6","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Obsolete: methods refactored on master (commit c6177ee). Rubocop ABC clean for these files."}}
276
+ {"id":"int-14872708","kind":"field_change","created_at":"2026-05-06T07:19:56.276618255Z","actor":"Denis Kiselev","issue_id":"EV-gml5","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Obsolete: methods refactored on master (commit c6177ee). Rubocop ABC clean for these files."}}
277
+ {"id":"int-3a46d2c8","kind":"field_change","created_at":"2026-05-06T07:19:56.746453231Z","actor":"Denis Kiselev","issue_id":"EV-wg1v","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Obsolete: methods refactored on master (commit c6177ee). Rubocop ABC clean for these files."}}
278
+ {"id":"int-7e6cad25","kind":"field_change","created_at":"2026-05-06T07:19:57.199497315Z","actor":"Denis Kiselev","issue_id":"EV-jf8v","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Obsolete: methods refactored on master (commit c6177ee). Rubocop ABC clean for these files."}}
279
+ {"id":"int-596241e1","kind":"field_change","created_at":"2026-05-06T07:19:57.648508843Z","actor":"Denis Kiselev","issue_id":"EV-p699","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Obsolete: methods refactored on master (commit c6177ee). Rubocop ABC clean for these files."}}
280
+ {"id":"int-47d13782","kind":"field_change","created_at":"2026-05-06T07:19:58.119871705Z","actor":"Denis Kiselev","issue_id":"EV-mur2","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Obsolete: methods refactored on master (commit c6177ee). Rubocop ABC clean for these files."}}
281
+ {"id":"int-5bcb3ba0","kind":"field_change","created_at":"2026-05-06T07:19:58.593580083Z","actor":"Denis Kiselev","issue_id":"EV-t05i","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Obsolete: methods refactored on master (commit c6177ee). Rubocop ABC clean for these files."}}
282
+ {"id":"int-d0a8a49b","kind":"field_change","created_at":"2026-05-06T07:19:59.066030169Z","actor":"Denis Kiselev","issue_id":"EV-t3os","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Obsolete: methods refactored on master (commit c6177ee). Rubocop ABC clean for these files."}}
283
+ {"id":"int-c5fd767e","kind":"field_change","created_at":"2026-05-06T07:19:59.519830731Z","actor":"Denis Kiselev","issue_id":"EV-70v7","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Obsolete: methods refactored on master (commit c6177ee). Rubocop ABC clean for these files."}}
284
+ {"id":"int-ee96343f","kind":"field_change","created_at":"2026-05-06T07:19:59.945079843Z","actor":"Denis Kiselev","issue_id":"EV-g067","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Obsolete: methods refactored on master (commit c6177ee). Rubocop ABC clean for these files."}}
285
+ {"id":"int-1088cf0f","kind":"field_change","created_at":"2026-05-06T07:20:00.369713429Z","actor":"Denis Kiselev","issue_id":"EV-vybg","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Obsolete: methods refactored on master (commit c6177ee). Rubocop ABC clean for these files."}}
286
+ {"id":"int-677bcb4c","kind":"field_change","created_at":"2026-05-06T07:20:00.849595223Z","actor":"Denis Kiselev","issue_id":"EV-b2j8","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Obsolete: methods refactored on master (commit c6177ee). Rubocop ABC clean for these files."}}
287
+ {"id":"int-49853be8","kind":"field_change","created_at":"2026-05-06T07:20:01.309796737Z","actor":"Denis Kiselev","issue_id":"EV-jxio","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Obsolete: methods refactored on master (commit c6177ee). Rubocop ABC clean for these files."}}
288
+ {"id":"int-7d1d715d","kind":"field_change","created_at":"2026-05-06T07:20:01.802408893Z","actor":"Denis Kiselev","issue_id":"EV-v1df","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Obsolete: methods refactored on master (commit c6177ee). Rubocop ABC clean for these files."}}
289
+ {"id":"int-f8751a4f","kind":"field_change","created_at":"2026-05-06T07:20:02.269343453Z","actor":"Denis Kiselev","issue_id":"EV-05x3","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Obsolete: methods refactored on master (commit c6177ee). Rubocop ABC clean for these files."}}
290
+ {"id":"int-98efe12b","kind":"field_change","created_at":"2026-05-06T07:20:02.712854653Z","actor":"Denis Kiselev","issue_id":"EV-neqr","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Obsolete: methods refactored on master (commit c6177ee). Rubocop ABC clean for these files."}}
291
+ {"id":"int-2fab6f44","kind":"field_change","created_at":"2026-05-06T07:20:03.192828055Z","actor":"Denis Kiselev","issue_id":"EV-ugrl","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Obsolete: methods refactored on master (commit c6177ee). Rubocop ABC clean for these files."}}
292
+ {"id":"int-64c45537","kind":"field_change","created_at":"2026-05-06T07:20:03.645870239Z","actor":"Denis Kiselev","issue_id":"EV-1czz","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Obsolete: methods refactored on master (commit c6177ee). Rubocop ABC clean for these files."}}
293
+ {"id":"int-b226aaaa","kind":"field_change","created_at":"2026-05-06T07:20:04.115581656Z","actor":"Denis Kiselev","issue_id":"EV-nsp3","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Obsolete: methods refactored on master (commit c6177ee). Rubocop ABC clean for these files."}}
294
+ {"id":"int-40a144bf","kind":"field_change","created_at":"2026-05-06T07:20:04.57274421Z","actor":"Denis Kiselev","issue_id":"EV-bx35","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Obsolete: methods refactored on master (commit c6177ee). Rubocop ABC clean for these files."}}
295
+ {"id":"int-bb3376cc","kind":"field_change","created_at":"2026-05-06T07:20:05.130537402Z","actor":"Denis Kiselev","issue_id":"EV-2viy","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Obsolete: methods refactored on master (commit c6177ee). Rubocop ABC clean for these files."}}
296
+ {"id":"int-6ae5b449","kind":"field_change","created_at":"2026-05-06T07:20:05.597150157Z","actor":"Denis Kiselev","issue_id":"EV-0nre","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Obsolete: methods refactored on master (commit c6177ee). Rubocop ABC clean for these files."}}
297
+ {"id":"int-f37c08ed","kind":"field_change","created_at":"2026-05-06T07:20:06.22033588Z","actor":"Denis Kiselev","issue_id":"EV-n4ai","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Obsolete: methods refactored on master (commit c6177ee). Rubocop ABC clean for these files."}}
298
+ {"id":"int-f1cc76b6","kind":"field_change","created_at":"2026-05-06T07:20:06.659235495Z","actor":"Denis Kiselev","issue_id":"EV-oyus","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Obsolete: methods refactored on master (commit c6177ee). Rubocop ABC clean for these files."}}
299
+ {"id":"int-7d54a6e7","kind":"field_change","created_at":"2026-05-06T07:20:07.091511841Z","actor":"Denis Kiselev","issue_id":"EV-h46p","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Obsolete: methods refactored on master (commit c6177ee). Rubocop ABC clean for these files."}}
300
+ {"id":"int-2bea4b64","kind":"field_change","created_at":"2026-05-06T07:20:06.87585377Z","actor":"Denis Kiselev","issue_id":"EV-n05g","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Obsolete: methods refactored on master (commit c6177ee). Rubocop ABC clean for these files."}}
301
+ {"id":"int-3b25e06c","kind":"field_change","created_at":"2026-05-06T07:20:06.448623384Z","actor":"Denis Kiselev","issue_id":"EV-htfi","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Obsolete: methods refactored on master (commit c6177ee). Rubocop ABC clean for these files."}}
302
+ {"id":"int-9fedcb1f","kind":"field_change","created_at":"2026-05-06T07:20:06.870511987Z","actor":"Denis Kiselev","issue_id":"EV-86au","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Obsolete: methods refactored on master (commit c6177ee). Rubocop ABC clean for these files."}}
303
+ {"id":"int-55d2834d","kind":"field_change","created_at":"2026-05-06T07:20:07.313207411Z","actor":"Denis Kiselev","issue_id":"EV-fyq8","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Obsolete: methods refactored on master (commit c6177ee). Rubocop ABC clean for these files."}}
304
+ {"id":"int-44442358","kind":"field_change","created_at":"2026-05-06T07:20:07.761317317Z","actor":"Denis Kiselev","issue_id":"EV-jxr1","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Obsolete: methods refactored on master (commit c6177ee). Rubocop ABC clean for these files."}}
305
+ {"id":"int-1ec5b145","kind":"field_change","created_at":"2026-05-06T07:20:08.263779524Z","actor":"Denis Kiselev","issue_id":"EV-0lhb","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Obsolete: methods refactored on master (commit c6177ee). Rubocop ABC clean for these files."}}
306
+ {"id":"int-3177494f","kind":"field_change","created_at":"2026-05-06T07:20:08.690447157Z","actor":"Denis Kiselev","issue_id":"EV-6xeh","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Obsolete: methods refactored on master (commit c6177ee). Rubocop ABC clean for these files."}}
307
+ {"id":"int-c3e862ed","kind":"field_change","created_at":"2026-05-06T07:20:09.150754493Z","actor":"Denis Kiselev","issue_id":"EV-n5vx","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Obsolete: methods refactored on master (commit c6177ee). Rubocop ABC clean for these files."}}
308
+ {"id":"int-bbb95b03","kind":"field_change","created_at":"2026-05-06T07:20:09.610416065Z","actor":"Denis Kiselev","issue_id":"EV-pbo4","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Obsolete: methods refactored on master (commit c6177ee). Rubocop ABC clean for these files."}}
309
+ {"id":"int-42dadd38","kind":"field_change","created_at":"2026-05-06T07:20:10.034048271Z","actor":"Denis Kiselev","issue_id":"EV-45kf","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Obsolete: methods refactored on master (commit c6177ee). Rubocop ABC clean for these files."}}
310
+ {"id":"int-2973ca4f","kind":"field_change","created_at":"2026-05-06T07:20:10.503854404Z","actor":"Denis Kiselev","issue_id":"EV-t2o9","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Obsolete: methods refactored on master (commit c6177ee). Rubocop ABC clean for these files."}}
311
+ {"id":"int-523d3c8c","kind":"field_change","created_at":"2026-05-06T07:20:11.036667234Z","actor":"Denis Kiselev","issue_id":"EV-qtvs","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Obsolete: methods refactored on master (commit c6177ee). Rubocop ABC clean for these files."}}
312
+ {"id":"int-be905e1b","kind":"field_change","created_at":"2026-05-06T07:20:11.472283074Z","actor":"Denis Kiselev","issue_id":"EV-psit","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Obsolete: methods refactored on master (commit c6177ee). Rubocop ABC clean for these files."}}
313
+ {"id":"int-b2204b5b","kind":"field_change","created_at":"2026-05-06T07:59:55.142970285Z","actor":"Denis Kiselev","issue_id":"EV-inyq","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Already addressed upstream in v0.29.0 (rubocop ABC clean; tuple-return migrations landed in PRs #1094-#1102)."}}
314
+ {"id":"int-20a87f61","kind":"field_change","created_at":"2026-05-06T07:59:55.620019557Z","actor":"Denis Kiselev","issue_id":"EV-bvwe","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Already addressed upstream in v0.29.0 (rubocop ABC clean; tuple-return migrations landed in PRs #1094-#1102)."}}
315
+ {"id":"int-3b31029e","kind":"field_change","created_at":"2026-05-06T07:59:56.145819366Z","actor":"Denis Kiselev","issue_id":"EV-crru","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Already addressed upstream in v0.29.0 (rubocop ABC clean; tuple-return migrations landed in PRs #1094-#1102)."}}
316
+ {"id":"int-af4d932d","kind":"field_change","created_at":"2026-05-06T07:59:55.93110283Z","actor":"Denis Kiselev","issue_id":"EV-0nep","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Already addressed upstream in v0.29.0 (rubocop ABC clean; tuple-return migrations landed in PRs #1094-#1102)."}}
317
+ {"id":"int-a16fb04a","kind":"field_change","created_at":"2026-05-07T08:38:44.320058211Z","actor":"Denis Kiselev","issue_id":"EV-i5yp","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"merged via PR #1163"}}
318
+ {"id":"int-3571ab77","kind":"field_change","created_at":"2026-05-07T09:00:32.015564768Z","actor":"Denis Kiselev","issue_id":"EV-vtoe","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"merged"}}
319
+ {"id":"int-59058caf","kind":"field_change","created_at":"2026-05-07T10:50:55.015519734Z","actor":"Denis Kiselev","issue_id":"EV-jmq4","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"merged"}}
320
+ {"id":"int-3fb9d199","kind":"field_change","created_at":"2026-05-07T13:05:45.604108546Z","actor":"Denis Kiselev","issue_id":"EV-1l8z","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"merged"}}
321
+ {"id":"int-3d3c2194","kind":"field_change","created_at":"2026-05-08T15:20:43.738723453Z","actor":"Denis Kiselev","issue_id":"EV-yyd8","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Merged via PR #1175. Harness shipped: bin/evilution-self, script/build_runtime_snapshot, script/run_self_baseline, script/run_self_validation. All 10 originally-crashing dirs measurable. Follow-ups EV-9qh1/EV-u8n5/EV-2jex tracked separately."}}
322
+ {"id":"int-9093e7db","kind":"field_change","created_at":"2026-05-08T18:03:23.097429903Z","actor":"Denis Kiselev","issue_id":"EV-9qh1","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Merged via PR #1180. Length-prefix marshal + polling waitpid loop in subject Isolation::Fork. Snapshot patch_runtime_protocol step removed (no longer needed). Spec coverage added for nested-fork pipe-EOF regression. Unblocks EV-u8n5."}}
323
+ {"id":"int-9510ef73","kind":"field_change","created_at":"2026-05-08T18:24:44.05157246Z","actor":"Denis Kiselev","issue_id":"EV-u8n5","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Resolved by EV-9qh1. Both acceptance bullets verified post-merge (parallel jobs=4 completes; self-mutation of fork.rb/worker.rb/baseline.rb succeeds). No new code needed beyond dropping the script/run_self_baseline skip list."}}
324
+ {"id":"int-93b88ded","kind":"field_change","created_at":"2026-05-10T01:58:49.010521846Z","actor":"Denis Kiselev","issue_id":"EV-2jex","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Merged. Full self-mutation re-baseline recorded: 30657 muts, 22525 killed, 7672 survived, 0 timeouts, score 74.59% across all 20 lib/ subdirs. Numbers posted to EV-j2kz description + GH#1178."}}
325
+ {"id":"int-e5511e59","kind":"field_change","created_at":"2026-05-10T03:05:25.311104857Z","actor":"Denis Kiselev","issue_id":"EV-pn5y","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Merged via PR #1183. index_to_at now skips symbol/string keyed access (Hash-shape heuristic). Verified post-fix: in_process.rb self-mut produced 0 Hash.at NoMethodError, 250 measurable muts (was 260 with ~10 invalid Hash.at attempts)."}}
326
+ {"id":"int-42aeec67","kind":"field_change","created_at":"2026-05-10T04:26:08.578561775Z","actor":"Denis Kiselev","issue_id":"EV-s5br","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Merged via PR #1184. 6 delegating accessors on MutationResult swapped from nil? checks to is_a?(ExpectedClass) guards. Verified: self-mut of subject mutation_result.rb produced 0 'undefined method ... for false' crashes (235 muts, 177 killed, exit 0)."}}
327
+ {"id":"int-c6021b93","kind":"field_change","created_at":"2026-05-10T19:05:56.88581869Z","actor":"Denis Kiselev","issue_id":"EV-t7kh","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Merged via PR #1185. Minimal verbosity now surfaces a trimmed errors sample (first 3 entries × 5-line backtrace head + key fields) when errors>0; absent when errors=0. Tool description + README updated. Unblocks paired EV-187j (default-verbosity token caps) and agent-driven debugging on partly-broken runs."}}
328
+ {"id":"int-96158302","kind":"field_change","created_at":"2026-05-11T03:15:27.20532545Z","actor":"Denis Kiselev","issue_id":"EV-187j","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Merged via PR #1186. Summary verbosity now strips diff + error_backtrace from timed_out/errors/unresolved entries; error_message preserved. 100-error synthetic payload measured <50KB. Tool description + README updated. Pairs with EV-t7kh — together unblock agent-driven debugging at scale."}}
329
+ {"id":"int-f7afa606","kind":"field_change","created_at":"2026-05-11T05:14:25.551359428Z","actor":"Denis Kiselev","issue_id":"EV-nrgw","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Merged via PR #1187. Reframed scope: bead's stale-cache hypothesis didn't reproduce — Evilution::Cache is content-addressed via SHA(file_source), so source changes invalidate correctly. Real silent-failure mode: score = killed / (total - errors - neutral - equivalent - unresolved - unparseable), so high error rates produce 'PASS 100%' that masks 16/19 errored. Fix: ErrorRateWarning line formatter prints '! High error rate: N/T (X%)' under the Score line when errors / total > 25%. Verified with Dry::Struct repro (10/11 errored → warning surfaces under misleading 100% score)."}}
330
+ {"id":"int-1f633a18","kind":"field_change","created_at":"2026-05-11T05:44:28.177265737Z","actor":"Denis Kiselev","issue_id":"EV-a43i","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Implemented explicit preload fallthrough: missing config.preload under :fork+rails warns to stderr and falls through to auto-detect chain; combined error lists both missing explicit + chain candidates when chain also empty. PR #1188 merged."}}
331
+ {"id":"int-13cc794a","kind":"field_change","created_at":"2026-05-11T06:16:58.805696639Z","actor":"Denis Kiselev","issue_id":"EV-corn","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Implemented option (a): added 'mutate' as run alias in CommandExtractor (RUN_ALIASES). Updated CLI --help banner, README CLI table, and MCP tool description (with [files...] placeholder). PR #1189 merged. GH #1172."}}
332
+ {"id":"int-980f1e21","kind":"field_change","created_at":"2026-05-11T18:16:52.733542472Z","actor":"Denis Kiselev","issue_id":"EV-kjkd","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"probe only"}}
333
+ {"id":"int-90d90758","kind":"field_change","created_at":"2026-05-12T01:35:59.390842791Z","actor":"Denis Kiselev","issue_id":"EV-hmd5","extra":{"field":"status","new_value":"open","old_value":"in_progress"}}
334
+ {"id":"int-9426e0f2","kind":"field_change","created_at":"2026-05-12T09:22:16.445201172Z","actor":"Denis Kiselev","issue_id":"EV-99r2","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"dry-monads canary complete: 3 surfaced bugs (EV-174x #1197, EV-wwx3 #1198, EV-wzmq #1199) all merged; post-merge canary 385/246/0/0 score 1.0"}}
335
+ {"id":"int-89a6abbb","kind":"field_change","created_at":"2026-05-12T09:38:41.132122586Z","actor":"Denis Kiselev","issue_id":"EV-hmd5","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"dry-types canary complete: 3 mutator output bugs filed (EV-2cv1 #1200, EV-nmhi #1201, EV-jjpt #1202); zero evilution crashes; score 0.79"}}
336
+ {"id":"int-7daa2e34","kind":"field_change","created_at":"2026-05-12T09:49:30.104392229Z","actor":"Denis Kiselev","issue_id":"EV-3xxc","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"pundit canary clean: 800 mutations / 789 killed / 0 errors / score 1.0; 2 new mutator bugs filed (EV-bjot, EV-xsg2)"}}
337
+ {"id":"int-dfdf0230","kind":"field_change","created_at":"2026-05-12T09:56:50.344492509Z","actor":"Denis Kiselev","issue_id":"EV-mw2h","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"dotenv canary complete: 984/624 killed score 0.66; 3 evilution bugs filed (EV-b0ee preload, EV-kws8 + EV-xsg2 sighting mutator); 31 NameErrors are gem-side missing require, not evilution"}}
338
+ {"id":"int-3bf7bd77","kind":"field_change","created_at":"2026-05-12T10:12:38.509609431Z","actor":"Denis Kiselev","issue_id":"EV-o5p5","extra":{"field":"status","new_value":"blocked","old_value":"in_progress"}}
339
+ {"id":"int-2fcc28b2","kind":"field_change","created_at":"2026-05-12T13:55:33.618634552Z","actor":"Denis Kiselev","issue_id":"EV-ui96","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"thor canary clean: 517/359 killed score 0.70; zero evilution bugs; survivors are thor test gaps"}}
340
+ {"id":"int-a2ec0eeb","kind":"field_change","created_at":"2026-05-12T14:05:07.302733558Z","actor":"Denis Kiselev","issue_id":"EV-lnjm","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Recursion stress canary passed (score 0.8768, 0 evilution bugs)"}}
341
+ {"id":"int-f2e146f0","kind":"field_change","created_at":"2026-05-12T14:17:32.642381092Z","actor":"Denis Kiselev","issue_id":"EV-4i26","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"IO/HTTP canary passed (score 0.6361, 0 new bugs, 5 known EV-xsg2 sightings appended)"}}
342
+ {"id":"int-66c73ae9","kind":"field_change","created_at":"2026-05-12T14:27:33.553239753Z","actor":"Denis Kiselev","issue_id":"EV-jm43","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"AST canary done: pass_with_blocking_bug. 1 new evilution bug (EV-l19q heredoc neutralizer), 2 existing bugs (EV-bjot, EV-wzmq) appended/reopened"}}
343
+ {"id":"int-2e92815c","kind":"field_change","created_at":"2026-05-12T15:01:03.20238706Z","actor":"Denis Kiselev","issue_id":"EV-l19q","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Merged via GH#1209 (PR for GH#1208). BodyCallNeutralizer now extends replacement range past heredoc terminators."}}
344
+ {"id":"int-908402ad","kind":"field_change","created_at":"2026-05-12T16:03:48.265773859Z","actor":"Denis Kiselev","issue_id":"EV-xpfi","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Rails canary pass (yaml+config smoke clean, 0 evilution bugs)"}}
345
+ {"id":"int-ff8e85b2","kind":"field_change","created_at":"2026-05-12T17:03:40.966592538Z","actor":"Denis Kiselev","issue_id":"EV-l6gx","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Merged via PR #1210 (GH#1207). Minitest 6.x + 5.x compatibility restored. Unblocks 9 canaries."}}
346
+ {"id":"int-5b7b8149","kind":"field_change","created_at":"2026-05-12T17:57:03.394930914Z","actor":"Denis Kiselev","issue_id":"EV-o5p5","extra":{"field":"status","new_value":"closed","old_value":"blocked","reason":"EV-l6gx fix verified; new follow-up EV-blnq filed for fork-isolation hang. Direct integration probe confirms Minitest works."}}
347
+ {"id":"int-0dfac9d1","kind":"field_change","created_at":"2026-05-13T01:38:31.908382613Z","actor":"Denis Kiselev","issue_id":"EV-70hd","extra":{"field":"assignee","new_value":"Denis Kiselev","old_value":""}}
348
+ {"id":"int-7616b8d5","kind":"field_change","created_at":"2026-05-13T01:40:01.770243671Z","actor":"Denis Kiselev","issue_id":"EV-aati","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"roda canary complete: score 1.0 (0 survivors), 1 new HIGH bug filed (EV-70hd #1212 BodyCallNeutralizer lazy-load), 4 mutator bug sightings appended (nmhi/xsg2/bjot/kws8). 32724 mutations / 30273 killed / 0 survived."}}
349
+ {"id":"int-05b998b4","kind":"field_change","created_at":"2026-05-13T01:58:27.852827156Z","actor":"Denis Kiselev","issue_id":"EV-720r","extra":{"field":"assignee","new_value":"Denis Kiselev","old_value":""}}
350
+ {"id":"int-a323a995","kind":"field_change","created_at":"2026-05-13T02:49:22.801975686Z","actor":"Denis Kiselev","issue_id":"EV-lqpn","extra":{"field":"assignee","new_value":"Denis Kiselev","old_value":""}}
351
+ {"id":"int-49c2877f","kind":"field_change","created_at":"2026-05-13T02:49:23.250796095Z","actor":"Denis Kiselev","issue_id":"EV-05tp","extra":{"field":"assignee","new_value":"Denis Kiselev","old_value":""}}
352
+ {"id":"int-1db1cd93","kind":"field_change","created_at":"2026-05-13T02:50:33.4238377Z","actor":"Denis Kiselev","issue_id":"EV-ien5","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"sinatra canary complete: 1 new HIGH bug filed (EV-lqpn #1214 TypeError superclass mismatch on Struct.new superclass — 6782 errors blocking 92% of base.rb mutations, score 0.0); 1 new LOW bug (EV-05tp #1215 explicit_super dangling comma); 3 mutator bug sightings appended (xsg2/kws8/bjot)"}}
353
+ {"id":"int-6b08fe75","kind":"field_change","created_at":"2026-05-13T02:54:40.126050522Z","actor":"Denis Kiselev","issue_id":"EV-n3au","extra":{"field":"assignee","new_value":"Denis Kiselev","old_value":""}}
354
+ {"id":"int-78d79b10","kind":"field_change","created_at":"2026-05-13T02:54:40.58615495Z","actor":"Denis Kiselev","issue_id":"EV-74e3","extra":{"field":"assignee","new_value":"Denis Kiselev","old_value":""}}
355
+ {"id":"int-5f3c2a62","kind":"field_change","created_at":"2026-05-13T02:54:41.035195233Z","actor":"Denis Kiselev","issue_id":"EV-m47s","extra":{"field":"assignee","new_value":"Denis Kiselev","old_value":""}}
356
+ {"id":"int-a891f124","kind":"field_change","created_at":"2026-05-13T16:10:07.942340376Z","actor":"Denis Kiselev","issue_id":"EV-wzmq","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"PR #1221 merged: widened adjacent_string_concat? to detect mixed plain+interp adjacent (line-continued + same-line). Predicate tightened per Copilot review to require StringNode/InterpolatedStringNode type AND own opening_loc, rejecting pure-interpolation EmbeddedStatementsNode parts. 3649 specs pass."}}
357
+ {"id":"int-5243c70e","kind":"field_change","created_at":"2026-05-13T16:46:03.689538886Z","actor":"Denis Kiselev","issue_id":"EV-2cv1","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"PR #1222 merged: skip block_param_removal when anonymous & param + body forwards via &. Per Copilot review, walker stops at nested DefNode boundary."}}
358
+ {"id":"int-77c3d7b0","kind":"field_change","created_at":"2026-05-13T17:00:36.3309915Z","actor":"Denis Kiselev","issue_id":"EV-nmhi","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"PR merged: string_literal skips StringNode chunks of InterpolatedSymbolNode / InterpolatedRegularExpressionNode / InterpolatedXStringNode. Chunks are not standalone literals."}}
359
+ {"id":"int-205e0413","kind":"field_change","created_at":"2026-05-14T04:35:40.188276228Z","actor":"Denis Kiselev","issue_id":"EV-n3au","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"PR #1224 merged: MCP preload param + setup_warning heuristic. Copilot review addressed (schema oneOf, mutations vs workers wording)."}}
360
+ {"id":"int-0f60034f","kind":"field_change","created_at":"2026-05-14T05:36:59.692727916Z","actor":"Denis Kiselev","issue_id":"EV-xsg2","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"PR #1225 merged: receiver_replacement skips reserved-keyword method names. Per Copilot review, writer suffix (=) stripped before keyword lookup to cover self.class= form."}}
361
+ {"id":"int-f7e471ae","kind":"field_change","created_at":"2026-05-14T06:18:02.455563481Z","actor":"Denis Kiselev","issue_id":"EV-bjot","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"PR #1226 merged: centralized HeredocSpan extension in Mutator::Base.add_mutation. Per Copilot review, skip-heuristic tightened to regex matching heredoc-anchor identifier pattern (not bare <<). Covers 8 operators via single infrastructure fix."}}
362
+ {"id":"int-3871825c","kind":"field_change","created_at":"2026-05-14T06:57:02.232644676Z","actor":"Denis Kiselev","issue_id":"EV-kws8","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"PR #1228 merged: rescue_removal walks BeginNode + uses structural clause boundaries. Covers orphan-else and orphan-rescue-class variants. Copilot review evaluated and rejected (end_keyword_loc is populated for implicit-begin shapes, no NoMethodError path)."}}
363
+ {"id":"int-f2bc98ca","kind":"field_change","created_at":"2026-05-14T07:13:14.206329238Z","actor":"Denis Kiselev","issue_id":"EV-jjpt","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"PR merged: splat_operator skips kwarg-preceded **splat to avoid positional-after-keyword."}}
364
+ {"id":"int-78870411","kind":"field_change","created_at":"2026-05-14T07:28:17.94685909Z","actor":"Denis Kiselev","issue_id":"EV-05tp","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"PR merged: explicit_super_mutation extends byte range structurally (block start / rparen / args end). Short-circuit spec switched to synthetic in-test operator."}}
365
+ {"id":"int-36e5c972","kind":"field_change","created_at":"2026-05-14T08:23:06.045690955Z","actor":"Denis Kiselev","issue_id":"EV-b0ee","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"PR merged: GemDetector multi-gemspec disambiguation via exact-entry, lib-subdir, then shortest-name fallback."}}
366
+ {"id":"int-00368bf4","kind":"field_change","created_at":"2026-05-14T09:07:21.14041556Z","actor":"Denis Kiselev","issue_id":"EV-blnq","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Not a hang — slow run with no progress feedback. Investigated 2026-05-14: 269 mutations / 202 killed / 42 survived / 25 timed_out / 0 errors / score 0.75 in 4min with -j 4 -t 10 on Shopify/liquid v5.12.0. Per-mutation Minitest test_helper re-bootstrap + 25 worker timeouts caused the perceived 10-min hang. Combined with --no-progress + non-TTY stderr (no parent output) the run looks silent until the JSON dump. Worker logs (--quiet-children --quiet-children-dir DIR) show steady progress. README updated with a 'Long Minitest fork runs — not a hang' section under §7 explaining the timing math + recommended -j/-t flags. No code change needed."}}
data/.rubocop_todo.yml CHANGED
@@ -4,3 +4,10 @@
4
4
  Metrics/AbcSize:
5
5
  Exclude:
6
6
  - "lib/evilution/runner.rb"
7
+ - "lib/evilution/isolation/fork.rb"
8
+
9
+ Metrics/ClassLength:
10
+ Exclude:
11
+ - "lib/evilution/isolation/fork.rb"
12
+ - "lib/evilution/integration/minitest.rb"
13
+ - "lib/evilution/mcp/mutate_tool.rb"
data/CHANGELOG.md CHANGED
@@ -1,5 +1,54 @@
1
1
  # Changelog
2
2
 
3
+ Versioning policy: see [docs/versioning.md](docs/versioning.md).
4
+
5
+ ## [0.30.0] - 2026-05-15
6
+
7
+ ### Added
8
+
9
+ - **Two new mutation operators bring the default registry to 74** — `LastExpressionRemoval` strips a trailing literal (`true`/`false`/`nil`/integer/symbol) from a method body, targeting the idiomatic `def predicate?; side_effect; true; end` pattern where the explicit literal return value is the high-signal behavior under test (EV-74e3, PR #1236). `ArgumentMethodCallReplacement` drops a method call appearing in argument position (`fn(x.attr)` → `fn(x)`, also inside hash values, array elements, and keyword arguments), surfacing the common log-payload / structured-data substitution pattern under its own operator name instead of buried under `method_call_removal` (EV-m47s, PR #1237)
10
+ - **`MutationPlanner` now deduplicates byte-identical mutations across operators** — key is `(file_path, mutated_source)`; first-registered operator wins. Eliminates wasted compute and inflated denominators when multiple operators produce the same edit (e.g. `statement_deletion` + `last_expression_removal` both deleting a trailing literal). `DeadCode` equivalence heuristic widened to recognize `last_expression_removal` so unreachable trailing literals retain equivalent-classification regardless of which operator name survives dedup (PR #1236 and follow-up review)
11
+ - **`BodyCallNeutralizer`: strip non-idempotent class/module body calls before re-eval in fork workers** — DSL registries (`register_mixin`, plugin registration, etc.) raise on second invocation because they assume single-eval semantics. The parent's preload already executed them; re-running them in the child fork is wasted work that aborts the eval before the mutated method takes effect. The neutralizer walks the Prism tree, replaces non-allowlisted top-level call statements with `nil` byte-for-byte, and extends the replacement range to cover heredoc bodies and terminators. Lazy-load-aware: a `$LOADED_FEATURES` snapshot taken at parent preload-end gates neutralization on whether the target file was actually preloaded — first-load-in-child files (e.g. roda's `lib/roda/plugins/typecast_params.rb`) are left intact so subsequent statements depending on those DSL-defined methods do not cascade `NameError` (#1195, EV-70hd PR #1232)
12
+ - **Setup-warning subsystem surfaces silent mutation failures** — when ≥80% of mutations error with ≥80% of those errors sharing a single error class, the warning formatter emits a class-specific hint (`NameError` → preload pointer; `LoadError` → require path; etc.) telling the user the run's numbers are unreliable and where to look. Wired into the CLI text reporter; visible in MCP `evilution-mutate` output too (#1216, #1168)
13
+ - **`mutate` CLI alias for `run`** — `evilution mutate path/foo.rb` is now equivalent to `evilution run path/foo.rb`; matches the `gem` name users reach for first (#1172)
14
+ - **`--preload PATH` flag with explicit fallback + error surface** — supersedes implicit autoloading. Resolves the path with explicit error messages when the file is missing or unreadable; falls back to the inferred convention only when explicitly opted in. MCP option parser accepts boolean `false` to disable preload entirely (#1171)
15
+ - **Method splicing for live method redefinition (`Evilution::Mutator::Splice`)** — supports method-level swaps in workers that previously required full source re-eval. Plumbed alongside the existing source-evaluator strategy (#1194)
16
+ - **Fork-protocol length-prefixed payloads** — replaces the ad-hoc line-terminated protocol that could hang when payload contents contained newlines. Worker self-baseline script can now use multiple jobs safely; the previous skip list for fork-using files was removed (#1176, #1177, #1178)
17
+ - **MCP / session / config schema versioning** — MCP tool envelopes carry `Evilution::MCP::CONTRACT_VERSION` (currently `1`); session JSON files declare a `schema_version`; configuration files (`.evilution.yml`) validated against a versioned schema. Forward compatibility now follows a documented policy (#856, #857, #858)
18
+ - **`docs/versioning.md`** — explicit policy on what counts as the public contract, what triggers a major bump, and how deprecations work. Linked from the top of `CHANGELOG.md` and the `## Versioning` section of `README.md` (#864)
19
+ - **Dual-runtime harness scripts for self-mutation testing** — run evilution's own suite against mutated evilution code in a separate Ruby process, isolating bootstrap effects (#1175)
20
+
21
+ ### Fixed
22
+
23
+ - **Mutation scoring no longer silently inflates kills when RSpec returns nonzero with zero examples loaded** — `Baseline` now accepts `test_files:` and honors `--spec` at the baseline phase (previously the `--spec` flag was only consulted at mutation time, so the misleading "No matching test found... Use --spec to specify the test file" warning fired even when the user *did* pass `--spec`). `Integration::RSpec#execute_run` captures `RSpec.world.example_count` after the run; if the status is nonzero and zero examples loaded, `ResultBuilder#from_run` returns an explicit error hash so `classify_status` reports `:error` instead of falling through to `:killed`. Without this, environments with `fail_if_no_examples = true`, autoload mismatches, or spec-file load failures would mark every mutation as killed regardless of whether any example ran (EV-720r, PR #1234)
24
+ - **`class X < Struct.new(...)` (or `Data.define`, dynamic `Class.new`) no longer crashes the eval with `TypeError: superclass mismatch`** — `RedefinitionRecovery` now handles `TypeError` for messages containing "superclass mismatch": strips the constants the source declares (same path as the existing `ArgumentError 'already defined'` recovery) and retries once. If the retry still raises, the mutation reports `:error` rather than being silently miscounted as survived. Unblocks sinatra's `lib/sinatra/base.rb` and similar Rack-middleware-style anonymous-parent class patterns (EV-lqpn, PR #1235)
25
+ - **Gem detector now disambiguates multiple gemspecs in a single root** — when a repository ships e.g. `dotenv.gemspec` alongside `dotenv-rails.gemspec`, the previous `Dir.glob.first` was filesystem-order-dependent and often picked the wrong companion gem, triggering `uninitialized constant Rails` at preload. New three-tier resolution: exact-entry match against the target's `lib/foo.rb` path, then first-lib-subdirectory match, then the shortest gemspec basename as the conventional "parent" gem (EV-b0ee, PR #1224)
26
+ - **Heredoc-body orphaning across mutation operators centralized in `Evilution::AST::HeredocSpan`** — operators whose byte edit straddles a `<<~MARKER` anchor (argument_removal, argument_nil_substitution, method_call_removal, statement_deletion, method_body_replacement, block_removal, conditional_branch, string_interpolation, etc.) previously emitted unparseable mutations whenever the kept range included the heredoc opener without its body/terminator. `Mutator::Base#add_mutation` now extends the byte range via a single shared visitor; when the replacement itself re-references a heredoc anchor, the mutation is skipped rather than emitted as broken bytes (EV-bjot, PR #1223)
27
+ - **`receiver_replacement` skips reserved-keyword method names** — replacing `obj.if` (where `if` is the method name spelled as a Ruby keyword) with bare `if` produced unparseable Ruby. The operator now strips writer-form `=` suffixes and bails out when the candidate is a Ruby reserved keyword (EV-xsg2, PR #1222)
28
+ - **`rescue_removal` removes the orphan `else` clause when stripping the sole `rescue`** — `begin; ...; rescue Foo; ...; else; ...; end` with the rescue clause removed previously left a dangling `else` without a matching `rescue`, which is invalid Ruby. The operator now visits `BeginNode` directly and computes structural clause boundaries, dropping orphan else atoms (EV-kws8, PR #1221)
29
+ - **`explicit_super` "remove all args" trims the dangling comma** — `super(a, b)` → `super()` was correctly handled; `super(a, b,)` → `super(,)` was not. The trailing-args boundary now walks block-start / rparen / args-end so the resulting `super` is always parseable (EV-05tp, PR #1230)
30
+ - **`positional-after-keyword` syntax error in argument removal** — eliminated cases where positional arg removal left a kwarg followed by a positional in the result, which Ruby rejects (#1202)
31
+ - **Interpolated-node string parts no longer crash mutators on non-string segments** — `visit_interpolated_symbol_node` / `visit_interpolated_regular_expression_node` / `visit_interpolated_x_string_node` now skip embedded StringNode parts instead of treating them as standalone string literals (EV-nmhi, #1201)
32
+ - **`block_param_removal` anonymous-forward safety check** — body uses of `&` / `*` / `**` previously crashed when the corresponding block-param was removed. The operator now scans the body for anonymous forwards before deciding to remove (EV-2cv1, #1200)
33
+ - **`string_literal` adjacent-string concatenation handled** — Ruby implicitly concatenates adjacent string literals at parse time; mutating one half could leave a syntactically wrong fragment. The operator now detects adjacent quoted literals via Prism's part-type predicates and `opening_loc`, and skips when the result would be unparseable (#1220)
34
+ - **`string_literal` backslash-continuation handling** — multi-line literals joined by trailing `\` survived mutation as half-statements; now correctly span the continuation range (#1196)
35
+ - **`BodyCallNeutralizer` heredoc handling preserves parseable output** — when a neutralized call carried a heredoc argument, the replacement-range collector now walks every variant of interpolated-string / x-string / interpolated-symbol / regex with a `heredoc?` predicate and extends the end offset to the heredoc terminator's line (#1208)
36
+ - **Minitest version compatibility (Minitest 6 removed `__run`)** — `Integration::Minitest` now dispatches to the correct runner method based on the installed Minitest version; integration spec updated to assert the dispatch contract without `NoMethodError` regressions (#1207)
37
+ - **Nil-replacement crash in parallel cleanup accessors** — pool teardown could call accessors on partially-initialized worker state; nil-guards added in the affected paths (#1174)
38
+ - **`indexable?` skips symbol/string keys** — the index-conversion operators no longer attempt receiver mutation on call sites whose argument is itself a symbol/string literal (the receiver is necessarily indexable in those cases; the mutation produced no new signal) (#1173)
39
+ - **Error rate warning formatter wired into text reporter** — high error rates now produce a visible single-line warning before the mutations breakdown (#1168)
40
+
41
+ ### Changed
42
+
43
+ - **MCP `evilution-mutate` default verbosity tightened to fit agent token caps** — minimal verbosity reports only the high-signal slice (summary + survived); full verbosity audited for unresolved-diffs leaks. Error sampling at minimal verbosity (cap per error class) prevents deadlock when thousands of mutations fail with the same exception (#1169, #1170, EV-r1tt)
44
+
45
+ ## [0.29.0] - 2026-05-06
46
+
47
+ ### Changed
48
+
49
+ - **Internal codebase hygiene sweep — `Metrics/AbcSize` ceiling tightened from `25` → `17`** — every method exceeding the new threshold was refactored via pure extract-method (no behavior change). ~48 sites across `lib/evilution/{ast,cli,compare,config,disable_comment,integration,mcp,mutation,mutator,parallel,reporter,runner,session,spec_ast_cache}` plus supporting `scripts/` utilities. No public API, CLI flag, or output changes; mutation operators and report emission are bit-identical. The upper bound on per-method ABC is now strictly enforced repo-wide — only `lib/evilution/runner.rb` remains in `.rubocop_todo.yml` (#371, PR #1160 + per-file sub-PRs)
50
+ - **Tuple-return methods across the runner pipeline migrated to named `Data.define` value objects** — internal-only refactor introducing typed return shapes for `Runner::MutationExecutor#call` (→`ExecutionResult`), `Runner::MutationPlanner#call` (→`Plan` plus internal `GenerationResult` / `DisabledFilterResult` / `SigFilterResult` / `EquivalentFilterResult`), `Parallel::WorkQueue` outputs, `Cache#partition` (→`Partition`), `Config.normalize_limit` (→`LimitResult`), `Mutation::Slicer.collect_chain` (→`Chain`), `slice_affected_lines` (→`AffectedSlices`), `CLI::Parser::FilesAndRanges` (→`ParsedPaths`), and assorted CLI command helpers. Improves call-site readability without affecting external behavior (#948, PR #1094; #949, PR #1095; #950, PR #1096; #951, PR #1097; #952, PR #1098; #953, PR #1099; #954, PR #1100; #955, PR #1101; #956, PR #1102)
51
+
3
52
  ## [0.28.0] - 2026-05-03
4
53
 
5
54
  ### Added