evilution 0.30.3 → 0.30.4
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 +2 -0
- data/CHANGELOG.md +8 -0
- data/lib/evilution/integration/minitest.rb +35 -4
- data/lib/evilution/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 2bd9eaca72cb973c6e11841144b8bae68d2a838aef1ff64c429e18b4090505f1
|
|
4
|
+
data.tar.gz: bbdedbc5ef66ca367deeec89a53399ce83a235616fe2ac179ed98bf880f8be9b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b7cf12d8381e05d66b1a2ffcf1c243e3e18d66f8f073de892d40ff139bb6952214ac5c6bdcff3ab026dd475601629790e7c4d5f86f8315a8baf989bcb5b4aa7b
|
|
7
|
+
data.tar.gz: 21a523a1f2753c5e70b9fb2d53262d28b169661b75c2bd2ca44ce5f9e5c6234591f6d8dcc935fea8c49a79689d7be5a2883cae6ff4517b711379b80b8d8315bf
|
data/.beads/interactions.jsonl
CHANGED
|
@@ -385,3 +385,5 @@
|
|
|
385
385
|
{"id":"int-434f659f","kind":"field_change","created_at":"2026-05-15T12:15:28.901913417Z","actor":"Denis Kiselev","issue_id":"EV-225l","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Canary PASS 0.30.2 (re-run, earlier skip was wrong). Baseline 285/286 (1 error = port-9736-hardcoded test, infra collateral). stat.rb 95.92%, job.rb 100% (451 muts, 1 equivalent). No evilution bugs. Ran against shared docker redis on 6381 with 3-line test_helper.rb patch (which-guard, backtick self-spawn, port). Artifact .artifacts/resque_resque.yml."}}
|
|
386
386
|
{"id":"int-d1684261","kind":"field_change","created_at":"2026-05-15T13:01:27.370142624Z","actor":"Denis Kiselev","issue_id":"EV-laxo","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Investigation complete. Root causes found, both confirmed via instrumented iseq probing. pagy 0%: fork isolation clobbers eval'd mutation — spec require()s lazily-loaded target file not in $LOADED_FEATURES, reloads original from disk (EV-vxgl #1253 P1). kaminari 0%: kaminari runs on test-unit gem not Minitest (ActiveSupport::TestCase < Test::Unit::TestCase), test classes never Minitest::Runnable, 0 tests dispatch — plus evilution silently scores 0% instead of erroring (EV-5dxk #1254 P2). Original hypothesis (reset_state runnables clear) was wrong — disproven."}}
|
|
387
387
|
{"id":"int-011584d4","kind":"field_change","created_at":"2026-05-15T15:55:27.437673072Z","actor":"Denis Kiselev","issue_id":"EV-vxgl","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Fixed PR (merged). MutationApplier#mark_feature_loaded registers realpath in $LOADED_FEATURES post-eval — spec require() no longer reloads original. pagy jobs=4: 0% -> 82.81%. Residual gap vs jobs=1 is separate (EV-wu8w in_process inflation)."}}
|
|
388
|
+
{"id":"int-c44e7652","kind":"field_change","created_at":"2026-05-16T12:45:46.793709029Z","actor":"Denis Kiselev","issue_id":"EV-xfaj","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Fixed in PR #1260 — run_minitest counts test methods from Minitest::Runnable.runnables registry instead of an evictable reporter"}}
|
|
389
|
+
{"id":"int-eea19850","kind":"field_change","created_at":"2026-05-16T14:22:49.671269232Z","actor":"Denis Kiselev","issue_id":"EV-wu8w","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Fixed in PR #1264 — run_minitest reads verdict from evilution's own per-run SummaryReporter attached after plugin init"}}
|
data/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
Versioning policy: see [docs/versioning.md](docs/versioning.md).
|
|
4
4
|
|
|
5
|
+
## [0.30.4] - 2026-05-16
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
- **Minitest integration no longer errors every mutation when the project test helper calls `Minitest::Reporters.use!`** — a regression shipped in 0.30.3. The EV-5dxk zero-tests guard read `summary.count` from a `SummaryReporter` that evilution adds to its `CompositeReporter`. But when the target's test helper uses the `minitest-reporters` gem (`Minitest::Reporters.use!` — an extremely common setup), that plugin **replaces** the composite's reporters during `Minitest.init_plugins`, evicting evilution's own `SummaryReporter`. `summary.count` then never advanced — it read 0 even when tests ran — so the guard false-fired and every mutation was reported as errored ("no Minitest tests executed"), collapsing the score to a meaningless 0/0. `run_minitest` now derives the dispatched test-method count from the runnable registry (`Minitest::Runnable.runnables`), which is immune to reporter plugins. Surfaced by the EV-7764 pagy stability canary (EV-xfaj, PR #1260, GH #1259)
|
|
10
|
+
- **In-process isolation no longer false-kills genuinely-equivalent mutations and inflates the score** — `run_minitest` returned `passed: reporter.passed?`. When the target test helper calls `Minitest::Reporters.use!`, `init_plugins` replaces the composite's reporters with `minitest-reporters`' `DelegateReporter`, which delegates to a process-global reporter created once by `use!` and never reset between runs. Under in-process isolation one process runs every mutation in sequence, so that reporter's failures accumulate: `reporter.passed?` then reported `false` for every mutation after the first genuine kill, false-killing real survivors. On the pagy `request.rb` canary, in-process scored 98.44% against fork's correct 82.81%. `run_minitest` now attaches evilution's own fresh `SummaryReporter` to the composite **after** plugin init (so init_plugins cannot evict it) and reads the run's verdict from that per-run reporter; in-process and fork now converge (EV-wu8w, PR #1264, GH #1263)
|
|
11
|
+
- **`MinitestCrashDetector` survives reporter-plugin eviction** — the same `Minitest::Reporters.use!` swap that evicted evilution's `SummaryReporter` also detached the `MinitestCrashDetector`, which was attached to the composite before `initialize_minitest_state`. With the detector evicted, `build_minitest_result`'s `detector.only_crashes?` path went dead on `minitest-reporters` projects: a crash-only mutation result lost its `test_crashed` / `error` / `error_class` crash diagnostics and returned a plain killed result. The detector is now attached after plugin init alongside the `SummaryReporter`, keeping it in the live composite (EV-8z2n, PR #1265, GH #1262)
|
|
12
|
+
|
|
5
13
|
## [0.30.3] - 2026-05-16
|
|
6
14
|
|
|
7
15
|
### Fixed
|
|
@@ -178,16 +178,47 @@ class Evilution::Integration::Minitest < Evilution::Integration::Base
|
|
|
178
178
|
options[:io] = out
|
|
179
179
|
|
|
180
180
|
reporter = ::Minitest::CompositeReporter.new
|
|
181
|
-
summary = ::Minitest::SummaryReporter.new(out, options)
|
|
182
|
-
reporter << summary
|
|
183
|
-
reporter << detector
|
|
184
181
|
|
|
185
182
|
self.class.initialize_minitest_state(reporter, options)
|
|
183
|
+
summary = attach_evilution_reporters(reporter, detector, out, options)
|
|
186
184
|
reporter.start
|
|
187
185
|
dispatch_minitest_suites(reporter, options)
|
|
188
186
|
reporter.report
|
|
189
187
|
|
|
190
|
-
{ passed:
|
|
188
|
+
{ passed: summary.passed?, count: minitest_method_count }
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
# Attach evilution's own reporters to the composite AFTER plugin init, and
|
|
192
|
+
# read the run's verdict from the SummaryReporter rather than reporter.passed?.
|
|
193
|
+
#
|
|
194
|
+
# A target test helper that calls Minitest::Reporters.use! makes
|
|
195
|
+
# init_plugins replace the composite's reporters with minitest-reporters'
|
|
196
|
+
# DelegateReporter, which delegates to a process-global reporter created
|
|
197
|
+
# once by use!. That global reporter is never reset between runs, so under
|
|
198
|
+
# in_process isolation — where one process runs every mutation in sequence
|
|
199
|
+
# — its failures accumulate: reporter.passed? would report false for every
|
|
200
|
+
# mutation after the first genuine kill, false-killing real survivors and
|
|
201
|
+
# inflating the score. Anything attached before init_plugins is likewise
|
|
202
|
+
# evicted — that silently disabled the MinitestCrashDetector, so
|
|
203
|
+
# build_minitest_result's only_crashes? path went dead and crashes were
|
|
204
|
+
# downgraded from :error to :killed. Attaching both reporters here, after
|
|
205
|
+
# init_plugins has run, keeps them in the live composite for the current
|
|
206
|
+
# run. Returns the SummaryReporter.
|
|
207
|
+
def attach_evilution_reporters(reporter, detector, out, options)
|
|
208
|
+
summary = ::Minitest::SummaryReporter.new(out, options)
|
|
209
|
+
reporter << summary
|
|
210
|
+
reporter << detector
|
|
211
|
+
summary
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
# Count dispatched test methods from the runnable registry, not a reporter.
|
|
215
|
+
# A project test helper that calls Minitest::Reporters.use! swaps the
|
|
216
|
+
# composite's reporters during init_plugins, evicting evilution's
|
|
217
|
+
# SummaryReporter — a reporter-based count then reads 0 even on a real run.
|
|
218
|
+
# The runnable registry is immune to reporter plugins. Must run after
|
|
219
|
+
# initialize_minitest_state: runnable_methods calls srand(Minitest.seed).
|
|
220
|
+
def minitest_method_count
|
|
221
|
+
::Minitest::Runnable.runnables.sum { |r| r.runnable_methods.size }
|
|
191
222
|
end
|
|
192
223
|
|
|
193
224
|
def dispatch_minitest_suites(reporter, options)
|
data/lib/evilution/version.rb
CHANGED