sbt "project avroIntegration" stryker fails on main since #107 (9fd3e21). Reproduced on a detached origin/main checkout with no feature branch involved, so this is main's state, not a PR artifact.
This undoes the unblocking work that landed today — avro had just been confirmed scoreable (391 killed / 78 survived / 17 NoCoverage in ~126 s) and #114 raises it to 431/38.
Blocker 1 — flow-typed val in totalNominalIndex breaks under mutation
AvroWalk.totalNominalIndex has:
val here = if index != null then index else normalisedNameIndex(record)
The inferred type comes from the != null flow test. When stryker mutates that condition, the inference collapses to JMap[String, Integer] | Null under -Yexplicit-nulls, and the subsequent here.get(...) no longer compiles. stryker4s then reports:
UnableToFixCompilerErrorsException: No mutants were removed in AvroWalk.scala even though there were 1 compile errors
The mutant-removal recovery cannot help: the breakage is in type inference at the mutated site, not in a mutant that can be dropped.
Verified fix (the same pattern PR #109 used for a different stryker/source interaction) — ascribe the type so it does not depend on the flow test:
val here: JMap[String, Integer] = if index != null then index.nn else normalisedNameIndex(record)
This was applied locally, confirmed to clear blocker 1, and then reverted — it is production code and did not belong in the test-only PR that found it.
Blocker 2 — stryker4s rollback invariant on AvroBinaryCursor.scala
With blocker 1 fixed, the run proceeds further and then dies while rolling back 37 compile-error mutants:
org.scalameta.invariants.InvariantFailedException: invariant failed (cases should be non-empty)
Also reproduced on plain main + fix 1. This one is inside stryker4s's rollback path rather than in eo's source, so it likely needs either an exclusion or an upstream report — worth diagnosing before choosing.
Why this matters beyond the score
mutationAll runs avro, so quality.yml on a release tag hits this. More importantly, the nominal field-resolution rung is exactly the code whose doctrine blind spots issue #104 documented — a mis-targeted optic satisfies get-put, put-get, put-put and modify-fusion perfectly, so mutation testing is one of the few instruments that can see a regression there. Losing it silently is worse than losing a number.
Suggested shape
Two commits, or two PRs: the one-line ascription for blocker 1, then a diagnosis of blocker 2 (eo-side exclusion vs. upstream stryker4s issue). Blocker 1 alone restores partial scoring and is low risk.
Found while rebasing #114 onto main.
sbt "project avroIntegration" strykerfails onmainsince #107 (9fd3e21). Reproduced on a detachedorigin/maincheckout with no feature branch involved, so this is main's state, not a PR artifact.This undoes the unblocking work that landed today — avro had just been confirmed scoreable (391 killed / 78 survived / 17 NoCoverage in ~126 s) and #114 raises it to 431/38.
Blocker 1 — flow-typed
valintotalNominalIndexbreaks under mutationAvroWalk.totalNominalIndexhas:The inferred type comes from the
!= nullflow test. When stryker mutates that condition, the inference collapses toJMap[String, Integer] | Nullunder-Yexplicit-nulls, and the subsequenthere.get(...)no longer compiles. stryker4s then reports:The mutant-removal recovery cannot help: the breakage is in type inference at the mutated site, not in a mutant that can be dropped.
Verified fix (the same pattern PR #109 used for a different stryker/source interaction) — ascribe the type so it does not depend on the flow test:
This was applied locally, confirmed to clear blocker 1, and then reverted — it is production code and did not belong in the test-only PR that found it.
Blocker 2 — stryker4s rollback invariant on
AvroBinaryCursor.scalaWith blocker 1 fixed, the run proceeds further and then dies while rolling back 37 compile-error mutants:
Also reproduced on plain
main+ fix 1. This one is inside stryker4s's rollback path rather than in eo's source, so it likely needs either an exclusion or an upstream report — worth diagnosing before choosing.Why this matters beyond the score
mutationAllruns avro, soquality.ymlon a release tag hits this. More importantly, the nominal field-resolution rung is exactly the code whose doctrine blind spots issue #104 documented — a mis-targeted optic satisfies get-put, put-get, put-put and modify-fusion perfectly, so mutation testing is one of the few instruments that can see a regression there. Losing it silently is worse than losing a number.Suggested shape
Two commits, or two PRs: the one-line ascription for blocker 1, then a diagnosis of blocker 2 (eo-side exclusion vs. upstream stryker4s issue). Blocker 1 alone restores partial scoring and is low risk.
Found while rebasing #114 onto main.