Skip to content

avro: stryker fails on main since #107 — flow-typed val in totalNominalIndex, then a rollback invariant in AvroBinaryCursor #115

Description

@kryptt

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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions