Skip to content

ci(mutation): point PIT where survivors are real, and make the lane trustworthy - #111

Merged
astubbs merged 23 commits into
masterfrom
docs/mutation-testing-plan
Aug 4, 2026
Merged

ci(mutation): point PIT where survivors are real, and make the lane trustworthy#111
astubbs merged 23 commits into
masterfrom
docs/mutation-testing-plan

Conversation

@astubbs

@astubbs astubbs commented Aug 3, 2026

Copy link
Copy Markdown
Owner

Description

Started as analysis of whether the PIT lane is pointed anywhere useful. It now acts on that analysis: the plumbing that made the lane unreliable, and the retarget it was all clearing a path for.

What it does not do is claim a result. The retarget is a config change made on the strength of an argument, and no sweep has completed under the new target - so the PR ends with an experiment to run, not a mutation score.

Three things the original draft got wrong turned up while implementing it - two by reading pitest's source instead of its docs, one because the automated reviewer kept insisting. They are corrected in place in the doc rather than quietly patched, because a plan that silently self-corrects teaches nothing.

What changed

A single flaky test no longer switches mutation testing off repo-wide.
PIT needs a green baseline to attribute a kill to a mutant rather than to noise, so any test unstable without mutation aborted the whole run - zero mutants scored anywhere, regardless of which class flaked. It happened twice, both times unrelated (#101, #110), which meant the lane's green-ness had been tracking suite stability rather than mutation coverage.

skipFailingTests makes PIT drop the failing test's coverage instead of aborting. Verified both directions with a deliberate always-failing test (added, then removed):

setting result
false exit 1, 1 tests did not pass without mutation ... requires a green suite, zero mutants
true exit 0, run completes, 18 mutations scored

Two traps worth knowing: it is pom-only (the PitMojo @Parameter declares no property, so -DskipFailingTests is silently ignored), and parseSurefireConfig would let a <testFailureIgnore> override it from a distance. Its cost is silence - pitest logs nothing when it skips a test this way, so the job summary carries that caveat next to the no-coverage count. The flake itself is not hidden: it still reddens the Unit gate, which is where a flake belongs.

One mutation lane, not three. PIT ran three times per PR - twice on highcpu, once on the hosted lane - two of them the same scoped computation. A fourth copy sat in the local lane but was dormant: that workflow's pull_request trigger is commented out while its runner is offline, so it only ran on dispatch. (Being precise rather than rounding up to "four times per PR": a disabled trigger is a real difference, and the copy that isn't running isn't the one costing anything.)

The dormant copy was still worth removing, because it carried a hazard the others don't: it checks out shallow, and a shallow checkout makes the script fall back from scoped to the full sweep - so re-enabling that trigger would have shipped the hazard with it. Now exactly one lane, maven.yml, which checks out with fetch-depth: 0.

Unit + Integration leave the highcpu matrix too, for the same reason rather than a mutation-specific one: measured as not actually faster than the GitHub-hosted gate that already runs them, so they were a second copy of an existing verdict and one more tick to triage per PR. The measured fork tuning (1C, 8 broker-forks, and the -Dsurefire.forkCount vs bare -DforkCount trap) is preserved in comments rather than lost with the entries. highcpu now carries only what needs the cores: Performance and the Chaos Pain Suite.

The full sweep is manual-only. As internal.* it had never once completed (42+ min on CI, 83+ min locally with minions dying on MEMORY_ERROR), so it scored zero mutants while holding a 16-core runner for its whole 60-minute timeout on every push.

It is not left unscheduled because a sweep can never be scheduled - that reasoning was specific to internal.* and does not survive the retarget to offsets.*, where the sweep is plausibly minutes. It is unscheduled because nothing has measured its runtime yet: one dispatch settles it. When it is wired, push: branches: [master] beats a cron, since a mutation score changes only when the code does - a nightly recomputes an identical answer whenever master did not move, and blames a date instead of a merge.

A green tick now says what kind of green it is. The old advice was "read the log, not the tick", which only helps people who already know to be suspicious. Every exit path writes a job summary instead: scored (with the run totals), skipped because nothing changed, or died before scoring - the last naming the failing tests if the green-suite abort is somehow reached. Only the final - Statistics block is reported: PIT also prints a per-class tally in the identical >> Generated N Killed M shape, and pasting those in would show several numbers that all look like the score.

Three corrections to the analysis

mutableCodePaths was unimplementable, not merely unset. §4.5 proposed setting it explicitly. It is not a pitest-maven parameter at all - adding the element fails the build. MojoToReportOptionsConverter hard-codes the mutable path to target/classes, widened only by crossModule. So main-only is structural under Maven, not an unstated default anyone could flip. <crossModule>false</crossModule> is pinned in its place, with the reasoning attached.

§4.2 contradicted this repo's own verified finding - flagged by the automated reviewer on five consecutive passes before it was acted on. The section claimed the basic history file is free in OSS pitest and asked someone to "confirm whether the free tier covers it", while the in-flight ledger already recorded the opposite as a verified PR #69 result. Settled by running it rather than choosing a document to believe:

[ERROR] History has been enabled but no history plugin has been installed/activated.
[ERROR] If you are using https://www.arcmutate.com remember to activate the history plugin

withHistory does not work at all on pitest 1.25.8 - file-based history was dropped in the 1.17.4 → 1.25.8 bump (#73). So there is no free tier to check, and the real work item is obtaining and wiring an arcmutate licence (free for OSS, but needs maintainer signup and a licence file at the repo root - a committed key or CI secret on a public repo), not setting a flag. The ledger note gains the re-verification date so the next reader finds agreement rather than a contradiction to arbitrate.

The meta-lesson is worth more than the fix, and is recorded in the doc: a review finding that keeps being deferred is usually a real one. This one cost a single local run to settle.

§3.4 may already be false. The script warns that pitest ignores excluded.groups. But parseSurefireConfig defaults to true and SurefireConfigConverter.convertGroups reads surefire's <excludedGroups>, which our pom sets. It hinges on whether ${excluded.groups} interpolates in the raw Xpp3Dom. Left unverified and marked as such rather than guessed at - a throwaway @Quarantined unit test settles it, and §4.4 may turn out to be a comment to delete rather than work to do.

Retargeted to offsets.*

The substantive change from the analysis (§4.3), and the reason the rest of it was worth doing.

internal.* is the concurrency core, which makes it close to the worst possible thing to mutate: mutants to locks, loop conditions and timeouts hang by construction rather than dying fast - that is why that sweep never completed - and the covering tests are timing-based, so a survivor is often unfalsifiable: "nothing asserts this" is indistinguishable from "the race didn't happen this run". A finding you cannot act on is not a finding.

The offset encoders/decoders are the opposite on both counts. Deterministic tests, so a survivor is a real gap someone can go and close; and the highest stakes in the codebase, since a silent bug there means lost or duplicated records.

Applies in both places. It is the sweep default (script and workflow input), and the per-PR lane now intersects its changed-class list with the same decidable set (PIT_DECIDABLE_PACKAGES, default offsets.), naming in the log and summary any changed class it declined to mutate.

The lane needed it as much as the sweep - a first cut of this change retargeted only the sweep, which is the path that runs least often, leaving the recurring case exactly as bad as before. The job timeout is no defence either: it converts "slow" into "cancelled with nothing scored", which is the same zero signal the sweep produced for months.

Measured before choosing the default (12 cores). One changed internal class (BrokerPollSystem): 271s coverage pass, then mutation analysis of that single class had still not reached the statistics stage four minutes later, when it was killed. One changed offsets class: 430s end to end, 18 mutants scored. The hosted lane has two cores, not twelve.

Starting narrow on purpose - offsets. alone. state. is the obvious next candidate but is bookkeeping around the same concurrency, so it earns inclusion by measurement.

The survivor list, because a score is not a finding

Killed 9 (50%) cannot be acted on - it does not say which half. Every run now ends with the mutants that lived:

SURVIVED     OffsetSimpleSerialisation.java:38  removed call to ObjectOutputStream::writeObject
NO_COVERAGE  OffsetSimpleSerialisation.java:55  removed call to SnappyOutputStream::write
NO_COVERAGE  OffsetSimpleSerialisation.java:119 negated conditional

Each line is a behaviour nothing asserts - a work item. (That real example is worth reading: 8 of 9 are NO_COVERAGE, so the snappy, base64 and Java-serialisation paths have no test touching them at all. The percentage alone would never have surfaced that.)

Parsed from mutations.xml with sed - pitest writes one element per line, so an XML parser would be a dependency for no gain. Mutants that could not be evaluated (MEMORY_ERROR, RUN_ERROR, NON_VIABLE) are counted separately rather than listed as test gaps, since they are infrastructure failures - listing them under "a behaviour nothing asserts" would be the lane misreporting itself, which is the defect this whole PR is about.

target-tests is deliberately not narrowed to match, though the two pair naturally. It is the one lever on the 332s instrumented coverage pass, but as a default it trades accuracy for speed: a mutant killed only by a test outside offsets.* would be reported as no-coverage rather than killed, manufacturing survivors that aren't real. Left as a deliberate purchase (-f target-tests=...) rather than an inherited one.

Still outstanding: the measurement

This is a config change made on the strength of an argument, not a result. Nothing has completed under the new target either - offsets.* is not obviously cheap, with RunLengthEncoderTest alone at ~140s re-run per mutant. So:

gh workflow run mutation-full-sweep                  # against master
gh workflow run mutation-full-sweep --ref <branch>   # against a branch

Only after this merges. workflow_dispatch requires the workflow file to be on the default branch before it can be dispatched at all - even when dispatching a different ref - so this PR cannot exercise the workflow it introduces (could not find any workflows named mutation-full-sweep). Worth knowing generally: any new dispatch-only workflow is unrunnable until it lands on master.

If it completes, a schedule: trigger and a history file both become real options and there is finally a mutation score worth quoting. If it doesn't, that is itself the answer on whether mutation testing can work on this codebase. The plan doc and docs/inflight/ci-mutation-testing.md both say not to quote a score for this project until one has.

Also in here: a stale comment that taught the wrong thing

Not planned, but the same defect class the rest of this PR is about - CI that misreports itself.

Asked whether the quarantine lane re-checks after a push, I found it does (on: pull_request, verified against eight runs on this branch, one per pushed commit). But the comment sitting directly above that trigger still described a superseded design: "Runs NIGHTLY against master (running per-PR added ~10min of runner noise...)". It reads as authoritative because of where it sits, and it had convinced a reader that a re-push would not re-assess.

The same claim had spread to bin/check-quarantine-registry.sh, bin/check-quarantine-owners.sh, and - most instructively - to a test named perPrWorkflowRunsTheAuditAndTheNightlyWorkflowRunsTheLane. Its assertions were correct, and its sibling laneWorkflowDeclaresItsTriggers pins pull_request: explicitly. So the executable half of that contract had kept up while every human-readable half of it had not: a test can encode the right behaviour and still teach the wrong one, because people read the name. Renamed; no coverage change, all 11 tests in the class pass.

While there, recorded the corollary that matters for reading the checks list: a green tick on that lane does not mean the quarantined tests passed - step-level continue-on-error puts the verdict in the step summary and sticky comment. Exactly the same trap as the mutation lane.

Files

  • pom.xml - skipFailingTests, crossModule=false, both with their reasoning
  • bin/ci-mutation-test.sh - job summary on every exit path, PIT_TARGET_CLASSES/PIT_TARGET_TESTS
  • .github/workflows/mutation-full-sweep.yml - new, workflow_dispatch only
  • .github/workflows/pr-highcpu-fast-feedback.yml, pr-local-fast-feedback.yml - lane collapse
  • docs/plans/2026-08-03-002-mutation-testing-plan.md - the analysis, corrected in place
  • docs/inflight/ci-mutation-testing.md (new one-file-per-item ledger, per docs: audit the in-flight ledger against reality, then split it so PRs stop colliding #112) and docs/inflight/ci-disabled-jobs-and-runner-load.md, whose "six suites including mutation sweeps" description this PR made false
  • docs/SELF_HOSTED_RUNNER.md
  • .github/workflows/quarantine-lane.yml, bin/check-quarantine-*.sh, QuarantinedAnnotationContractTest - the stale-comment purge above

Testing

Local PIT runs against offsets.* exercised all three summary paths (scored / skipped / died, both branches of died) and the skipFailingTests behaviour in both directions. One bug found in my own work and fixed: a no-match grep on the failure path would have aborted the script under set -euo pipefail, losing the summary and replacing PIT's exit status with grep's.

-DwithHistory=true was run against the current build to settle the §4.2 contradiction (it errors; see above).

Full suite not run - no main code changed; the pom edit touches only the pitest plugin.

Checklist

  • Tests added/updated - N/A for coverage: no main code changed. One test was renamed (QuarantinedAnnotationContractTest) because its name asserted a superseded design; its assertions are unchanged and all 11 pass. The CI behaviour claims are verified by the runs described above.
  • Docs updated - plan doc, two in-flight notes, SELF_HOSTED_RUNNER. No CHANGELOG.adoc entry: docs(changelog): compact it for readers, and generate future releases from the commit log #113 abolished per-PR entries, and release notes are now generated from the commit log.
  • Title & body reflect the final content of this PR
  • Self-hosted runner / security implications considered - the new workflow is workflow_dispatch only, so only someone with write access can start it and a fork PR can never reach the self-hosted runner through it. Net reduction in self-hosted exposure: four per-PR self-hosted jobs removed (Unit, Integration, and both Mutation entries), plus a dormant fifth in the local lane.

Note: the branch is still named docs/mutation-testing-plan, which no longer describes it. Renaming a branch with an open PR auto-closes the PR, so it stays.

🤖 Generated with Claude Code

astubbs and others added 3 commits August 3, 2026 20:11
…the fix

PR #110 restores the PIT lane by fixing the flake that was aborting it. Whether
the lane is pointed anywhere useful is a separate question, and this records the
answer rather than losing it.

The short version: the full internal.* sweep has never completed, so it scores
zero mutants while costing highcpu runner time on every PR - and internal.* is
close to the worst possible target, because mutants to locks and loop conditions
in the concurrency core hang by construction rather than dying fast, and the
timing-based covering tests make a survivor unfalsifiable.

Two traps written down explicitly because both are counter-intuitive:

- Lowering timeoutConstant is NOT a safe speed-up. PIT counts TIMED_OUT as
  KILLED, so a shorter timeout reclassifies slow survivors as kills and inflates
  the score.
- Mutating test code would be actively harmful, not merely wasteful. A mutated
  assertion fails its own test, so the mutant is recorded KILLED; the score
  climbs toward 100% while carrying no information about main code. Our
  targetClasses glob does match test classes by name - tests share the
  production package - and only pitest's mutableCodePaths default keeps them
  out. That is protection by unstated default, not by intent.

Proposals are listed in payoff order and deliberately NOT scheduled: nightly
full sweep, withHistory incremental analysis (verify free-vs-arcmutate first),
retarget to offsets.* where a bug means lost records and mutants are decidable,
explicit excludedGroups, explicit mutableCodePaths. Per-PR scoping to changed
classes stays - that instinct was right.

Docs only. No behaviour change, no workflow change.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QqHpNSXC39ANv9kG1ZvUzn
… that never completes

Corrects the payoff ordering in the entry added a moment ago. I had ranked
incremental analysis second, as though cached results were being left on the
table. They were not: no run has ever completed, so there was never anything to
cache, and a run that dies in the coverage stage writes no useful history.

It is an optimisation for 'completes, but slowly and repeatedly'. We are at
'does not complete', so retargeting to a finishable, decidable scope is the
enabler and now leads the list.

Second reason it would disappoint even after that: for scoped runs the dominant
cost is the 332s instrumented full-suite coverage pass, paid regardless of how
few classes are mutated. Caching mutant verdicts does not touch it - the lever
there is narrowing what must run for coverage at all.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QqHpNSXC39ANv9kG1ZvUzn
The section is headed 'in payoff order' but 4.2 was demoted to last in the
previous commit without renumbering. Renumbering would break the cross-reference
from 3.3, so say it plainly instead.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QqHpNSXC39ANv9kG1ZvUzn
@github-actions

github-actions Bot commented Aug 3, 2026

Copy link
Copy Markdown

Dependency Review

The following issues were found:
  • ✅ 0 vulnerable package(s)
  • ✅ 0 package(s) with incompatible licenses
  • ✅ 0 package(s) with invalid SPDX license definitions
  • ⚠️ 3 package(s) with unknown licenses.
See the Details below.

License Issues

.github/workflows/mutation-full-sweep.yml

PackageVersionLicenseIssue Type
actions/checkout6.*.*NullUnknown License
actions/setup-java5.*.*NullUnknown License
actions/upload-artifact7.*.*NullUnknown License
Excluded from license check: pkg:githubactions/actions/github-script

OpenSSF Scorecard

PackageVersionScoreDetails
actions/actions/checkout 6.*.* 🟢 6.9
Details
CheckScoreReason
Binary-Artifacts🟢 10no binaries found in the repo
Code-Review🟢 10all changesets reviewed
Maintained🟢 1024 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Token-Permissions⚠️ 0detected GitHub workflow tokens with excessive permissions
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Fuzzing⚠️ 0project is not fuzzed
Packaging⚠️ -1packaging workflow not detected
License🟢 10license file detected
Pinned-Dependencies🟢 3dependency not pinned by hash detected -- score normalized to 3
Signed-Releases⚠️ -1no releases found
Security-Policy🟢 9security policy file detected
SAST🟢 10SAST tool is run on all commits
Branch-Protection🟢 5branch protection is not maximal on development and all release branches
actions/actions/setup-java 5.*.* 🟢 5.1
Details
CheckScoreReason
Code-Review⚠️ 0Found 1/19 approved changesets -- score normalized to 0
Maintained🟢 1030 commit(s) and 2 issue activity found in the last 90 days -- score normalized to 10
Binary-Artifacts🟢 10no binaries found in the repo
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Packaging⚠️ -1packaging workflow not detected
Token-Permissions⚠️ 0detected GitHub workflow tokens with excessive permissions
Pinned-Dependencies⚠️ 0dependency not pinned by hash detected -- score normalized to 0
License🟢 10license file detected
Fuzzing⚠️ 0project is not fuzzed
Signed-Releases⚠️ -1no releases found
Security-Policy🟢 9security policy file detected
Branch-Protection⚠️ 0branch protection not enabled on development/release branches
SAST🟢 10SAST tool is run on all commits
actions/actions/upload-artifact 7.*.* 🟢 5.2
Details
CheckScoreReason
Maintained⚠️ 00 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0
Binary-Artifacts🟢 10no binaries found in the repo
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Packaging⚠️ -1packaging workflow not detected
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Code-Review🟢 10all changesets reviewed
Token-Permissions⚠️ 0detected GitHub workflow tokens with excessive permissions
Pinned-Dependencies⚠️ 1dependency not pinned by hash detected -- score normalized to 1
Fuzzing⚠️ 0project is not fuzzed
License🟢 10license file detected
Signed-Releases⚠️ -1no releases found
Security-Policy🟢 9security policy file detected
SAST🟢 10SAST tool is run on all commits
Branch-Protection⚠️ 0branch protection not enabled on development/release branches

Scanned Files

  • .github/workflows/mutation-full-sweep.yml

@github-actions

github-actions Bot commented Aug 3, 2026

Copy link
Copy Markdown

✅ Duplicate Code Report

Two engines run in parallel for cross-validation. Each has its own thresholds tuned to its baseline - the real safety net is the per-engine "max increase vs base" check.

✅ PMD CPD

PR Base Change
Clones 29 29 ➖ 0
Duplicated lines 874 874 ➖ 0
Duplication 2.58% 2.58% ➖ 0
Rule Limit Status
Max duplication 5% ✅ Pass (2.58%)
Max increase vs base +0.1% ✅ Pass (+0.00%)

No new clones introduced by this PR.

✅ jscpd (language-agnostic)

PR Base Change
Clones 77 77 ➖ 0
Duplicated lines 1111 1111 ➖ 0
Duplication 3.31% 3.31% ➖ 0
Rule Limit Status
Max duplication 5% ✅ Pass (3.31%)
Max increase vs base +0.1% ✅ Pass (+0.00%)

No new clones introduced by this PR.

Powered by astubbs/duplicate-code-cross-check

@github-actions

github-actions Bot commented Aug 3, 2026

Copy link
Copy Markdown

📌 Duplicate code detection tool report

The tool analyzed your source code and found the following degree of similarity between the files:

✅ No new or increased file similarities introduced by this PR.

Full similarity report
parallel-consumer-core/src/main/java/io/confluent/csid/utils/Java8StreamUtils.java

📄 parallel-consumer-core/src/main/java/io/confluent/csid/utils/Java8StreamUtils.java

File Similarity (%)
parallel-consumer-core/src/main/java/io/confluent/csid/utils/JavaUtils.java 35.32
parallel-consumer-core/src/test/java/io/confluent/csid/utils/CollectionUtils.java 33.26
parallel-consumer-core/src/main/java/io/confluent/csid/utils/JavaUtils.java

📄 parallel-consumer-core/src/main/java/io/confluent/csid/utils/JavaUtils.java

File Similarity (%)
parallel-consumer-core/src/test/java/io/confluent/csid/utils/CollectionUtils.java 39.5
parallel-consumer-core/src/main/java/io/confluent/csid/utils/Java8StreamUtils.java 35.32
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/ExceptionInUserFunctionException.java

📄 parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/ExceptionInUserFunctionException.java

File Similarity (%)
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/ParallelConsumerException.java 54.36 ⚠️
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/internal/InternalException.java 40.38
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/EncodingNotSupportedException.java 37.0
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/PCRetriableException.java 36.97
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/RunLengthV1EncodingNotSupported.java 35.39
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/RunLengthV2EncodingNotSupported.java 35.39
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/BitSetEncodingNotSupportedException.java 35.28
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/OffsetDecodingError.java 34.15
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/NoEncodingPossibleException.java 30.07
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/JStreamParallelEoSStreamProcessor.java

📄 parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/JStreamParallelEoSStreamProcessor.java

File Similarity (%)
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/JStreamParallelStreamProcessor.java 60.96 ⚠️
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/ParallelEoSStreamProcessor.java 54.74 ⚠️
parallel-consumer-vertx/src/main/java/io/confluent/parallelconsumer/vertx/JStreamVertxParallelEoSStreamProcessor.java 40.4
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/ParallelStreamProcessor.java 37.01
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/PollContextInternal.java 32.68
parallel-consumer-vertx/src/main/java/io/confluent/parallelconsumer/vertx/JStreamVertxParallelStreamProcessor.java 31.47
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/JStreamParallelStreamProcessor.java

📄 parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/JStreamParallelStreamProcessor.java

File Similarity (%)
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/JStreamParallelEoSStreamProcessor.java 60.96 ⚠️
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/ParallelEoSStreamProcessor.java 50.65 ⚠️
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/ParallelStreamProcessor.java 36.76
parallel-consumer-vertx/src/main/java/io/confluent/parallelconsumer/vertx/JStreamVertxParallelEoSStreamProcessor.java 32.44
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/PollContextInternal.java 31.63
parallel-consumer-vertx/src/main/java/io/confluent/parallelconsumer/vertx/JStreamVertxParallelStreamProcessor.java 30.22
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/PCRetriableException.java

📄 parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/PCRetriableException.java

File Similarity (%)
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/ExceptionInUserFunctionException.java 36.97
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/internal/InternalException.java 33.11
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/ParallelConsumerException.java

📄 parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/ParallelConsumerException.java

File Similarity (%)
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/ExceptionInUserFunctionException.java 54.36 ⚠️
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/internal/InternalException.java 53.28 ⚠️
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/EncodingNotSupportedException.java 44.98
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/BitSetEncodingNotSupportedException.java 35.05
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/OffsetDecodingError.java 33.75
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/RunLengthV1EncodingNotSupported.java 31.14
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/RunLengthV2EncodingNotSupported.java 31.14
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/internal/InternalRuntimeException.java 30.74
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/NoEncodingPossibleException.java 30.15
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/ParallelConsumerOptions.java

📄 parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/ParallelConsumerOptions.java

File Similarity (%)
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/internal/ProducerManager.java 32.32
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/state/PartitionState.java 30.0
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/ParallelEoSStreamProcessor.java

📄 parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/ParallelEoSStreamProcessor.java

File Similarity (%)
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/JStreamParallelEoSStreamProcessor.java 54.74 ⚠️
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/JStreamParallelStreamProcessor.java 50.65 ⚠️
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/ParallelStreamProcessor.java 45.53
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/PollContextInternal.java 33.92
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/internal/AbstractParallelEoSStreamProcessor.java 33.05
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/internal/TestParallelEoSStreamProcessor.java 31.14
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/ParallelStreamProcessor.java

📄 parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/ParallelStreamProcessor.java

File Similarity (%)
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/ParallelEoSStreamProcessor.java 45.53
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/JStreamParallelEoSStreamProcessor.java 37.01
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/JStreamParallelStreamProcessor.java 36.76
parallel-consumer-vertx/src/main/java/io/confluent/parallelconsumer/vertx/JStreamVertxParallelStreamProcessor.java 32.6
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/PollContext.java

📄 parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/PollContext.java

File Similarity (%)
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/RecordContextInternal.java 35.38
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/PollContextInternal.java 32.36
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/PollContextInternal.java

📄 parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/PollContextInternal.java

File Similarity (%)
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/ParallelEoSStreamProcessor.java 33.92
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/RecordContextInternal.java 33.09
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/JStreamParallelEoSStreamProcessor.java 32.68
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/PollContext.java 32.36
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/JStreamParallelStreamProcessor.java 31.63
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/RecordContextInternal.java

📄 parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/RecordContextInternal.java

File Similarity (%)
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/PollContext.java 35.38
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/PollContextInternal.java 33.09
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/internal/AbstractParallelEoSStreamProcessor.java

📄 parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/internal/AbstractParallelEoSStreamProcessor.java

File Similarity (%)
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/internal/BrokerPollSystem.java 33.48
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/ParallelEoSStreamProcessor.java 33.05
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/internal/BrokerPollSystem.java

📄 parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/internal/BrokerPollSystem.java

File Similarity (%)
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/internal/AbstractParallelEoSStreamProcessor.java 33.48
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/internal/ExternalEngine.java

📄 parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/internal/ExternalEngine.java

File Similarity (%)
parallel-consumer-vertx/src/main/java/io/confluent/parallelconsumer/vertx/VertxParallelEoSStreamProcessor.java 39.59
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/internal/InternalException.java

📄 parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/internal/InternalException.java

File Similarity (%)
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/EncodingNotSupportedException.java 60.58 ⚠️
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/ParallelConsumerException.java 53.28 ⚠️
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/OffsetDecodingError.java 51.0 ⚠️
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/NoEncodingPossibleException.java 48.89
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/ExceptionInUserFunctionException.java 40.38
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/internal/InternalRuntimeException.java 39.43
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/BitSetEncodingNotSupportedException.java 37.28
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/RunLengthV1EncodingNotSupported.java 34.02
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/RunLengthV2EncodingNotSupported.java 34.02
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/PCRetriableException.java 33.11
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/internal/InternalRuntimeException.java

📄 parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/internal/InternalRuntimeException.java

File Similarity (%)
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/internal/InternalException.java 39.43
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/EncodingNotSupportedException.java 31.39
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/ParallelConsumerException.java 30.74
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/internal/PCModule.java

📄 parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/internal/PCModule.java

File Similarity (%)
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/internal/PCModuleTestEnv.java 32.97
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/internal/ProducerManager.java

📄 parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/internal/ProducerManager.java

File Similarity (%)
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/ParallelConsumerOptions.java 32.32
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/internal/ProducerManagerTest.java 30.64
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/BitSetEncodingNotSupportedException.java

📄 parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/BitSetEncodingNotSupportedException.java

File Similarity (%)
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/EncodingNotSupportedException.java 51.75 ⚠️
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/RunLengthV1EncodingNotSupported.java 37.68
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/RunLengthV2EncodingNotSupported.java 37.68
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/internal/InternalException.java 37.28
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/ExceptionInUserFunctionException.java 35.28
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/ParallelConsumerException.java 35.05
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/OffsetDecodingError.java 32.92
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/EncodingNotSupportedException.java

📄 parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/EncodingNotSupportedException.java

File Similarity (%)
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/internal/InternalException.java 60.58 ⚠️
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/BitSetEncodingNotSupportedException.java 51.75 ⚠️
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/OffsetDecodingError.java 48.47
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/RunLengthV1EncodingNotSupported.java 47.37
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/RunLengthV2EncodingNotSupported.java 47.37
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/NoEncodingPossibleException.java 46.84
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/ParallelConsumerException.java 44.98
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/ExceptionInUserFunctionException.java 37.0
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/internal/InternalRuntimeException.java 31.39
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/NoEncodingPossibleException.java

📄 parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/NoEncodingPossibleException.java

File Similarity (%)
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/internal/InternalException.java 48.89
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/EncodingNotSupportedException.java 46.84
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/OffsetDecodingError.java 45.47
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/RunLengthV1EncodingNotSupported.java 38.39
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/RunLengthV2EncodingNotSupported.java 38.39
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/ParallelConsumerException.java 30.15
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/ExceptionInUserFunctionException.java 30.07
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/OffsetDecodingError.java

📄 parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/OffsetDecodingError.java

File Similarity (%)
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/internal/InternalException.java 51.0 ⚠️
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/EncodingNotSupportedException.java 48.47
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/NoEncodingPossibleException.java 45.47
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/ExceptionInUserFunctionException.java 34.15
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/ParallelConsumerException.java 33.75
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/BitSetEncodingNotSupportedException.java 32.92
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/RunLengthV1EncodingNotSupported.java 31.8
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/RunLengthV2EncodingNotSupported.java 31.8
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/RunLengthV1EncodingNotSupported.java

📄 parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/RunLengthV1EncodingNotSupported.java

File Similarity (%)
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/RunLengthV2EncodingNotSupported.java 63.65 ⚠️
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/EncodingNotSupportedException.java 47.37
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/NoEncodingPossibleException.java 38.39
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/BitSetEncodingNotSupportedException.java 37.68
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/ExceptionInUserFunctionException.java 35.39
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/internal/InternalException.java 34.02
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/OffsetDecodingError.java 31.8
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/ParallelConsumerException.java 31.14
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/RunLengthV2EncodingNotSupported.java

📄 parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/RunLengthV2EncodingNotSupported.java

File Similarity (%)
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/RunLengthV1EncodingNotSupported.java 63.65 ⚠️
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/EncodingNotSupportedException.java 47.37
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/NoEncodingPossibleException.java 38.39
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/BitSetEncodingNotSupportedException.java 37.68
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/ExceptionInUserFunctionException.java 35.39
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/internal/InternalException.java 34.02
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/OffsetDecodingError.java 31.8
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/ParallelConsumerException.java 31.14
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/state/PartitionState.java

📄 parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/state/PartitionState.java

File Similarity (%)
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/state/PartitionStateManager.java 30.45
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/ParallelConsumerOptions.java 30.0
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/state/PartitionStateManager.java

📄 parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/state/PartitionStateManager.java

File Similarity (%)
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/state/WorkManager.java 39.62
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/state/PartitionState.java 30.45
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/state/ProcessingShard.java

📄 parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/state/ProcessingShard.java

File Similarity (%)
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/state/ShardManager.java 36.71
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/state/ShardManager.java

📄 parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/state/ShardManager.java

File Similarity (%)
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/state/ProcessingShard.java 36.71
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/state/WorkManager.java

📄 parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/state/WorkManager.java

File Similarity (%)
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/state/PartitionStateManager.java 39.62
parallel-consumer-core/src/test-integration/java/io/confluent/parallelconsumer/integrationTests/AmbientProbeExtension.java

📄 parallel-consumer-core/src/test-integration/java/io/confluent/parallelconsumer/integrationTests/AmbientProbeExtension.java

File Similarity (%)
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/AmbientProbeExtensionTest.java 30.14
parallel-consumer-core/src/test-integration/java/io/confluent/parallelconsumer/integrationTests/DrainingMemberRebalanceIT.java

📄 parallel-consumer-core/src/test-integration/java/io/confluent/parallelconsumer/integrationTests/DrainingMemberRebalanceIT.java

File Similarity (%)
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/internal/BrokerPollSystemDrainTest.java 31.54
parallel-consumer-core/src/test-integration/java/io/confluent/parallelconsumer/integrationTests/KafkaSanityTests.java

📄 parallel-consumer-core/src/test-integration/java/io/confluent/parallelconsumer/integrationTests/KafkaSanityTests.java

File Similarity (%)
parallel-consumer-core/src/test/java/io/confluent/csid/utils/LoopingResumingIteratorTest.java 34.02
parallel-consumer-core/src/test-integration/java/io/confluent/parallelconsumer/integrationTests/MultiInstanceHighVolumeTest.java

📄 parallel-consumer-core/src/test-integration/java/io/confluent/parallelconsumer/integrationTests/MultiInstanceHighVolumeTest.java

File Similarity (%)
parallel-consumer-core/src/test-integration/java/io/confluent/parallelconsumer/integrationTests/VeryLargeMessageVolumeTest.java 55.42 ⚠️
parallel-consumer-core/src/test-integration/java/io/confluent/parallelconsumer/integrationTests/TransactionAndCommitModeTest.java 46.93
parallel-consumer-core/src/test-integration/java/io/confluent/parallelconsumer/integrationTests/MultiInstanceRebalanceTest.java 38.68
parallel-consumer-core/src/test-integration/java/io/confluent/parallelconsumer/integrationTests/MultiInstanceRebalanceTest.java

📄 parallel-consumer-core/src/test-integration/java/io/confluent/parallelconsumer/integrationTests/MultiInstanceRebalanceTest.java

File Similarity (%)
parallel-consumer-core/src/test-integration/java/io/confluent/parallelconsumer/integrationTests/VeryLargeMessageVolumeTest.java 44.13
parallel-consumer-core/src/test-integration/java/io/confluent/parallelconsumer/integrationTests/TransactionAndCommitModeTest.java 41.11
parallel-consumer-core/src/test-integration/java/io/confluent/parallelconsumer/integrationTests/MultiInstanceHighVolumeTest.java 38.68
parallel-consumer-core/src/test-integration/java/io/confluent/parallelconsumer/integrationTests/RebalanceEoSDeadlockTest.java

📄 parallel-consumer-core/src/test-integration/java/io/confluent/parallelconsumer/integrationTests/RebalanceEoSDeadlockTest.java

File Similarity (%)
parallel-consumer-core/src/test-integration/java/io/confluent/parallelconsumer/integrationTests/RebalanceTest.java 36.56
parallel-consumer-core/src/test-integration/java/io/confluent/parallelconsumer/integrationTests/RebalanceTest.java

📄 parallel-consumer-core/src/test-integration/java/io/confluent/parallelconsumer/integrationTests/RebalanceTest.java

File Similarity (%)
parallel-consumer-core/src/test-integration/java/io/confluent/parallelconsumer/integrationTests/RebalanceEoSDeadlockTest.java 36.56
parallel-consumer-core/src/test-integration/java/io/confluent/parallelconsumer/integrationTests/TransactionAndCommitModeTest.java

📄 parallel-consumer-core/src/test-integration/java/io/confluent/parallelconsumer/integrationTests/TransactionAndCommitModeTest.java

File Similarity (%)
parallel-consumer-core/src/test-integration/java/io/confluent/parallelconsumer/integrationTests/VeryLargeMessageVolumeTest.java 60.72 ⚠️
parallel-consumer-core/src/test-integration/java/io/confluent/parallelconsumer/integrationTests/MultiInstanceHighVolumeTest.java 46.93
parallel-consumer-core/src/test-integration/java/io/confluent/parallelconsumer/integrationTests/MultiInstanceRebalanceTest.java 41.11
parallel-consumer-vertx/src/test-integration/java/io/confluent/parallelconsumer/vertx/integrationTests/VertxConcurrencyIT.java 30.02
parallel-consumer-core/src/test-integration/java/io/confluent/parallelconsumer/integrationTests/VeryLargeMessageVolumeTest.java

📄 parallel-consumer-core/src/test-integration/java/io/confluent/parallelconsumer/integrationTests/VeryLargeMessageVolumeTest.java

File Similarity (%)
parallel-consumer-core/src/test-integration/java/io/confluent/parallelconsumer/integrationTests/TransactionAndCommitModeTest.java 60.72 ⚠️
parallel-consumer-core/src/test-integration/java/io/confluent/parallelconsumer/integrationTests/MultiInstanceHighVolumeTest.java 55.42 ⚠️
parallel-consumer-core/src/test-integration/java/io/confluent/parallelconsumer/integrationTests/MultiInstanceRebalanceTest.java 44.13
parallel-consumer-vertx/src/test-integration/java/io/confluent/parallelconsumer/vertx/integrationTests/VertxConcurrencyIT.java 39.24
parallel-consumer-core/src/test-integration/java/io/confluent/parallelconsumer/integrationTests/chaostests/AbstractRevokeUnderWorkScenario.java

📄 parallel-consumer-core/src/test-integration/java/io/confluent/parallelconsumer/integrationTests/chaostests/AbstractRevokeUnderWorkScenario.java

File Similarity (%)
parallel-consumer-core/src/test-integration/java/io/confluent/parallelconsumer/integrationTests/chaostests/ChaosChurnStormIT.java 48.87
parallel-consumer-core/src/test-integration/java/io/confluent/parallelconsumer/integrationTests/chaostests/ChaosRevokeUnderWorkIT.java 35.69
parallel-consumer-core/src/test-integration/java/io/confluent/parallelconsumer/integrationTests/chaostests/ChaosChurnStormIT.java

📄 parallel-consumer-core/src/test-integration/java/io/confluent/parallelconsumer/integrationTests/chaostests/ChaosChurnStormIT.java

File Similarity (%)
parallel-consumer-core/src/test-integration/java/io/confluent/parallelconsumer/integrationTests/chaostests/AbstractRevokeUnderWorkScenario.java 48.87
parallel-consumer-core/src/test-integration/java/io/confluent/parallelconsumer/integrationTests/chaostests/ChaosScenarioBase.java 38.27
parallel-consumer-core/src/test-integration/java/io/confluent/parallelconsumer/integrationTests/chaostests/ChaosRevokeUnderWorkIT.java 30.35
parallel-consumer-core/src/test-integration/java/io/confluent/parallelconsumer/integrationTests/chaostests/ChaosRevokeUnderWorkCooperativeIT.java

📄 parallel-consumer-core/src/test-integration/java/io/confluent/parallelconsumer/integrationTests/chaostests/ChaosRevokeUnderWorkCooperativeIT.java

File Similarity (%)
parallel-consumer-core/src/test-integration/java/io/confluent/parallelconsumer/integrationTests/chaostests/ChaosRevokeUnderWorkIT.java 49.38
parallel-consumer-core/src/test-integration/java/io/confluent/parallelconsumer/integrationTests/chaostests/ChaosRevokeUnderWorkIT.java

📄 parallel-consumer-core/src/test-integration/java/io/confluent/parallelconsumer/integrationTests/chaostests/ChaosRevokeUnderWorkIT.java

File Similarity (%)
parallel-consumer-core/src/test-integration/java/io/confluent/parallelconsumer/integrationTests/chaostests/ChaosRevokeUnderWorkCooperativeIT.java 49.38
parallel-consumer-core/src/test-integration/java/io/confluent/parallelconsumer/integrationTests/chaostests/AbstractRevokeUnderWorkScenario.java 35.69
parallel-consumer-core/src/test-integration/java/io/confluent/parallelconsumer/integrationTests/chaostests/ChaosChurnStormIT.java 30.35
parallel-consumer-core/src/test-integration/java/io/confluent/parallelconsumer/integrationTests/chaostests/ChaosScenarioBase.java

📄 parallel-consumer-core/src/test-integration/java/io/confluent/parallelconsumer/integrationTests/chaostests/ChaosScenarioBase.java

File Similarity (%)
parallel-consumer-core/src/test-integration/java/io/confluent/parallelconsumer/integrationTests/chaostests/ChaosChurnStormIT.java 38.27
parallel-consumer-core/src/test/java/io/confluent/csid/utils/CollectionUtils.java

📄 parallel-consumer-core/src/test/java/io/confluent/csid/utils/CollectionUtils.java

File Similarity (%)
parallel-consumer-core/src/main/java/io/confluent/csid/utils/JavaUtils.java 39.5
parallel-consumer-core/src/main/java/io/confluent/csid/utils/Java8StreamUtils.java 33.26
parallel-consumer-core/src/test/java/io/confluent/csid/utils/LoopingResumingIteratorTest.java

📄 parallel-consumer-core/src/test/java/io/confluent/csid/utils/LoopingResumingIteratorTest.java

File Similarity (%)
parallel-consumer-core/src/test-integration/java/io/confluent/parallelconsumer/integrationTests/KafkaSanityTests.java 34.02
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/AbstractParallelEoSStreamProcessorTestBase.java

📄 parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/AbstractParallelEoSStreamProcessorTestBase.java

File Similarity (%)
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/ParallelEoSStreamProcessorTest.java 30.01
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/AmbientProbeExtensionTest.java

📄 parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/AmbientProbeExtensionTest.java

File Similarity (%)
parallel-consumer-core/src/test-integration/java/io/confluent/parallelconsumer/integrationTests/AmbientProbeExtension.java 30.14
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/BatchTestBase.java

📄 parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/BatchTestBase.java

File Similarity (%)
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/CoreBatchTest.java 30.61
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/CheckQuarantineOwnersScriptTest.java

📄 parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/CheckQuarantineOwnersScriptTest.java

File Similarity (%)
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/QuarantineLaneReportScriptTest.java 45.22
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/QuarantineRegistryScriptTest.java 43.72
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/CommitRejectionTestBase.java

📄 parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/CommitRejectionTestBase.java

File Similarity (%)
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/MockConsumerTest.java 32.44
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/MockConsumerCommitTimeoutTest.java 32.42
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/CoreBatchTest.java

📄 parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/CoreBatchTest.java

File Similarity (%)
parallel-consumer-reactor/src/test/java/io/confluent/parallelconsumer/reactor/ReactorBatchTest.java 52.04 ⚠️
parallel-consumer-mutiny/src/test/java/io/confluent/parallelconsumer/mutiny/MutinyBatchTest.java 50.73 ⚠️
parallel-consumer-vertx/src/test/java/io/confluent/parallelconsumer/vertx/VertxBatchTest.java 44.86
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/BatchTestBase.java 30.61
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/MockConsumerCommitTimeoutTest.java

📄 parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/MockConsumerCommitTimeoutTest.java

File Similarity (%)
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/MockConsumerEarlyCloseTest.java 70.36 ⚠️
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/MockConsumerTest.java 56.9 ⚠️
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/MockConsumerSaslAuthenticationTest.java 49.45
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/CommitRejectionTestBase.java 32.42
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/MockConsumerEarlyCloseTest.java

📄 parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/MockConsumerEarlyCloseTest.java

File Similarity (%)
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/MockConsumerCommitTimeoutTest.java 70.36 ⚠️
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/MockConsumerTest.java 55.42 ⚠️
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/MockConsumerSaslAuthenticationTest.java 52.82 ⚠️
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/MockConsumerSaslAuthenticationTest.java

📄 parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/MockConsumerSaslAuthenticationTest.java

File Similarity (%)
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/MockConsumerEarlyCloseTest.java 52.82 ⚠️
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/MockConsumerCommitTimeoutTest.java 49.45
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/MockConsumerTest.java 46.82
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/MockConsumerTest.java

📄 parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/MockConsumerTest.java

File Similarity (%)
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/MockConsumerCommitTimeoutTest.java 56.9 ⚠️
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/MockConsumerEarlyCloseTest.java 55.42 ⚠️
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/MockConsumerSaslAuthenticationTest.java 46.82
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/CommitRejectionTestBase.java 32.44
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/ParallelEoSSStreamProcessorRebalancedTest.java

📄 parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/ParallelEoSSStreamProcessorRebalancedTest.java

File Similarity (%)
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/ParallelEoSStreamProcessorTest.java 34.69
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/ParallelEoSStreamProcessorTest.java

📄 parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/ParallelEoSStreamProcessorTest.java

File Similarity (%)
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/ParallelEoSSStreamProcessorRebalancedTest.java 34.69
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/AbstractParallelEoSStreamProcessorTestBase.java 30.01
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/QuarantineLaneReportScriptTest.java

📄 parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/QuarantineLaneReportScriptTest.java

File Similarity (%)
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/CheckQuarantineOwnersScriptTest.java 45.22
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/QuarantineRegistryScriptTest.java 33.08
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/QuarantineRegistryScriptTest.java

📄 parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/QuarantineRegistryScriptTest.java

File Similarity (%)
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/CheckQuarantineOwnersScriptTest.java 43.72
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/QuarantineLaneReportScriptTest.java 33.08
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/TestConventionsArchTest.java

📄 parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/TestConventionsArchTest.java

File Similarity (%)
parallel-consumer-vertx/src/test/java/io/confluent/parallelconsumer/vertx/TestConventionsArchTest.java 90.34 ⚠️
parallel-consumer-mutiny/src/test/java/io/confluent/parallelconsumer/mutiny/TestConventionsArchTest.java 89.68 ⚠️
parallel-consumer-reactor/src/test/java/io/confluent/parallelconsumer/reactor/TestConventionsArchTest.java 89.68 ⚠️
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/internal/BrokerPollSystemDrainTest.java

📄 parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/internal/BrokerPollSystemDrainTest.java

File Similarity (%)
parallel-consumer-core/src/test-integration/java/io/confluent/parallelconsumer/integrationTests/DrainingMemberRebalanceIT.java 31.54
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/internal/ExceptionConstructorsTest.java

📄 parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/internal/ExceptionConstructorsTest.java

File Similarity (%)
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/internal/InternalRuntimeExceptionTest.java 30.08
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/internal/InternalRuntimeExceptionTest.java

📄 parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/internal/InternalRuntimeExceptionTest.java

File Similarity (%)
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/internal/ExceptionConstructorsTest.java 30.08
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/internal/PCModuleTestEnv.java

📄 parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/internal/PCModuleTestEnv.java

File Similarity (%)
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/internal/PCModule.java 32.97
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/internal/ProducerManagerTest.java

📄 parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/internal/ProducerManagerTest.java

File Similarity (%)
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/internal/ProducerManager.java 30.64
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/internal/TestParallelEoSStreamProcessor.java

📄 parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/internal/TestParallelEoSStreamProcessor.java

File Similarity (%)
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/ParallelEoSStreamProcessor.java 31.14
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/offsets/OffsetEncodingBackPressureTest.java

📄 parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/offsets/OffsetEncodingBackPressureTest.java

File Similarity (%)
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/offsets/OffsetEncodingBackPressureUnitTest.java 40.08
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/offsets/OffsetEncodingBackPressureUnitTest.java

📄 parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/offsets/OffsetEncodingBackPressureUnitTest.java

File Similarity (%)
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/offsets/OffsetEncodingBackPressureTest.java 40.08
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/truth/CommitHistorySubject.java

📄 parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/truth/CommitHistorySubject.java

File Similarity (%)
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/truth/LongPollingMockConsumerSubject.java 36.66
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/truth/LongPollingMockConsumerSubject.java

📄 parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/truth/LongPollingMockConsumerSubject.java

File Similarity (%)
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/truth/CommitHistorySubject.java 36.66
parallel-consumer-mutiny/src/main/java/io/confluent/parallelconsumer/mutiny/MutinyProcessor.java

📄 parallel-consumer-mutiny/src/main/java/io/confluent/parallelconsumer/mutiny/MutinyProcessor.java

File Similarity (%)
parallel-consumer-reactor/src/main/java/io/confluent/parallelconsumer/reactor/ReactorProcessor.java 52.23 ⚠️
parallel-consumer-mutiny/src/test/java/io/confluent/parallelconsumer/mutiny/MutinyBatchTest.java

📄 parallel-consumer-mutiny/src/test/java/io/confluent/parallelconsumer/mutiny/MutinyBatchTest.java

File Similarity (%)
parallel-consumer-reactor/src/test/java/io/confluent/parallelconsumer/reactor/ReactorBatchTest.java 78.97 ⚠️
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/CoreBatchTest.java 50.73 ⚠️
parallel-consumer-vertx/src/test/java/io/confluent/parallelconsumer/vertx/VertxBatchTest.java 49.07
parallel-consumer-mutiny/src/test/java/io/confluent/parallelconsumer/mutiny/MutinyPCTest.java

📄 parallel-consumer-mutiny/src/test/java/io/confluent/parallelconsumer/mutiny/MutinyPCTest.java

File Similarity (%)
parallel-consumer-reactor/src/test/java/io/confluent/parallelconsumer/reactor/ReactorPCTest.java 71.2 ⚠️
parallel-consumer-mutiny/src/test/java/io/confluent/parallelconsumer/mutiny/MutinyTest.java

📄 parallel-consumer-mutiny/src/test/java/io/confluent/parallelconsumer/mutiny/MutinyTest.java

File Similarity (%)
parallel-consumer-reactor/src/test/java/io/confluent/parallelconsumer/reactor/ReactorTest.java 32.74
parallel-consumer-mutiny/src/test/java/io/confluent/parallelconsumer/mutiny/MutinyUnitTestBase.java

📄 parallel-consumer-mutiny/src/test/java/io/confluent/parallelconsumer/mutiny/MutinyUnitTestBase.java

File Similarity (%)
parallel-consumer-reactor/src/test/java/io/confluent/parallelconsumer/reactor/ReactorUnitTestBase.java 32.16
parallel-consumer-mutiny/src/test/java/io/confluent/parallelconsumer/mutiny/TestConventionsArchTest.java

📄 parallel-consumer-mutiny/src/test/java/io/confluent/parallelconsumer/mutiny/TestConventionsArchTest.java

File Similarity (%)
parallel-consumer-vertx/src/test/java/io/confluent/parallelconsumer/vertx/TestConventionsArchTest.java 91.13 ⚠️
parallel-consumer-reactor/src/test/java/io/confluent/parallelconsumer/reactor/TestConventionsArchTest.java 90.46 ⚠️
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/TestConventionsArchTest.java 89.68 ⚠️
parallel-consumer-reactor/src/main/java/io/confluent/parallelconsumer/reactor/ReactorProcessor.java

📄 parallel-consumer-reactor/src/main/java/io/confluent/parallelconsumer/reactor/ReactorProcessor.java

File Similarity (%)
parallel-consumer-mutiny/src/main/java/io/confluent/parallelconsumer/mutiny/MutinyProcessor.java 52.23 ⚠️
parallel-consumer-reactor/src/test/java/io/confluent/parallelconsumer/reactor/ReactorBatchTest.java

📄 parallel-consumer-reactor/src/test/java/io/confluent/parallelconsumer/reactor/ReactorBatchTest.java

File Similarity (%)
parallel-consumer-mutiny/src/test/java/io/confluent/parallelconsumer/mutiny/MutinyBatchTest.java 78.97 ⚠️
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/CoreBatchTest.java 52.04 ⚠️
parallel-consumer-vertx/src/test/java/io/confluent/parallelconsumer/vertx/VertxBatchTest.java 50.33 ⚠️
parallel-consumer-reactor/src/test/java/io/confluent/parallelconsumer/reactor/ReactorPCTest.java

📄 parallel-consumer-reactor/src/test/java/io/confluent/parallelconsumer/reactor/ReactorPCTest.java

File Similarity (%)
parallel-consumer-mutiny/src/test/java/io/confluent/parallelconsumer/mutiny/MutinyPCTest.java 71.2 ⚠️
parallel-consumer-reactor/src/test/java/io/confluent/parallelconsumer/reactor/ReactorTest.java

📄 parallel-consumer-reactor/src/test/java/io/confluent/parallelconsumer/reactor/ReactorTest.java

File Similarity (%)
parallel-consumer-mutiny/src/test/java/io/confluent/parallelconsumer/mutiny/MutinyTest.java 32.74
parallel-consumer-reactor/src/test/java/io/confluent/parallelconsumer/reactor/ReactorUnitTestBase.java

📄 parallel-consumer-reactor/src/test/java/io/confluent/parallelconsumer/reactor/ReactorUnitTestBase.java

File Similarity (%)
parallel-consumer-mutiny/src/test/java/io/confluent/parallelconsumer/mutiny/MutinyUnitTestBase.java 32.16
parallel-consumer-reactor/src/test/java/io/confluent/parallelconsumer/reactor/TestConventionsArchTest.java

📄 parallel-consumer-reactor/src/test/java/io/confluent/parallelconsumer/reactor/TestConventionsArchTest.java

File Similarity (%)
parallel-consumer-vertx/src/test/java/io/confluent/parallelconsumer/vertx/TestConventionsArchTest.java 91.13 ⚠️
parallel-consumer-mutiny/src/test/java/io/confluent/parallelconsumer/mutiny/TestConventionsArchTest.java 90.46 ⚠️
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/TestConventionsArchTest.java 89.68 ⚠️
parallel-consumer-vertx/src/main/java/io/confluent/parallelconsumer/vertx/JStreamVertxParallelEoSStreamProcessor.java

📄 parallel-consumer-vertx/src/main/java/io/confluent/parallelconsumer/vertx/JStreamVertxParallelEoSStreamProcessor.java

File Similarity (%)
parallel-consumer-vertx/src/main/java/io/confluent/parallelconsumer/vertx/VertxParallelEoSStreamProcessor.java 41.54
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/JStreamParallelEoSStreamProcessor.java 40.4
parallel-consumer-vertx/src/main/java/io/confluent/parallelconsumer/vertx/JStreamVertxParallelStreamProcessor.java 39.88
parallel-consumer-vertx/src/main/java/io/confluent/parallelconsumer/vertx/VertxParallelStreamProcessor.java 35.43
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/JStreamParallelStreamProcessor.java 32.44
parallel-consumer-vertx/src/main/java/io/confluent/parallelconsumer/vertx/JStreamVertxParallelStreamProcessor.java

📄 parallel-consumer-vertx/src/main/java/io/confluent/parallelconsumer/vertx/JStreamVertxParallelStreamProcessor.java

File Similarity (%)
parallel-consumer-vertx/src/main/java/io/confluent/parallelconsumer/vertx/JStreamVertxParallelEoSStreamProcessor.java 39.88
parallel-consumer-vertx/src/main/java/io/confluent/parallelconsumer/vertx/VertxParallelStreamProcessor.java 39.29
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/ParallelStreamProcessor.java 32.6
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/JStreamParallelEoSStreamProcessor.java 31.47
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/JStreamParallelStreamProcessor.java 30.22
parallel-consumer-vertx/src/main/java/io/confluent/parallelconsumer/vertx/VertxParallelEoSStreamProcessor.java

📄 parallel-consumer-vertx/src/main/java/io/confluent/parallelconsumer/vertx/VertxParallelEoSStreamProcessor.java

File Similarity (%)
parallel-consumer-vertx/src/main/java/io/confluent/parallelconsumer/vertx/VertxParallelStreamProcessor.java 41.75
parallel-consumer-vertx/src/main/java/io/confluent/parallelconsumer/vertx/JStreamVertxParallelEoSStreamProcessor.java 41.54
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/internal/ExternalEngine.java 39.59
parallel-consumer-vertx/src/main/java/io/confluent/parallelconsumer/vertx/VertxParallelStreamProcessor.java

📄 parallel-consumer-vertx/src/main/java/io/confluent/parallelconsumer/vertx/VertxParallelStreamProcessor.java

File Similarity (%)
parallel-consumer-vertx/src/main/java/io/confluent/parallelconsumer/vertx/VertxParallelEoSStreamProcessor.java 41.75
parallel-consumer-vertx/src/main/java/io/confluent/parallelconsumer/vertx/JStreamVertxParallelStreamProcessor.java 39.29
parallel-consumer-vertx/src/main/java/io/confluent/parallelconsumer/vertx/JStreamVertxParallelEoSStreamProcessor.java 35.43
parallel-consumer-vertx/src/test-integration/java/io/confluent/parallelconsumer/vertx/integrationTests/VertxConcurrencyIT.java

📄 parallel-consumer-vertx/src/test-integration/java/io/confluent/parallelconsumer/vertx/integrationTests/VertxConcurrencyIT.java

File Similarity (%)
parallel-consumer-core/src/test-integration/java/io/confluent/parallelconsumer/integrationTests/VeryLargeMessageVolumeTest.java 39.24
parallel-consumer-core/src/test-integration/java/io/confluent/parallelconsumer/integrationTests/TransactionAndCommitModeTest.java 30.02
parallel-consumer-vertx/src/test/java/io/confluent/parallelconsumer/vertx/TestConventionsArchTest.java

📄 parallel-consumer-vertx/src/test/java/io/confluent/parallelconsumer/vertx/TestConventionsArchTest.java

File Similarity (%)
parallel-consumer-mutiny/src/test/java/io/confluent/parallelconsumer/mutiny/TestConventionsArchTest.java 91.13 ⚠️
parallel-consumer-reactor/src/test/java/io/confluent/parallelconsumer/reactor/TestConventionsArchTest.java 91.13 ⚠️
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/TestConventionsArchTest.java 90.34 ⚠️
parallel-consumer-vertx/src/test/java/io/confluent/parallelconsumer/vertx/VertxBatchTest.java

📄 parallel-consumer-vertx/src/test/java/io/confluent/parallelconsumer/vertx/VertxBatchTest.java

File Similarity (%)
parallel-consumer-reactor/src/test/java/io/confluent/parallelconsumer/reactor/ReactorBatchTest.java 50.33 ⚠️
parallel-consumer-mutiny/src/test/java/io/confluent/parallelconsumer/mutiny/MutinyBatchTest.java 49.07
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/CoreBatchTest.java 44.86

@claude

claude Bot commented Aug 3, 2026

Copy link
Copy Markdown

Reviewing PR #111

View job run

@github-actions

github-actions Bot commented Aug 3, 2026

Copy link
Copy Markdown

✅ SpotBugs Report

No bugs found (new bugs only — baseline from base branch excluded).

…part

The pitest flag is trivial; carrying the file between CI runs is the actual
work. Records three things worth not re-deriving: it must never be committed
(regenerated every run, conflicts constantly, and its verdicts are valid only
for one code state - a stale committed file is worse than none); our script
does not clean, so locally it would persist and pay off immediately; and CI
starts every job from an empty target/, so it needs deliberate caching.

Plus the cache-key trap: per-SHA keys never hit, so you want a restore-key chain
letting PR runs inherit master's history - with periodic invalidation so stale
verdicts do not accumulate silently.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QqHpNSXC39ANv9kG1ZvUzn
@claude

claude Bot commented Aug 3, 2026

Copy link
Copy Markdown

Claude finished @astubbs's task in 2m 53s —— View job


Reviewing PR #111

Summary

Docs-only, no behaviour change — verified against the diff (git diff origin/master...HEAD --stat touches only the two listed files). Most claims check out against the live repo:

One factual issue worth fixing before this is taken as settled analysis

§4.2 / "Where the history file lives" in docs/plans/2026-08-03-002-mutation-testing-plan.md (lines 124–146) contradicts this repo's own already-documented finding, in the same file it's next to.

The new doc states:

the basic history file is free in OSS pitest; the git-aware, change-based incremental analysis is part of arcmutate (pitest Pro), which is commercial

and then spends a subsection discussing historyInputFile/historyOutputFile as a usable-today OSS mechanism (gitignore it, design a cache key, etc.).

But docs/inflight.md's existing, unchanged "INCREMENTAL HISTORY REMOVED (PR #69)" entry (around line 533 pre-PR, still present after this diff) already recorded the opposite, from an actual test against the exact pitest version this repo pins (1.25.8, confirmed in pom.xml):

-DwithHistory and the explicit -DhistoryInputFile/-DhistoryOutputFile now both error with "no history plugin has been installed" (history moved entirely to the commercial arcmutate plugin)

So on the version actually in use here, the basic history file is not free — it errors out without arcmutate too. That's not an open question needing verification, as the new doc frames it ("Flagged in the doc as needing verification first") — it was already tried and confirmed to fail in this exact repo, by an earlier PR (#69), which is why the history flags were removed from the build in the first place.

This doesn't change the doc's bottom-line recommendation (§4.2 stays deprioritized either way, arguably more justified once this is corrected), but as written, a future reader skimming just the new plan doc would come away believing plain history files are usable today and only the git-aware variant costs money — which this repo already disproved. Worth reconciling the two sections (either correct §4.2's premise, or add a pointer to the PR #69 finding) before this doc is treated as the definitive record docs/inflight.md says it is.

Everything else — the trap write-ups on timeoutConstant and test-code mutation, the proposal ordering, the "keep" list — reads as accurate and well-reasoned for a parked/draft analysis doc.

@github-actions

github-actions Bot commented Aug 3, 2026

Copy link
Copy Markdown

🧪🔒 Quarantine Lane Report

Quarantined test Outcome Owner Meaning
ChaosChurnStormIT.churnStormMeetsSlosAndBalancesLedger 🔴 failing (expected) #80 quarantine holding
PartitionStateCommittedOffsetIT.committedOffsetRemoved 🟡🎲 passed (flapper) #80 proves nothing - passes most runs by nature

🔴 expected while the owner PR is open · 🟡🎲 flapper, pass proves nothing · 🚨 a deterministic quarantined test passing means its fix landed: delete its @Quarantined annotation + docs/QUARANTINED_TESTS.md entry (a merge-blocking review thread has been opened). Lane: non-gating; rules: see the Quarantine Audit check.

…ntirely

This was the generalisable lesson from #108's inflight note, which had to be
resolved away during the rebase onto master once #110 rewrote the entry it was
updating. The specific flake is fixed and documented; the pattern behind it was
about to be lost, so it moves here where it belongs.

PIT refuses to run while ANY test is unstable without mutation - it needs a green
baseline to attribute kills to mutants rather than noise. So one unrelated flake
does not degrade the signal, it switches the whole lane off: zero mutants scored
anywhere, regardless of which class flaked or whether it relates to the code
being mutated. That has happened twice, both times somewhere unrelated - #101's
shutdown-commit flake and #110's produce-lock flake.

Three consequences worth holding onto, now written down:

- The lane's green-ness has been tracking SUITE STABILITY, not mutation
  coverage. Weaker signal than the one we thought we had.
- rerunFailingTestsCount cannot rescue it. Surefire reruns hide a flake from the
  unit gate, but PIT does its own coverage run and sees the raw result, so a
  papered-over flake still kills mutation testing. It has to be fixed.
- A red mutation lane usually means "something somewhere is flaky" rather than
  anything about mutants - check for the "did not pass without mutation" line
  before investigating mutation config.

Filed as section 3.0 rather than appended, because it is a property of the lane
as a whole and precedes the specific complaints about scope and targets.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QqHpNSXC39ANv9kG1ZvUzn
@claude

claude Bot commented Aug 4, 2026

Copy link
Copy Markdown

Claude finished @astubbs's task in 2m 59s —— View job


Reviewing PR #111

  • Gather context (PR body, diff, files changed)
  • Verify script/config claims against repo state (bin/ci-mutation-test.sh, pom.xml, test files)
  • Diff against my prior review (comment posted at commit 8e7ed7b3) to see what changed
  • Post review feedback

Summary

Docs-only, no behaviour change. I re-verified every checkable claim in the current HEAD (94d0758c) against the live repo — bin/ci-mutation-test.sh flags/messages, pom.xml's pinned pitest.version=1.25.8, and the referenced test method names (ParallelEoSStreamProcessorTest.queuedMessagesNotProcessedOrCommittedIfSubmittedDuringShutdown, ProducerManagerTest.producedRecordsCantBeInTransactionWithoutItsOffsetDirect) — all check out exactly as described.

The new §3.0 ("any single flaky test disables the lane entirely"), added since my last pass, is accurate and well-grounded: it matches PIT's actual behavior and cites #101 and #110 correctly as the two real occurrences.

Previously flagged issue — still present, unaddressed by the four commits since

My prior review (at 8e7ed7b3) flagged that §4.2 contradicts this repo's own already-documented finding. Four commits have landed on this exact topic since (be56ec9f, c5a996a7, 8e7ed7b3, 94d0758c), but the contradiction itself is untouched — same text, same line numbers (144–181 in docs/plans/2026-08-03-002-mutation-testing-plan.md).

The doc still says (line 159–161):

Check before relying on it: the basic history file is free in OSS pitest; the git-aware, change-based incremental analysis is part of arcmutate (pitest Pro), which is commercial. Confirm which capability we actually want and whether the free tier covers it, rather than assuming.

But docs/inflight.md (lines 540–543, unchanged, pre-existing) already recorded the opposite, from an actual test against the exact pinned pitest version (1.25.8, confirmed in pom.xml:116):

-DwithHistory and the explicit -DhistoryInputFile/-DhistoryOutputFile now both error with "no history plugin has been installed" (history moved entirely to the commercial arcmutate plugin)

So on the version actually in use here, the basic history file is not free — it errors out without arcmutate too. This isn't an open question needing verification (as framed by "Check before relying on it"/"Confirm ... rather than assuming") — it was already tried and confirmed to fail in this exact repo, by an earlier PR (#69), which is why the history flags were removed from the build in the first place.

This also undercuts the entire "Where the history file lives, and why CI is the hard part" subsection (lines 163–181), which discusses actions/cache cache-key design for carrying a history file between CI runs — premised on the OSS history mechanism working at all on this pitest version, which it doesn't.

Doesn't change the doc's bottom-line recommendation (§4.2 stays deprioritized either way — arguably more justified once corrected, since the "free OSS" fallback doesn't exist), but a reader who skims only the new plan doc would still come away believing plain history files are usable today and only the git-aware variant costs money. Worth reconciling before this is treated as the settled record docs/inflight.md points to it as.

Everything else — the new §3.0, the traps write-ups, the proposal ordering, the "keep" list, the numbers cited (42+/83+ min sweep times, 332s coverage pass, per-test timing) — reads as accurate for a parked/draft analysis doc.

astubbs and others added 2 commits August 4, 2026 14:07
…ches PIT off

The analysis in this PR argued that the mutation lane was measuring suite
stability rather than mutation coverage. This acts on the parts of that which
do not need a measurement first.

Any single flaky test used to disable mutation testing repo-wide: PIT needs a
green baseline to attribute a kill to a mutant rather than to noise, so one
unrelated flake scored zero mutants everywhere (twice: #101, #110).
skipFailingTests makes PIT drop that test's coverage instead of aborting.
Verified both ways with a deliberate failing test: off = exit 1 and the
green-suite abort, on = the run completes and scores. It has to live in the
pom - the mojo parameter declares no `property`, so -DskipFailingTests is
silently ignored - and parseSurefireConfig would let a <testFailureIgnore>
override it from a distance. Its cost is silence: pitest logs nothing when it
skips a test this way, so the job summary carries that caveat next to the
no-coverage count.

PIT was running up to four times per PR, three of them the same scoped
computation, and the `local` copy checked out shallow - which makes the script
fall back from scoped to the full sweep. One lane now: maven.yml. Unit and
Integration leave the highcpu matrix for the same reason: measured as not
faster than the hosted gate that already runs them, so they were a duplicate
verdict and one more tick to triage. The measured fork tuning is kept in
comments rather than lost with the entries.

The full internal.* sweep has never completed - 42+ min on CI, 83+ min locally
with minions dying on MEMORY_ERROR - so it scored zero mutants while holding a
16-core runner for its whole timeout on every push. It is now manual-only, and
deliberately not nightly: scheduling a job that has never finished only moves
the waste to a quieter hour. Its target is a dispatch input, so trying a
decidable package is a form field rather than a commit.

Every exit path now writes a job summary - scored, skipped, or died before
scoring - because a green mutation tick means "nothing to mutate" at least as
often as it means "all mutants killed".

Two corrections to the analysis, both from reading pitest's source rather than
its docs: skipFailingTests exists at all (the draft assumed the abort was
unavoidable), and mutableCodePaths is NOT a pitest-maven parameter, so §4.5 was
unimplementable - adding the element fails the build. Main-only is structural
under Maven; crossModule=false is pinned in its place.

Still outstanding and still unmeasured: the retarget off internal.* itself.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@astubbs astubbs changed the title docs(mutation): why mutation testing under-delivers here, and what would change it ci(mutation): one PR lane instead of four, and a flake no longer switches PIT off Aug 4, 2026
@claude

claude Bot commented Aug 4, 2026

Copy link
Copy Markdown

Claude finished @astubbs's task in 3m 28s —— View job


Reviewing PR #111

  • Gather context (PR body, diff, files changed, prior review comments)
  • Verify the new implementation commit (8c08ca14) against the repo: bin/ci-mutation-test.sh, pom.xml, all three workflow files
  • Check whether the previously-flagged §4.2 contradiction was addressed
  • Post review feedback

Summary

This adds the substantive implementation commit (8c08ca14) on top of the docs-only commits I reviewed earlier. No Java files changed (git diff origin/master...HEAD --stat -- '*.java' is empty), matching the PR body's claim. I re-verified every checkable claim against the live repo:

  • pom.xml:901+skipFailingTests/crossModule land in the pitest-maven <configuration> exactly as described, with the "no property, so -D... is silently ignored" reasoning in the comment.
  • bin/ci-mutation-test.sh — the set +e / PIPESTATUS[0] / set -e wrapping around the mvnw | tee pipe correctly isolates the build's exit code under set -euo pipefail, and the empty-STATS branch is only reachable once the earlier "nothing to mutate" exit 0 has already ruled itself out — so "died before scoring" is accurately scoped. The FAILED_TESTS grep's || true genuinely is needed on this path, matching the PR body's own bug note.
  • maven.yml (unmodified by this PR) really does call bin/ci-mutation-test.sh with no args and fetch-depth: 0 (maven.yml:131,143), confirming the "one lane" claim.
  • pr-highcpu-fast-feedback.yml and pr-local-fast-feedback.yml — the removed Unit/Integration/Mutation entries are gone cleanly (grep confirms no leftover job definitions, only explanatory comments), and the matrix/steps that remain are internally consistent.
  • mutation-full-sweep.ymlworkflow_dispatch-only, matches the "can't be reached from a fork PR" security claim.

Previously flagged issue — still unresolved, now a third time

My last two reviews (at 8e7ed7b3 and 94d0758c) flagged that §4.2 of docs/plans/2026-08-03-002-mutation-testing-plan.md contradicts this repo's own pre-existing finding. Commit 8c08ca14 rewrote large parts of this doc (183 lines changed) but left the contradiction itself untouched — still at lines 263–265:

Check before relying on it: the basic history file is free in OSS pitest; the git-aware, change-based incremental analysis is part of arcmutate (pitest Pro), which is commercial. Confirm which capability we actually want and whether the free tier covers it, rather than assuming.

docs/inflight.md:557–560 (pre-existing, unchanged by this PR) already recorded, from an actual test against the exact pinned pitest version (1.25.8, pom.xml:116):

-DwithHistory and the explicit -DhistoryInputFile/-DhistoryOutputFile now both error with "no history plugin has been installed" (history moved entirely to the commercial arcmutate plugin).

So the basic OSS history file is not free on this pitest version — it errors without arcmutate too, per PR #69's own finding. This isn't an open question needing "confirmation" as §4.2 frames it; it was already tried and failed in this exact repo. It also undercuts the "Where the history file lives, and why CI is the hard part" subsection (lines 267–285), which designs an actions/cache key strategy premised on the OSS history flag working at all.

Given this doc's own opening line now says "the cheap half is DONE... marked inline below" and docs/inflight.md points to it as the settled record, and given this is the third pass where the fix would have been a one-line pointer to the docs/inflight.md:557 finding, this is worth reconciling before the doc is treated as authoritative. It doesn't change the bottom-line recommendation (§4.2 stays low-priority either way — arguably more so once corrected, since the "free OSS fallback" doesn't exist), but a reader who trusts the doc's own "Check before relying on it" framing would go looking for something this repo already ruled out.

Minor, non-blocking

mutation-full-sweep.yml:80 interpolates ${{ inputs.threads }} directly into a shell run: command rather than routing it through env: first (as target-classes/target-tests on the two lines above it do). This matches an existing pattern elsewhere in the repo (release.yml), and workflow_dispatch already requires write access to trigger, so the practical risk is low — but it's an easy one-line fix (PIT_THREADS: ${{ inputs.threads }} + -Dthreads="$PIT_THREADS") for consistency with the two adjacent lines and with the "self-hosted runner" security posture the file's own header is careful about elsewhere.

Everything else — the CHANGELOG rewrite, docs/SELF_HOSTED_RUNNER.md, the docs/inflight.md "Mutation testing is pointed at the wrong target" addition, and the workflow comment claims about tuning/fork-counts — checks out accurately against the diff.

…l finding

The retarget the analysis argued for. internal.* is the concurrency core:
mutants to locks, loop conditions and timeouts hang by construction rather
than dying fast, which is why that sweep never completed - and its
timing-based tests make a survivor unfalsifiable anyway, since "nothing
asserts this" is indistinguishable from "the race didn't happen this run".
The offset encoders/decoders are the opposite on both counts: deterministic
tests, so a survivor is a real gap someone can act on, and the highest stakes
in the codebase, since a silent bug there means lost or duplicated records.

Applies to the sweep default only - in the script and as the workflow input
default, so a bare `gh workflow run mutation-full-sweep` now does the right
thing. Note where it does NOT apply: a PR run targets the classes that PR
changed, so a PR touching internal.* still mutates internal.*. Whether the
scoped lane should also refuse the hang-prone packages needs the measurement
below before it is worth answering.

target-tests is deliberately NOT narrowed to match. It is the one lever on the
332s instrumented coverage pass, but as a default it would trade accuracy for
speed: a mutant killed only by a test outside offsets.* would be reported as
no-coverage rather than killed, manufacturing survivors that aren't real. Left
as a deliberate purchase rather than an inherited one.

This is a config change made on the strength of an argument, not a result.
Nothing has completed under the new target either - offsets.* is not obviously
cheap, with RunLengthEncoderTest alone at ~140s re-run per mutant. The docs say
so, and say not to quote a mutation score for this project until a sweep
finishes.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@claude

claude Bot commented Aug 4, 2026

Copy link
Copy Markdown

Claude finished @astubbs's task in 1m 34s —— View job


Reviewing PR #111 (latest push)

  • Gather context (PR body, diff, prior review history)
  • Check what changed since my last review (commit 94d0758c → latest bc92a322)
  • Verify new/changed claims against repo state
  • Check if previously-flagged §4.2 issue was addressed
  • Post review feedback

Summary

The new commit (bc92a322) is the retarget itself: offsets.* becomes the default in bin/ci-mutation-test.sh:65 and mutation-full-sweep.yml's target-classes input default (.github/workflows/mutation-full-sweep.yml:45), with CHANGELOG.adoc, docs/inflight.md, and the plan doc updated to match. I re-verified the changed files against the live repo:

  • bin/ci-mutation-test.sh:65TARGET_CLASSES now defaults to io.confluent.parallelconsumer.offsets.*, and the PR-scoping logic above it (lines 79–97) derives the actual target from git diff against the base ref regardless of this default — so the doc's claim that "a PR touching internal.* still mutates internal.*" checks out; the default only governs the manual full-sweep path.
  • mutation-full-sweep.yml:45 — input default matches the script default (offsets.*), and the header comment's rationale (hang-by-construction mutants in internal.*, deterministic/high-stakes in offsets.*) is consistent word-for-word with the script comment and the plan doc's §4.3.
  • docs/inflight.md:406–417 — accurately reflects the new script/workflow state, including the "do not quote a score until a sweep completes" caveat.

Previously flagged issue — still present after this commit

My last two reviews flagged that §4.2 of docs/plans/2026-08-03-002-mutation-testing-plan.md (lines 267–268 currently) contradicts docs/inflight.md's pre-existing PR #69 finding that plain OSS history files also error out ("no history plugin has been installed") on the pinned pitest version (1.25.8), not just the git-aware/arcmutate variant. This commit touched the file extensively again (46 lines) but didn't touch §4.2 — same text, same contradiction, unaddressed for a fourth pass.

New, small inconsistency introduced by this commit

docs/plans/2026-08-03-002-mutation-testing-plan.md:3-4 (the top Status line, not edited by bc92a322) still reads:

the cheap half is DONE (shipped in PR #111, marked inline below); the substantive retarget is still parked and unscheduled.

But this commit's own table edit two lines below it (line 26) now says:

Retargeted to offsets.* | §4.3, the substantive one. ... | Done in #111

And §4.3's own heading was updated to — APPLIED in #111, not yet measured. So the retarget (the config change) is done — only the measurement (running the sweep) is still parked. The top Status line wasn't reconciled with the table/§4.3 edits in the same commit, and now reads as though the retarget itself never happened. Minor and doesn't affect the code, but worth a one-line fix (e.g. "the retarget is applied but unmeasured") since this line is the first thing a reader sees.

Everything else

The CHANGELOG.adoc rewrite and mutation-full-sweep.yml header/input-description changes are accurate and consistent with the script. The already-noted minor, non-blocking nit from my previous review (mutation-full-sweep.yml:89 interpolates ${{ inputs.threads }} directly into run: rather than via env:, unlike the two lines above it) is still present but unchanged in risk profile — workflow_dispatch already requires write access.

@astubbs astubbs changed the title ci(mutation): one PR lane instead of four, and a flake no longer switches PIT off ci(mutation): point PIT where survivors are real, and make the lane trustworthy Aug 4, 2026
…adds it

The docs told people to run `gh workflow run mutation-full-sweep`, which fails
with "could not find any workflows named mutation-full-sweep" until this
merges: workflow_dispatch requires the file on the DEFAULT BRANCH before it can
be dispatched at all, even when dispatching a different ref. So a workflow
introduced by a PR cannot be exercised by that PR.

Also spells out what a bare invocation targets - master - since that is the
question anyone reads the command and asks, and --ref is the answer for a
branch.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@claude

claude Bot commented Aug 4, 2026

Copy link
Copy Markdown

Claude finished @astubbs's task in 41s —— View job


Reviewing PR #111 (latest push)

  • Gather context (PR body, diff, prior review history)
  • Check what changed since my last review (bc92a322c33545f7)
  • Verify new claims against repo state
  • Post review feedback

Summary

The new commit (c33545f7) is docs-only: it adds the "workflow_dispatch requires the file on the default branch first" caveat to the sweep-invocation instructions in mutation-full-sweep.yml's header comment, docs/inflight.md, and the plan doc's §4.3-adjacent "run it" block. This matches known GitHub Actions behavior (workflow_dispatch resolves the workflow definition from the default branch, even when --ref points elsewhere) — the claim is accurate, and the three copies are consistent with each other word-for-word on the mechanism.

git diff origin/master...HEAD --stat now totals 762 insertions / 68 deletions across 9 files, matching the PR body's stated additions/deletions exactly, and confirms this push touched only the three files the commit message claims (mutation-full-sweep.yml, docs/inflight.md, the plan doc) — no code changed.

Previously flagged issue — still unresolved (fifth pass)

My prior four reviews flagged that §4.2 of docs/plans/2026-08-03-002-mutation-testing-plan.md (now lines 267–268) contradicts docs/inflight.md's own pre-existing, already-verified finding. This commit didn't touch §4.2.

Plan doc, lines 267–268:

Check before relying on it: the basic history file is free in OSS pitest; the git-aware, change-based incremental analysis is part of arcmutate (pitest Pro), which is commercial. Confirm which capability we actually want and whether the free tier covers it, rather than assuming.

docs/inflight.md:568–569 (pre-existing, from PR #69, unchanged by this PR):

-DhistoryInputFile/-DhistoryOutputFile now both error with "no history plugin has been installed" (history moved entirely to the commercial arcmutate plugin).

So on the pitest version this repo pins (1.25.8), the basic OSS history file already doesn't work — it was tried and confirmed to fail, which is why the flags were removed from the build in PR #69. §4.2 frames this as something to "check"/"confirm" rather than something already known, and the "Where the history file lives, and why CI is the hard part" subsection right after it (now ~lines 271–289) still designs an actions/cache key strategy premised on that OSS mechanism working. This doesn't change the doc's bottom-line recommendation (§4.2 stays low-priority regardless), but it's a one-line pointer to docs/inflight.md:568 away from being correct, and five commits have now touched this doc without closing it.

Everything else

Accurate and consistent with the repo. No new issues introduced by this push.

@astubbs

astubbs commented Aug 4, 2026

Copy link
Copy Markdown
Owner Author

Review response: §4.2 contradiction — fixed, and you were right to keep raising it

Addressed the finding flagged across five passes. It was not a documentation nitpick: the plan doc contradicted an already-verified finding in this repo's own ledger, which is precisely the failure the ledger exists to prevent.

Rather than pick between the two documents, I re-ran it:

$ bin/ci-mutation-test.sh -DwithHistory=true
[ERROR] History has been enabled but no history plugin has been installed/activated.
[ERROR] If you are using https://www.arcmutate.com remember to activate the history plugin with +arcmutate_history

docs/inflight.md is correct and §4.2 was wrong twice over: pitest 1.25.8 has no free file-based history at all (dropped in the 1.17.4 → 1.25.8 bump in #73), so there was no "free tier" to confirm. §4.2 now:

  • opens with the correction and the reproduction above, rather than being silently rewritten;
  • names the real work item — obtaining and wiring an arcmutate licence (free for OSS, but needs maintainer signup and a licence file at the repo root, which on a public repo means a committed key or a CI secret) — and points at the existing shelved plan in docs/inflight.md instead of duplicating it;
  • keeps the cache-key discussion, which is unaffected by which plugin produces the file;
  • records the meta-lesson: a repeated review finding that keeps being deferred is usually a real one, and this one cost a single local run to settle.

docs/inflight.md also now carries the re-verification date, so the next person finds agreement rather than a contradiction to arbitrate.

Thanks for the persistence on this one — the earlier passes were correct and I should have acted on the first.

…dy said otherwise

The automated reviewer flagged this contradiction on five consecutive passes
and it kept being deferred. It was right, and it was not a nitpick: the plan
doc asserted "the basic history file is free in OSS pitest, confirm whether the
free tier covers what we want", while docs/inflight.md records the opposite as
an already-verified PR #69 finding - 1.25.x dropped file-based history when #73
bumped 1.17.4 -> 1.25.8.

Settled by running it rather than by choosing which document to believe:

  [ERROR] History has been enabled but no history plugin has been installed/activated.
  [ERROR] If you are using https://www.arcmutate.com remember to activate the history plugin

So there is no free tier to check. History lives entirely in arcmutate, and the
work item is obtaining and wiring a licence - free for OSS, but needing
maintainer signup and a licence file at the repo root, which on a public repo
means a committed key or a CI secret. The existing shelved plan in inflight.md
covers that; §4.2 now points at it rather than duplicating it.

The correction is written in place, with the reproduction, rather than the
section being quietly rewritten - the same treatment as the other two
corrections in this doc. inflight.md gains the re-verification date so the next
reader finds agreement instead of a contradiction to arbitrate.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@claude

claude Bot commented Aug 4, 2026

Copy link
Copy Markdown

Claude finished @astubbs's task in 1m 4s —— View job


Reviewing PR #111 (latest push)

  • Gather context (PR body, diff, prior review history)
  • Check what changed since my last review (c33545f7aaae3f05)
  • Verify the §4.2 fix against the repo
  • Post review feedback

Summary

The new commit (aaae3f05) is the fix for the issue I flagged across five consecutive reviews. It's docs-only (docs/inflight.md, docs/plans/2026-08-03-002-mutation-testing-plan.md), and I independently re-verified every factual claim in it:

  • The 1.17.4 → 1.25.8 pitest bump claim checks out. git show 6b59dde2 (PR build(deps): refresh dependencies + build plugins to latest non-major #73) shows exactly that change: -<pitest.version>1.17.4</pitest.version> / +<pitest.version>1.25.8</pitest.version>.
  • The current pin matches what's now documented as broken. pom.xml:116 still pins 1.25.8, so the "no free tier to check" conclusion applies to the version actually in use, not a hypothetical one.
  • The reproduction is consistent with docs/inflight.md's pre-existing PR test: faster + cleaner unit suite - fork per-core, ArchUnit integration-test guard, RunLengthEncoder speedup, DI #69 finding — both cite the identical error text ("no history plugin has been installed/activated" / "...installed"), and the corrected §4.2 now explicitly attributes the ledger as the source of truth rather than silently rewriting itself.
  • docs/inflight.md's entry was tightened, not just re-asserted: it now names the re-verification date (2026-08-04) and points at the corrected plan-doc section, closing the loop between the two documents instead of leaving one to contradict the other.
  • The overall diff total (782 insertions(+), 68 deletions(-) across 9 files) matches the PR body exactly, confirming no other files were touched by this push.

This resolves the contradiction cleanly: §4.2 now opens with the correction and a live reproduction, keeps the (unaffected) cache-key design discussion, and replaces "confirm which capability we want" with the actual work item (an arcmutate licence). The meta-lesson paragraph about deferred review findings is a good addition for future readers of this doc.

I have no further findings on this PR. Everything across all reviewed commits (8e7ed7b3aaae3f05) now reads as internally consistent, and the one previously-open item is resolved.

@claude

claude Bot commented Aug 4, 2026

Copy link
Copy Markdown

Claude finished @astubbs's task in 1m 1s —— View job


Reviewing PR #111

  • Gather context (PR body, diff, prior review history)
  • Check what changed since my last review (aaae3f05)
  • Verify repo state
  • Post review feedback

Summary

No new commits have landed since my previous review — HEAD is still aaae3f05, the same commit I already reviewed and confirmed resolves the one open issue (the §4.2 contradiction with docs/inflight.md's PR #69 finding).

Recap of that resolution, re-confirmed against the current tree:

  • pom.xml:116 pins pitest.version to 1.25.8, matching the reproduction in aaae3f05.
  • docs/plans/2026-08-03-002-mutation-testing-plan.md §4.2 now opens with the corrected finding and a live reproduction (-DwithHistory=true → "no history plugin has been installed/activated"), rather than asking a future reader to "confirm" something already disproven.
  • docs/inflight.md carries the re-verification date and points back at the corrected plan-doc section — the two documents no longer disagree.
  • git diff origin/master...HEAD --stat totals 782 insertions(+), 68 deletions(-) across 9 files, matching the PR body exactly; no files changed since my last pass.

I have no further findings on this PR across all six reviewed commits (8e7ed7b3aaae3f05). The lane consolidation, skipFailingTests/crossModule config, job-summary logic, and offsets.* retarget all check out against the live repo as described, and the one substantive issue raised during review has been fixed and independently verified.

Checking the PR's own claims against the diff caught a specifics error I had
repeated into five files: "PIT was running up to four times per PR". The fourth
copy, in pr-local-fast-feedback.yml, has had its `pull_request` trigger
commented out since that runner went offline - so it only ever ran on manual
dispatch. Three ran per PR: two highcpu entries plus the hosted lane, two of
them the same scoped computation.

The distinction matters in both directions. Rounding up overstates what was
being wasted, and it obscures the actual reason that copy was worth deleting:
not that it was burning runner time, but that it checks out SHALLOW, which
makes the script fall back from scoped to the full sweep - so re-enabling the
trigger would have silently shipped the hazard.

Corrected in the plan doc, inflight, SELF_HOSTED_RUNNER, CHANGELOG, the highcpu
workflow header and the PR body.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@claude

claude Bot commented Aug 4, 2026

Copy link
Copy Markdown

Claude finished @astubbs's task in 1m 42s —— View job


Reviewing PR #111 (latest push)

  • Gather context (PR body, diff, prior review history)
  • Check what changed since my last review (aaae3f055b480ffc)
  • Verify new claims against repo state
  • Post review feedback

Summary

One new commit since my last review, 5b480ffc, purely a precision correction: "PIT ran up to four times per PR" becomes "three times per PR, with a fourth copy configured but dormant" — corrected in the plan doc, docs/inflight.md, docs/SELF_HOSTED_RUNNER.md, CHANGELOG.adoc, and the pr-highcpu-fast-feedback.yml header comment.

I verified the corrected count directly against the pre-removal workflow (git show 8c08ca14^:.github/workflows/pr-highcpu-fast-feedback.yml): pr-highcpu carried two mutation entries, "Mutation (PIT, scoped)" and "Mutation (PIT, full)" (the latter forcing PIT_FULL_SWEEP, a genuinely different computation from the scoped one). Combined with maven.yml's scoped run, that's three jobs actually running per PR, of which two (maven.yml + highcpu-scoped) were duplicate scoped computations — exactly what the corrected text now says. pr-local-fast-feedback.yml's on: trigger confirms the fourth copy's dormancy: pull_request: is commented out, leaving only workflow_dispatch:, so that mutation job (removed by an earlier commit in this PR) never ran automatically.

One leftover inconsistency this correction pass didn't reach

.github/workflows/pr-local-fast-feedback.yml:60-61 (touched by an earlier commit in this PR, 8c08ca14, but not by 5b480ffc) still reads:

# NO MUTATION HERE. It was a third copy of the same scoped run (maven.yml + two highcpu entries), and this checkout is SHALLOW...

That sentence lists maven.yml + "two highcpu entries" (3 items) as the other copies, then calls the local job itself the "third" — which only works if it's counting local as one of 3 total, i.e. contradicting its own parenthetical (maven.yml + 2 highcpu = 3, plus local = 4). It also restates the pre-correction miscount this same commit just fixed everywhere else: only one of the two highcpu entries (scoped) was "the same scoped run" — the other (full) was the different, never-completing internal.* sweep, per git show 8c08ca14^ above.

Suggested fix, consistent with the wording now used in pr-highcpu-fast-feedback.yml's header:

# NO MUTATION HERE. It was a third copy of the same scoped run (maven.yml + the highcpu "scoped"
# entry), and this checkout is SHALLOW - so when the PR base ref failed to resolve,

Minor and comment-only — doesn't affect behavior — but it's the same class of cross-file numeric drift this PR has otherwise been careful to stamp out everywhere, and it sits right in the file that documents why the mutation job was deleted from this lane.

Everything else

No other changes since my last review (aaae3f05). All previously-verified claims (lane consolidation, skipFailingTests/crossModule, job-summary logic, offsets.* retarget, the §4.2 history-file correction) remain accurate against the current tree.

…ecord

Both files had grown a mutation entry many times the size of its neighbours,
by the same mechanism: every correction this PR made was APPENDED as another
clause instead of replacing the text it corrected.

CHANGELOG.adoc: 412 words against a ~90-word median for the section, and the
longest bullet in the file - it had become a copy of the PR description. Now 90
words: what changed, what it means, and a link to the plan doc that holds the
reasoning. The neighbouring highcpu entry is trimmed too (154 -> 121).

docs/inflight.md: 75 lines against a 5-line median, the largest of 75 entries
in a 758-line file. That file's own header forbids exactly what I did - "This
file is NOT a record... Do NOT keep a closed item by rewriting it into a
FIXED/DONE narrative - making a stale entry accurate is the wrong move." Every
closed item is deleted; the four genuinely-open follow-ups remain, in 13 lines,
pointing at the plan doc.

The duplication was not just noise. Two copies of the same claims have to be
corrected together, and this PR twice showed that doesn't happen reliably - the
§4.2 plan-doc/ledger contradiction, and the "four times per PR" fix that missed
its sixth file. Shrinking the copy removes the sync obligation.

Recorded the rule where the next writer will see it rather than relying on
someone catching it again: a terseness note in AGENTS.md's Changelog section
and in CHANGELOG.adoc's own header, both saying an entry highlights a change
and points at the detail, with the ~90-word calibration and the instruction
that corrections replace text rather than accrete onto it. README regenerated.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@claude

claude Bot commented Aug 4, 2026

Copy link
Copy Markdown

Claude finished @astubbs's task in 1m 34s —— View job


Reviewing PR #111 (latest push)

  • Gather context (PR body, diff, prior review history)
  • Check what changed since my last review (7666c9c92aabce5d)
  • Verify new claims against repo state
  • Post review feedback

Summary

One new commit since my last review, 2aabce5d — a trim pass on CHANGELOG.adoc, docs/inflight.md, README.adoc, and AGENTS.md. It's not code, but I checked its own quantitative claims rather than taking them on trust, since the commit's whole premise is precision:

  • CHANGELOG word counts. The commit message claims the mutation entry is now exactly 90 words and the neighbouring highcpu entry went from 154 to 121. I counted both directly: grep "Mutation testing (PIT) runs once per PR" CHANGELOG.adoc | wc -w90, grep "Optional, non-gating self-hosted..." CHANGELOG.adoc | wc -w121. Both exact.
  • docs/inflight.md trim. The mutation entry is now 4 bullets in 13 lines under a one-line summary, matching "the four genuinely-open follow-ups... in 13 lines" exactly. I checked each surviving bullet is actually still open and not a stale re-assertion: the sweep genuinely hasn't run yet, excludedGroups (plan §3.4) is explicitly still unverified, the withHistory/arcmutate finding is the one independently confirmed in my last review, and the scoped-lane-still-mutates-internal.* caveat is accurate per the retarget's own scope (confirmed in an earlier pass).
  • The "shelved plan below" pointer (docs/inflight.md:357) resolves correctly to the existing arcmutate OSS-licence section at line 499 in the same file — not a dangling reference introduced by the deletion.
  • The file's own header rule ("This file is NOT a record... delete closed items") is real, pre-existing text (docs/inflight.md:9-11), so the commit is correcting the entry to match a standing rule it had been violating, not inventing a new one.
  • README.adoc mirrors CHANGELOG.adoc for both edited bullets — confirmed byte-for-byte identical between the two files' corresponding entries.
  • No reasoning was lost in the deletion: the removed detail (the TIMED_OUT/timeoutConstant trap, the "green often means nothing to mutate" point, etc.) is present in docs/plans/2026-08-03-002-mutation-testing-plan.md (§6, the timeoutConstant=30000 discussion, the "nothing to mutate" job-summary section) — the ledger now points at it instead of duplicating it.
  • Diff scope: git diff 7666c9c9..HEAD --stat touches exactly the 4 files the commit message names, nothing else. git diff origin/master...HEAD --stat totals 771 insertions(+), 83 deletions(-) across 15 files, matching the PR body's stated Additions/Deletions exactly.

Overall

Across all nine reviewed commits (8e7ed7b32aabce5d), I have no unresolved findings. The two substantive issues raised during review — the §4.2 history-file contradiction and the pr-local-fast-feedback.yml count/attribution miscount — were both fixed and independently verified, and this final trim pass is accurate and doesn't reintroduce either. This PR is in good shape to merge.

The retarget only governed the manual sweep - the path that runs least often -
so the recurring case was left exactly as bad as before: a PR touching
internal.* still got hang-prone mutants and unfalsifiable survivors. Fixing the
rare path and calling it done was the wrong shape of fix.

The lane now intersects its changed-class list with the same decidable set that
the sweep targets (PIT_DECIDABLE_PACKAGES, default `offsets.`). Changed classes
outside it are not mutated, and are NAMED - in the log and in the job summary,
on both the skip path and the scoring path - so a run that mutated one of five
changed classes cannot read like a run that covered the PR.

The job timeout is not an argument against this. It does not bound the damage,
it converts "slow" into "cancelled with nothing scored", which is the same zero
signal the full sweep produced for months.

Measured on 12 cores before choosing the default:

  one changed internal class (BrokerPollSystem)
    coverage pass 271s, then mutation analysis of that SINGLE class had still
    not reached the statistics stage 4 minutes later, when it was killed
  one changed offsets class (OffsetSimpleSerialisation)
    430s end to end, 18 mutations scored

The hosted PR lane has two cores, not twelve.

Verified all three paths against a scratch commit touching one internal and one
offsets class: mixed -> mutates offsets only and names the internal skip;
internal-only -> skips in ~1s with the reason; offsets-only -> scores. The
scratch commit is not part of this change.

Starting narrow on purpose: `offsets.` alone. `state.` is the obvious next
candidate but is bookkeeping around the same concurrency, so it earns inclusion
by measurement, not by argument.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@claude

claude Bot commented Aug 4, 2026

Copy link
Copy Markdown

Claude finished @astubbs's task in 3m 14s —— View job


Reviewing PR #111 (latest push)

  • Gather context (PR body, diff, prior review history)
  • Check what changed since my last review (2aabce5ddd938d57)
  • Verify the new commit's logic against the repo (static trace of bin/ci-mutation-test.sh, cross-checked docs/workflows for stale claims)
  • Post review feedback

Summary

One new commit since my last review, dd938d57, and it closes out an item that had been sitting open in docs/inflight.md since my earlier passes: "the scoped PR lane still mutates whatever changed, including internal.* — whether it should refuse the hang-prone packages needs the measurement above first." This commit does the measurement and acts on it.

What it does: bin/ci-mutation-test.sh's PR-scoping now intersects the changed-class list with a new PIT_DECIDABLE_PACKAGES allowlist (default ^io\.confluent\.parallelconsumer\.offsets\.), so a PR touching internal.* no longer mutates it — those classes are named (not silently dropped) in both the console log and the job summary, on the skip path and the scoring path.

I traced the new script logic (bin/ci-mutation-test.sh:80-133,173-181) by hand rather than executing it — the Bash tool in this session declined to run the script directly (bash -n/bash <script> required approval that wasn't grantable headlessly), so this is static verification, not an executed one:

  • set -u safety: SKIPPED is only assigned inside the BASE_REF branch (line 106); the full-sweep else branch (line 132) never sets it. The later check correctly uses ${SKIPPED:-} (line 173) rather than $SKIPPED, which avoids an unbound-variable abort under set -euo pipefail on the full-sweep path. This is exactly the kind of thing that would only surface at runtime on the untested branch, and it's handled correctly.
  • Regex escaping: DECIDABLE="${PIT_DECIDABLE_PACKAGES:-^io\.confluent\.parallelconsumer\.offsets\.}" — inside double quotes, bash doesn't treat \. specially (backslash is only special before $, `, ", \, newline), so the literal backslash-dot sequence survives into the variable and is interpreted correctly by grep -E as an escaped literal dot, not "any char." Correct.
  • Both partition branches (grep -E "$DECIDABLE" / grep -Ev "$DECIDABLE", lines 105–106) are wrapped with || true, so an all-skipped or all-decidable split doesn't trip set -e on grep's no-match exit code — consistent with the existing pattern already used elsewhere in this file (and flagged as a real bug pattern in this PR's own "Testing" section for a different grep).
  • No double-counting: the early-exit skip path (all changed classes non-decidable, lines 107–120) and the later job-summary block (lines 169–181, reached only when at least one class was mutated) are mutually exclusive — I didn't find a path where both fire or where SKIPPED leaks stale state between runs (it's a fresh $() capture each invocation).

Cross-checked for staleness (the failure mode this PR has been systematically hunting): grepped the repo for the now-false claim "a PR touching internal.* still mutates internal.*" — no remaining occurrences; all other internal.* mentions are correctly historical/past-tense (describing what the sweep used to target, or what was removed from highcpu). docs/inflight.md's bullet was swapped 1:1 (still 4 bullets under "Mutation testing," matching the count established by the earlier trim commit I verified previously) rather than appended, so no drift there either. CHANGELOG.adoc and README.adoc are byte-identical for the updated bullet, as in every prior commit of this PR.

The measurement backing the default (12 cores: one changed internal class — coverage pass 271s, then mutation analysis of that single class still not at the statistics stage 4 minutes later when killed; one changed offsets class — 430s end-to-end, 18 mutations scored) is the author's own local run and not something I can re-execute here, but it's internally consistent with the 430s/18-mutant figure already independently verified in an earlier review pass of this PR, and with the plan doc's RunLengthEncoderTest ~140s figure.

Minor, non-blocking

maven.yml:118-120's header comment ("ci-mutation-test.sh scopes to the classes CHANGED vs the PR base... so it's fast enough for the 2-core hosted runner") predates this commit and wasn't touched by it. It's not wrong, but it's now incomplete: the reason a PR touching only internal.* is safe on a 2-core runner is the new decidable-package filter (a single internal.* class didn't finish in >4 min on 12 cores, per this commit's own measurement) — plain changed-class scoping alone wouldn't have been "fast enough" for that case. Not this commit's file to fix, and not a defect, just a comment that could use the same tightening this PR has given five other files.

Overall

Across all ten reviewed commits (8e7ed7b3dd938d57), I have no unresolved findings. This commit fixes a real, previously-flagged gap (the scoped lane's internal.* exposure) rather than just documenting around it, ships log/summary transparency for what it declines to mutate, and I found no logic or staleness defects in it.

"Killed 9 (50%)" cannot be acted on - it does not say which half survived, so
it reads as a grade rather than a work item. Each surviving mutant, by
contrast, names a specific behaviour that can be broken without any test
noticing:

  SURVIVED     OffsetSimpleSerialisation.java:38  removed call to ObjectOutputStream::writeObject
  NO_COVERAGE  OffsetSimpleSerialisation.java:55  removed call to SnappyOutputStream::write

Adds -DoutputFormats=XML,HTML and parses mutations.xml into the job summary.
No XML parser: pitest writes one <mutation> element per line, so sed does it
without adding a dependency to the CI path. Anything not KILLED or TIMED_OUT is
listed - PIT counts a timeout as a kill, which is also why the timeout cannot
simply be lowered.

Two details found by looking at the output rather than assuming it:

- sort the line numbers NUMERICALLY. As text, 119 sorts above 38 and the table
  reads as though it were in no order at all.
- strip fully-qualified paths from the descriptions. file:line already locates
  the mutant, so "for io/confluent/parallelconsumer/offsets/Foo::bar" is ~60
  characters of noise on every row.

Capped at 50 rows, and the cap is stated when it bites: a truncated list that
looks complete is worse than no list.

Verified end to end - 18 mutants generated, 9 killed, and the 9 that survived
listed in file/line order with readable descriptions.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@claude

claude Bot commented Aug 4, 2026

Copy link
Copy Markdown

Claude finished @astubbs's task in 7m 11s —— View job


Reviewing PR #111 (latest push)

  • Gather context (PR body, diff, prior review history)
  • Check what changed since my last review (dd938d5765519076)
  • Verify new claims against repo state — including an actual scoped PIT run to test the new sed/XML pipeline against real output
  • Post review feedback

Summary

One new commit, 65519076, adds the survivor list to the job summary: -DoutputFormats=XML,HTML plus a sed/awk/sort pipeline that parses mutations.xml into a file:line — description table, replacing the bare kill percentage.

This is the one commit in this PR's whole run where I couldn't verify the central claim by reading code alone — "pitest writes one <mutation> element per line" is an empirical claim about output formatting, and the whole pipeline's correctness hinges on it. So I ran it for real rather than trusting the commit message's "verified end to end":

  • Scoped a real PIT run at OffsetSimpleSerialisation / WorkManagerOffsetMapCodecManagerTest (the exact class the commit's own example uses) with the same flags this script passes. Result: 18 mutations, 9 killed — matching the commit message exactly.
  • Checked the real mutations.xml: 21 lines total (2 header/footer + 18 mutations) — confirming one <mutation> per line is genuinely true for this pitest version, not an assumption.
  • Independently confirmed (via a regex search, not the sed script itself) that all 18 lines match the shape the sed pattern expects (status='...'…<sourceFile>…</sourceFile>…<lineNumber>…</lineNumber>…<description>…</description>), and that the element order in real output (sourceFilelineNumberdescription) matches what the capture groups assume.
  • Tallied real statuses: 9 KILLED, 8 NO_COVERAGE, 1 SURVIVED → 9 non-killed/non-timed-out, matching the commit's "9 survived" claim exactly.
  • Also checked the reportsDirectory/timestampedReports assumption behind REPORT="parallel-consumer-core/target/pit-reports/mutations.xml" — queried pitest-maven 1.25.8's own mojo help rather than relying on memory (pitest-maven's default for this parameter has changed across versions, so I didn't want to guess): timestampedReports defaults to false on this exact pinned version, and reportsDirectory defaults to ${project.build.directory}/pit-reports. So the flat (non-timestamped) path the script assumes is correct for this pom.
  • Traced the HTML-entity unescaping order (&quot;&apos;&lt;&gt;&amp;, with &amp; last) against real output containing &quot;&quot; — correct order to avoid a double-unescape corrupting a literal ampersand.
  • Traced the FQCN-stripping regex against a real description (replaced return value with &quot;&quot; for io/confluent/parallelconsumer/offsets/OffsetSimpleSerialisation::base64) — correctly reduces to OffsetSimpleSerialisation::base64.

Everything checks out against real, freshly-generated output, not just the synthetic example in the commit message.

One minor, non-blocking observation

bin/ci-mutation-test.sh:209 filters with $3 != "KILLED" && $3 != "TIMED_OUT", so any other PIT status lands in the survivor table — including MEMORY_ERROR, RUN_ERROR, and NON_VIABLE, which are infrastructure/build failures, not "a behaviour nothing asserts" (the table's own header text). For the current target (offsets.* — deterministic, non-concurrency code) this is unlikely to bite, and the full sweep where MEMORY_ERROR is a known risk (per this PR's own mutation-full-sweep.yml comments) is manual-only and not wired to this summary path the same way. Not worth blocking on, but worth knowing if the decidable-package scope ever widens to something where minions are more failure-prone.

Overall

Across all eleven reviewed commits (8e7ed7b365519076), I have no unresolved findings. The two substantive issues raised earlier in review (the §4.2 history-file contradiction and the pr-local-fast-feedback.yml count/attribution miscount) were both fixed and verified in prior passes and remain intact. This commit is accurate and, unusually for a docs/CI PR, I was able to empirically verify its core technical claim by actually running the tool rather than reading the script.

@astubbs

astubbs commented Aug 4, 2026

Copy link
Copy Markdown
Owner Author

Review response: error statuses were being listed as test gaps - fixed

Valid, and worth more than "non-blocking": the table's header said each is a behaviour nothing asserts, while the filter admitted anything that was not KILLED/TIMED_OUT - so a MEMORY_ERROR or RUN_ERROR would have been presented as a missing test. That is the lane misreporting itself, which is the exact defect this PR exists to remove. Fixing it here rather than deferring, since the decidable-package scope is expected to widen and MEMORY_ERROR is a known risk on this codebase.

The two are now separated by meaning rather than by "not killed":

  • SURVIVED / NO_COVERAGE → the survivor table. Something is untested.
  • anything else (MEMORY_ERROR, RUN_ERROR, NON_VIABLE, …) → a separate "Could not be evaluated - infrastructure, not test gaps" count, with the line that matters: the score above is over a smaller set than it looks. An unevaluated mutant is neither killed nor surviving, and quietly folding it into either is how a broken run comes to look like a measured one.

Verified by injecting a MEMORY_ERROR into a real mutations.xml and re-running the reporting path: survivors stayed at 9, the error was reported separately under its own heading.

Also noted your verification method - regenerating mutations.xml and checking the one-element-per-line assumption, the element ordering, the entity-unescape order and timestampedReports against the pinned 1.25.8 mojo rather than from memory. The timestampedReports check in particular is one I should have made myself: the script hard-codes a flat report path, and that default has moved between versions.

The survivor table admitted anything that was not KILLED or TIMED_OUT, under a
heading reading "each is a behaviour nothing asserts". MEMORY_ERROR, RUN_ERROR
and NON_VIABLE mean the mutant could not be EVALUATED - the minion died, or the
bytecode would not load - which is an infrastructure problem, not a missing
test. Presenting one as the other is the lane misreporting itself, which is the
defect this PR exists to remove. Raised in review as non-blocking; fixed anyway,
because the decidable-package scope is meant to widen and MEMORY_ERROR is a
known risk here.

Split by meaning rather than by "not killed":

  SURVIVED / NO_COVERAGE  -> the survivor table; something is untested
  anything else           -> "Could not be evaluated - infrastructure, not test
                             gaps", with the count and the consequence stated:
                             the score is over a smaller set than it looks

An unevaluated mutant is neither killed nor surviving, and folding it into
either is how a broken run comes to look like a measured one.

Verified by injecting a MEMORY_ERROR into a real mutations.xml and re-running
the reporting path: survivors stayed at 9, the error reported separately.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@claude

claude Bot commented Aug 4, 2026

Copy link
Copy Markdown

Claude finished @astubbs's task in 1m 12s —— View job


Reviewing PR #111 (latest push)

  • Gather context (PR body, diff, prior review history)
  • Check what changed since my last review (65519076c5c8083c)
  • Verify the "unevaluated mutant" fix against repo state
  • Post review feedback

Summary

One new commit, c5c8083c, is the fix for the issue I flagged in my previous review: MEMORY_ERROR/RUN_ERROR/NON_VIABLE mutants were being folded into the survivor table alongside SURVIVED/NO_COVERAGE, which misreports infrastructure failures as test gaps.

I traced the new logic in bin/ci-mutation-test.sh:200-241 directly:

  • SURVIVORS switched from a negative filter ($3 != "KILLED" && $3 != "TIMED_OUT") to a positive allowlist ($3 == "SURVIVED" || $3 == "NO_COVERAGE") — this is the correct fix. It no longer admits any other status.
  • New UNEVALUATED block catches everything else ($3 != "KILLED" && $3 != "TIMED_OUT" && $3 != "SURVIVED" && $3 != "NO_COVERAGE"), tallies by status with uniq -c, and prints it under a separate "Could not be evaluated - infrastructure, not test gaps" heading with an explicit caveat that the score above is over a smaller set than it looks. Matches exactly what the author's response comment described, and what I verified by tracing rather than re-running (the author's own comment says they injected a synthetic MEMORY_ERROR and confirmed survivors stayed at 9 with the error reported separately — consistent with this diff).
  • Both SURVIVORS and UNEVALUATED share the same PARSED capture now (computed once, filtered twice) rather than re-parsing the XML — a reasonable simplification alongside the fix, not just the minimal patch.

One new finding: the fix leaves a stale comment saying the opposite of what the code now does

bin/ci-mutation-test.sh:200-201, untouched by this commit, still reads:

# No XML parser needed: pitest writes one <mutation> element per line, so sed suffices. Anything not
# KILLED or TIMED_OUT survived (PIT counts a timeout as a kill - see the timeoutConstant note above).

That was true of the old filter (!= KILLED && != TIMED_OUT) but is now false: three lines later, the new comment at line ~211 correctly says the opposite — MEMORY_ERROR/RUN_ERROR/NON_VIABLE are explicitly not survivors. The two comments, six lines apart in the same function, now contradict each other, and the stale one is the one a reader hits first.

This is squarely the defect class this PR spent itself hunting elsewhere (§ "a review finding that keeps being deferred is usually real," the quarantine-lane stale-comment purge, the pr-local-fast-feedback.yml miscount) — a comment that "reads as authoritative because of where it sits" and teaches the pre-fix behavior. Suggested fix, one line:

# No XML parser needed: pitest writes one <mutation> element per line, so sed suffices. SURVIVED and
# NO_COVERAGE are the only statuses that count as survived (PIT counts a timeout as a kill - see the
# timeoutConstant note above); anything else is unevaluated, not survived - see below.

Not a behavior bug — the code is correct — but worth closing given how deliberately this PR has been about exactly this failure mode elsewhere.

Overall

Across all twelve reviewed commits (8e7ed7b3c5c8083c), the three substantive issues raised during review (§4.2 history-file contradiction, the pr-local-fast-feedback.yml count/attribution miscount, and the survivor/unevaluated conflation) have all been fixed and independently verified. This one leftover stale comment is the only open item.

Two things this PR left mis-stated.

The inflight entry described the work as "retargeted but unmeasured", which
buries the operational fact: automatic mutation testing is now deliberately
NARROW. The only thing that runs by itself is one per-PR job over changed
classes in offsets. alone; the sweep is dispatch-only. On most PRs mutation
testing therefore does nothing, on purpose - and a reduction in coverage is
exactly the kind of thing that must be tracked rather than left to be
rediscovered. The entry now leads with that, and lists re-widening in order:
measure the sweep, give it a trigger, widen the package list.

The "why not nightly" reasoning was also stale. "Scheduling a job that has
never finished only moves the waste to a quieter hour" is sound about
internal.*, where mutants hang by construction - but it does not survive the
retarget, and I had been repeating it as though it did. With offsets. the sweep
is plausibly minutes. What is actually missing is one measurement, not a
structural objection, and the workflow header and plan doc now say so.

When it does get a trigger, prefer `push: branches: [master]` to a cron: a
mutation score changes only when the code changes, so a nightly recomputes an
identical answer whenever master did not move, and attributes a failure to a
date instead of to a merge.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@claude

claude Bot commented Aug 4, 2026

Copy link
Copy Markdown

Claude finished @astubbs's task in 1m 39s —— View job


Reviewing PR #111 (latest push)

  • Gather context (PR body, diff, prior review history)
  • Check what changed since my last review (c5c8083ccb444db5)
  • Verify new claims against repo state
  • Post review feedback

Summary

One new commit, cb444db5, docs-only (mutation-full-sweep.yml header comment, docs/inflight.md, docs/plans/2026-08-03-002-mutation-testing-plan.md §4.1). It corrects a piece of reasoning the PR had been carrying since early on: "never schedule this, it never finishes" was true of internal.* but doesn't automatically transfer to offsets.*, where the sweep is plausibly minutes. I verified the mechanical claims:

  • bin/ci-mutation-test.sh:104PIT_DECIDABLE_PACKAGES still defaults to ^io\.confluent\.parallelconsumer\.offsets\., consistent with "on most PRs mutation testing does nothing, by design."
  • .github/workflows/mutation-full-sweep.yml:51-56 — still workflow_dispatch: only, no schedule: trigger anywhere in the file (grepped) — matches "deliberately NOT wired until the runtime is known."
  • git diff origin/master...HEAD --stat totals exactly 918 insertions(+), 92 deletions(-) across 15 files, matching the PR body.
  • The push: branches: [master]-over-cron reasoning (a score only changes when code does, so a nightly on unchanged code just recomputes the same answer and blames a date instead of a merge) is sound and is stated identically in all three touched files.

New finding: the correction didn't reach the doc's own summary table

docs/plans/2026-08-03-002-mutation-testing-plan.md:20, in the "Done in #111" table right at the top of the doc, still reads:

Full sweep off PRs | Deleted from the highcpu matrix. Now manual-only in mutation-full-sweep.yml - not nightly: scheduling a job that has never once completed only moves the waste to a quieter hour. It earns a schedule: the day a run finishes.

That's the exact pre-correction reasoning §4.1 (line ~251) and docs/inflight.md were just changed away from in this same commit — stated as a flat, unqualified rule rather than "true for internal.*, not for offsets.*, which is why the real blocker is now just running the sweep once." I checked: this line is untouched by cb444db5 (git show c5c8083c:... shows identical text). A reader who only reads the top summary table — which is what a status table is for — walks away with the stale blanket claim the commit's own message says it was correcting.

Given this PR's own recurring theme (a claim fixed in one place and not swept everywhere — the §4.2 history-file contradiction, the pr-local-fast-feedback.yml count miscount, the survivor/unevaluated conflation), this is the same failure mode landing in the correction commit itself. Suggested fix, consistent with the corrected §4.1 wording:

| Full sweep off PRs | Deleted from the highcpu matrix. Now manual-only in `mutation-full-sweep.yml`. Not yet on a trigger - not because it can't be (that reasoning was `internal.*`-specific and doesn't survive the retarget to `offsets.*`), but because nothing has measured its runtime yet. |

Also still open: the doc's own Status line (flagged in an earlier review pass, still unaddressed)

Line 3-4, unchanged since it was first written and not touched by any of the last ~10 commits:

Status: the cheap half is DONE (shipped in PR #111, marked inline below); the substantive retarget is still parked and unscheduled.

But line 24 of the same table, three lines below, says the retarget itself is Done in #111. The thing that's actually still parked is the measurement (running the sweep), not the retarget (the config change), which is applied. This is the first thing a reader of the doc sees, and it currently says the opposite of what the table two lines later says. I flagged this exact line in an earlier review pass (after commit bc92a322); it doesn't appear to have been revisited since.

Everything else

No other changes since my last review. All previously-verified claims (lane consolidation, skipFailingTests/crossModule, job-summary logic, survivor/unevaluated split, offsets.* retarget itself) remain accurate against the current tree.

@astubbs

astubbs commented Aug 4, 2026

Copy link
Copy Markdown
Owner Author

Review response: both findings implemented, plus two you didn't catch

Both valid. Neither declined.

1. Summary table carried the pre-correction reasoning - FIXED

You're right that this is the PR's own recurring failure mode landing inside the correction commit. Row rewritten close to your suggested wording:

Not yet on a trigger - not because it cannot be (that reasoning was internal.*-specific and does not survive the retarget), but because nothing has measured its runtime.

2. The Status line contradicted its own table - FIXED

Worse than you flagged: you noted it in an earlier pass and it survived ~10 commits. It now reads:

Status: the plumbing and the retarget are DONE. What is still parked is the measurement: no sweep has completed under the new target, so no mutation score should be quoted for this project yet.

While in there I found two more staleness bugs in the same block that no review caught: the intro still said "Two things ... the original analysis had wrong" when §4.2 made it three, and the table was missing two shipped items (the per-PR decidable allowlist, and the survivor list). Both fixed.

3. and 4. Two more instances, found by sweeping instead of point-fixing

Your framing - a claim fixed in one place and not swept everywhere - is the actual defect, so this time I grepped every file for the claim rather than patching the line you pointed at. Two more:

  • pr-highcpu-fast-feedback.yml still described "the full internal. sweep ... is manual-only in mutation-full-sweep.yml"*. The manual sweep is no longer internal.*.
  • The PR description itself was the worst instance. It didn't merely carry the stale reasoning, it extended it: "the same reasoning applies to the retargeted sweep below, which is why that one is not scheduled either." That is precisely the inference the commit disproved. Rewritten.

The remaining "never completed" mentions are deliberate: they are historical statements about internal.*, which are still true.

On the pattern

Four of your findings across this PR have been the same shape - §4.2 vs the ledger, the pr-local miscount, the survivor/unevaluated conflation, and now this. In each case I fixed the instance I was shown and did not sweep. The sweep above is the first time I checked all of them at once, and it found two more, which is the argument for doing it that way by default.

…as pointed out

Review found the "not nightly because it never finishes" reasoning still in the
plan doc's own summary table - the exact claim the previous commit corrected in
§4.1 and the ledger. A reader who reads only the status table, which is what a
status table is for, would take away the version that commit says it was
fixing.

It also re-flagged the doc's Status line, which claimed "the substantive
retarget is still parked and unscheduled" while the table 20 lines below marked
that same retarget Done. It had been flagged an earlier pass and survived ~10
commits. What is parked is the MEASUREMENT, not the retarget.

Both fixed - and this time by grepping every file for the claim rather than
patching the line that was pointed at, which found two more instances no review
caught:

- pr-highcpu-fast-feedback.yml still called the manual sweep "the full
  internal.* sweep"; it has been offsets.* since the retarget.
- the PR description was the worst one. It did not merely repeat the stale
  reasoning, it EXTENDED it: "the same reasoning applies to the retargeted
  sweep below, which is why that one is not scheduled either" - exactly the
  inference the retarget disproves.

Two more staleness bugs in the same header block, unflagged by anyone: the
intro still said "Two things ... the original analysis had wrong" when §4.2
made it three, and the table was missing two shipped items (the per-PR
decidable allowlist, and the survivor list).

Remaining "never completed" mentions are deliberate: they are historical
statements about internal.*, which are still true.

The pattern is the point. Four review findings on this PR have had the same
shape - a claim fixed in one place and not swept - and each time I fixed the
instance shown. Sweeping first is cheaper than being told four times.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@claude

claude Bot commented Aug 4, 2026

Copy link
Copy Markdown

Claude finished @astubbs's task in 1m 22s —— View job


Reviewing PR #111 (latest push)

  • Gather context (PR body, diff, prior review history)
  • Check what changed since my last review (cb444db54cffd300)
  • Verify the four fixes astubbs described against repo state
  • Post review feedback

Summary

One new commit, 4cffd300, fixing the two issues I flagged in my previous review plus two more the author found by sweeping instead of point-fixing. I verified all four independently:

  1. Summary table row (docs/plans/...md:24) — now reads "Not yet on a trigger - not because it cannot be (that reasoning was internal.*-specific and does not survive the retarget), but because nothing has measured its runtime." Matches the corrected §4.1 reasoning. Fixed.

  2. Status line (docs/plans/...md:3-5) — now reads "the plumbing and the retarget are DONE... What is still parked is the measurement." No longer contradicts the table below it. Fixed.

  3. pr-highcpu-fast-feedback.yml:16-19 (a file I hadn't previously flagged, found by the author's own sweep) — the header comment no longer calls the manual sweep "the full internal.* sweep"; it now says "the full sweep moved to mutation-full-sweep.yml (manual, and retargeted off internal.* - see there)". Fixed.

  4. PR description — the current body's §4.1 text ("It is not left unscheduled because a sweep can never be scheduled - that reasoning was specific to internal.*...") already reflects the correction, consistent with the author's stated rewrite.

I also independently swept the repo for every remaining "never completed" / "internal.* sweep" mention (maven.yml:118-119, mutation-full-sweep.yml:55, pr-local-fast-feedback.yml:68, bin/ci-mutation-test.sh:49,62, docs/inflight.md:483,503,516, docs/plans/...md:163-166,251) to check nothing was missed. All remaining occurrences are correctly historical/scoped — factual statements that the internal.* sweep specifically never completed, not renewed blanket claims about scheduling being impossible in general. No new staleness found.

Two smaller items from the same commit also check out: the "Two things... the original analysis had wrong" intro is now "Three things... (§2, §3.4, §4.2)" — correctly counting the history-file correction alongside the two pre-existing ones — and the summary table's "Retargeted to offsets.*" and "A summary that explains itself" rows now mention the decidable-package intersection and the survivor list respectively, closing the gap where those two shipped items weren't reflected in the table.

Overall

Across all thirteen reviewed commits (8e7ed7b34cffd300), I have no unresolved findings. Four substantive issues were raised over the course of review (§4.2 history-file contradiction, pr-local-fast-feedback.yml count/attribution miscount, survivor/unevaluated conflation, and this stale-reasoning sweep) — all fixed and independently verified, the last one confirmed via an independent grep rather than re-checking only the spots pointed at. This PR is in good shape to merge.

astubbs added a commit that referenced this pull request Aug 4, 2026
…s stop colliding (#112)

The ledger had reached 677 lines and become a record of finished work. Entries
told to "delete when #98 merges" outlived three merges; the rebalance-commit fix
was still filed as awaiting PR after landing as #100; a static-state flake was
still listed as deliberately-unfixed after #101 fixed it at source. Meanwhile
#80, carrying the drain-zombie fix and the largest thing actually in flight,
appeared only as a footnote about quarantine ownership. The file's own scope rule
says entries vanish when work lands; it had stopped being applied.

Every surviving claim is now checked against GitHub, git and the code. Obsolete
entries are deleted rather than annotated: the jscpd cap is above baseline, no
workflow has path filters so the docs-only inconsistency cannot happen, the
ManagedPCInstance header carries its Modifications line, the CommitFailedException
follow-up shipped in #108, and the stacked-PR gap is closed by a new all-branches
ruleset. Upstream references now follow the convention the changelog already uses:
fork numbering reaches #111, so every bare reference at or above #162 was silently
upstream and read as ours.

With the content correct, the file became a directory. It appeared in 26 of the
last 30 master commits, so unrelated PRs conflicted on it constantly - not because
they disagreed, but because their notes were adjacent, and the merge that resolves
such a conflict silently drops one side (it happened between #108 and #110). Each
item is now its own file, named <category>-<slug>.md; two PRs recording unrelated
work touch disjoint files and cannot conflict, and finishing work is `git rm`,
which never conflicts with an edit elsewhere. The prefix is the structure - `ls
docs/inflight/` shows the shape of what is open without reading anything. There is
deliberately no committed index: it would be edited by every PR, which is the
problem the directory solves, and docs/TODO_INDEX.md is the cautionary case.

This was parked on docs/inflight-as-directory with "migrating ~600 lines of
existing entries" named as the reason not to do it. The audit is what made it
cheap. docs/refactoring.md stays a single file - 2 of the last 30 commits touched
it, so it has none of this problem.

The manifest had drifted the same way, which matters more, because it is the
declared source of truth that a future session trusts instead of re-deriving. Five
entries disagreed with reality: bug-857 recorded no fork PR while #29 was open,
#100 merged and #80 in review; fix-909 recorded no PR though #31 is open; bug-912
was in-progress when the schema's word for pushed-but-unPR'd is ready. Nothing
catches this - upstream-map.py validate only checks the schema and
upstream-sweep.sh only watches upstream, so "prs: []" beside an open PR passes
every check we have. Hence the AGENTS.md rule to update it at every lifecycle
transition, not only when starting.

Four rules now live in docs/inflight/AGENTS.md so they are inherited rather than
rediscovered: delete an entry in the PR that resolves it and never leave a "delete
when #NN merges" marker on master; never record what gh or git can answer, which
is why the open-PR table is gone; known code defects belong here even when an
issue exists, because an agent scans this directory and will not read the tracker;
and new guidance about how these notes are written goes into that file too.

Four deferred code items moved to docs/refactoring.md, where deferred work lives:
the SpotBugs thread-visibility findings, the produce-lock double release surfaced
by #110, the commitAndWait message that misstates its own wait, and jacoco's
single exec file under forked surefire.

Also shares the agent-tooling gitignore rules that until now existed only in one
checkout's .git/info/exclude, and deletes an empty duplicate-code-cross-check
clone - a git init that never fetched - rather than ignoring it.

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Conflict: #112 split docs/inflight.md into docs/inflight/, one file per item,
because every PR edited the single file. This branch had rewritten that file,
so it conflicted structurally rather than textually.

Resolved master's way. The mutation note is now docs/inflight/ci-mutation-testing.md,
following the new <category>-<slug> convention and the directory's rules -
open items only, no FIXED/DONE narrative, no committed index.

Also swept master's own notes for claims this PR invalidates, rather than only
resolving my side of the conflict. ci-disabled-jobs-and-runner-load.md said
"the highcpu lane runs six suites per branch on one box, including mutation
sweeps ... consider moving mutation off-box. Mutation strategy is being
reconsidered wholesale in #111" - #111 is this branch, and it did exactly that:
the lane is down to two suites, both mutation entries are off-box, and
Unit/Integration went with them. Left the runner-lost-communication symptom
noted but marked for re-checking, since its stated cause is largely gone.

Two references in the plan doc pointed at ledger content that the #112 audit
dropped (the arcmutate shelved plan). Rather than leave a dangling pointer, the
plan doc now says it is itself the record of that.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@claude

claude Bot commented Aug 4, 2026

Copy link
Copy Markdown

Claude finished @astubbs's task in 2m 7s —— View job


Reviewing PR #111 (latest push)

  • Gather context (PR body, diff, prior review history)
  • Check what changed since my last review (4cffd300eef80a6a)
  • Verify new claims against repo state
  • Post review feedback

Summary

No new original commits from this branch since my last review — git log 4cffd300..HEAD shows only 0de96fcb (master's PR #112, which split docs/inflight.md into docs/inflight/*.md) and eef80a6a, the merge of master into this branch. bin/ci-mutation-test.sh, pom.xml, all workflow files, and the test class are all byte-identical to what I already reviewed at 4cffd300.

The merge itself required manual conflict resolution, though, since this branch had rewritten docs/inflight.md and master deleted it in favour of the split. I reviewed that resolution (docs/inflight/ci-mutation-testing.md, the edit to docs/inflight/ci-disabled-jobs-and-runner-load.md, and the small follow-up edit to the plan doc) as new content, since it was authored specifically for this PR rather than inherited verbatim from either side.

Most of it holds up:

  • docs/inflight/ci-mutation-testing.md's "one PR-scoped lane + dispatch-only sweep, offsets. alone" description matches bin/ci-mutation-test.sh and maven.yml exactly.
  • docs/inflight/ci-disabled-jobs-and-runner-load.md's "cut from six suites to two (Performance, Chaos)" is verified directly against pr-highcpu-fast-feedback.yml's current matrix (suite-name: "Performance" / "Chaos Pain Suite" are the only two entries).
  • The plan doc's docs/inflight.md → "the in-flight ledger" wording update, and its "the longer shelved plan did not survive the ledger audit in docs: audit the in-flight ledger against reality, then split it so PRs stop colliding #112, so this section is now the record of it" claim, are both accurate — docs/inflight/ci-mutation-testing.md genuinely doesn't carry the fuller arcmutate write-up anymore, and the plan doc's §4.2 still has it.

New finding: the merge's own conflict resolution introduces a misleading cross-reference

docs/inflight/ci-mutation-testing.md:26-29:

withHistory is blocked on an arcmutate licence, not a flag - re-verified 2026-08-04 that pitest 1.25.8 errors with "no history plugin has been installed". See parked-quarantine-lane-foss.md for the same OSS-licence question in another form.

parked-quarantine-lane-foss.md isn't about a licence question at all — I read it directly:

Parked: extract the quarantine lane as its own FOSS project

The @Quarantined lane ... is generic; nothing in it is parallel-consumer-specific. The differentiator: the closed loop is enforced in CI ... Check for prior art first. Adjacent, mostly commercial: Trunk.io flaky-test quarantining, BuildPulse, Datadog Test Optimization, Develocity flaky management...

That's a proposal to spin the quarantine-lane code off into its own open-source project someday — nothing about needing a paid licence, free-for-OSS tiers, or a licence key at the repo root. I grepped the whole docs/inflight/ tree for "licence" and "OSS" to check I wasn't missing the actual intended target: ci-mutation-testing.md is the only file that mentions either. There's no other file discussing an OSS-licence question this could have meant.

The two "OSS" senses got conflated — arcmutate's free-for-open-source-projects licensing tier (a commercial-tool question) versus extracting quarantine-lane code as a new FOSS project (a totally different, "should this become its own thing" question). They share the acronym and nothing else. This is exactly the failure mode this PR spent itself hunting elsewhere (a claim/pointer that "reads as authoritative because of where it sits" and sends a future reader looking in the wrong place) — it just landed in the merge commit's conflict resolution instead of the PR's own commits, so none of the prior review passes could have caught it.

Fix is a one-line removal or correction — either drop the "See ... for the same OSS-licence question in another form" sentence entirely (the arcmutate item is fully self-contained in the four lines above it), or point it at wherever the actual "is licence-gated OSS software worth adopting" precedent lives, if one exists.

Overall

No other issues found in the merge's conflict resolution or the content it pulled in from master. All previously-fixed issues (the §4.2 history-file contradiction, the pr-local-fast-feedback.yml count/attribution miscount, the survivor/unevaluated conflation, and the stale-reasoning sweep) remain intact after the merge.

Branch: docs/mutation-testing-plan ·

#113 abolished per-PR changelog entries: CHANGELOG.adoc no longer has an
Unreleased section, and each release section is generated from the commit log
at release time. So this PR's changelog entry is not merely conflicted, it is
now forbidden - resolved by taking master's file, which drops it. README
regenerated to match; both are now byte-identical to master.

Two things the merge would otherwise have carried through silently.

AGENTS.md: this branch had added "an entry is terse ... entries here run ~90
words ... a correction should replace text, not accrete onto it" to the
Changelog section. #113 rewrote that section around a much stricter rule - one
sentence, about 25 words, assembled at release time - so the surviving
paragraph contradicted it (nearly 4x the word budget) and assumed a per-PR
editing workflow that no longer exists. Removed; #113 expresses the same intent
better. AGENTS.md now matches master exactly.

docs/inflight/ci-mutation-testing.md: the previous merge's conflict resolution
pointed the arcmutate item at parked-quarantine-lane-foss.md "for the same
OSS-licence question in another form". Raised in review, and correct - I
checked the file rather than take it on trust. That note is about extracting
the quarantine lane as its own FOSS *project*; it says nothing about licence
gating. Two unrelated senses of "OSS" conflated by the acronym. The pointer is
removed and the arcmutate item now carries the constraint inline, since it was
self-contained anyway.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@astubbs

astubbs commented Aug 4, 2026

Copy link
Copy Markdown
Owner Author

Review response: the bogus OSS cross-reference - fixed, plus two the merge would have carried silently

Correct, and I checked the file rather than take it on trust. parked-quarantine-lane-foss.md is about extracting the quarantine lane as its own FOSS project; it says nothing about licence gating. I had conflated arcmutate's free-for-open-source licensing tier with should this code become its own open-source thing - two unrelated questions sharing an acronym. Pointer removed; the arcmutate item now carries its constraint inline, since it was self-contained anyway.

Your framing is the part worth keeping: it landed in a merge commit's conflict resolution, which no prior pass could have seen. Conflict resolutions are new authored content and deserve the same scrutiny as a normal diff - I'd been treating them as mechanical.

Two more from this merge, found by applying that lesson

Master moved again (#113) while this was open, and the auto-merge would have carried both through silently:

  1. A now-forbidden changelog entry. docs(changelog): compact it for readers, and generate future releases from the commit log #113 abolished per-PR changelog entries - no Unreleased section, release notes generated from the commit log at release time. This PR's entry was not merely conflicted but no longer allowed. Resolved by taking master's file; CHANGELOG.adoc and README.adoc are now byte-identical to master and this PR touches neither. The changelog-ref: opt-out and the checklist line are gone from the body too, since docs(changelog): compact it for readers, and generate future releases from the commit log #113 removed both from the template.

  2. A rule of mine that survived into a section rewritten to contradict it. This branch had added "an entry is terse ... entries here run ~90 words ... a correction should replace text, not accrete onto it" to AGENTS.md's Changelog section. docs(changelog): compact it for readers, and generate future releases from the commit log #113 rewrote that section around one sentence, about 25 words, assembled at release time - so the surviving paragraph carried nearly 4x the word budget and assumed a per-PR editing workflow that no longer exists. Removed; docs(changelog): compact it for readers, and generate future releases from the commit log #113 states the same intent better. AGENTS.md now matches master exactly.

Neither was a conflict git could see - both were textual survivors that became false because the surrounding policy changed underneath them.

@claude

claude Bot commented Aug 4, 2026

Copy link
Copy Markdown

Claude finished @astubbs's task in 1m 33s —— View job


Reviewing PR #111 (latest push)

  • Gather context (PR body, diff, prior review history)
  • Check what changed since my last review (eef80a6a2700a1db)
  • Verify new claims against repo state
  • Post review feedback

Summary

No new original commits from this branch — git log eef80a6a..HEAD shows only e3b1601e (master's #113, changelog compaction) and 2700a1db, the merge of master into this branch that resolves the resulting conflicts. bin/ci-mutation-test.sh, pom.xml, all workflow files, and the test class remain byte-identical to what I already reviewed at 4cffd300.

I verified the merge's conflict resolution — the three fixes astubbs described in the review-response comment — directly against the tree rather than taking the commit message at its word:

  1. Forbidden changelog entry removed. git diff origin/master -- CHANGELOG.adoc and git diff origin/master -- README.adoc are both empty — both files are genuinely byte-identical to master, confirming this PR's own changelog entry (which docs(changelog): compact it for readers, and generate future releases from the commit log #113 made structurally impossible — no more Unreleased section) was dropped rather than merged in a broken state.

  2. AGENTS.md reconciled with docs(changelog): compact it for readers, and generate future releases from the commit log #113's rewritten Changelog section. git diff origin/master -- AGENTS.md is also empty. I read the surviving section (AGENTS.md:185-200): it states docs(changelog): compact it for readers, and generate future releases from the commit log #113's "generated at release time from the commit log" model with no remnant of this branch's old ~90-word-entry rule, which would have contradicted the new one-sentence-per-release-note model.

  3. The bogus cross-reference is actually gone, not just reworded. I read docs/inflight/ci-mutation-testing.md directly: the arcmutate item (lines 26-29) now states the licence constraint inline ("arcmutate is free for open-source projects, but claiming that needs maintainer signup and a licence file at the repo root...") with no pointer to parked-quarantine-lane-foss.md. Grepped the whole tree for parked-quarantine-lane-foss and OSS-licence question — zero remaining hits, so nothing was left dangling.

git diff origin/master...HEAD --stat totals exactly 923 insertions(+), 92 deletions(-) across 13 files, matching the PR body's stated Additions/Deletions precisely.

Overall

Across all fourteen reviewed commits/merges (8e7ed7b32700a1db), I have no unresolved findings. Every substantive issue raised over the course of review — the §4.2 history-file contradiction, the pr-local-fast-feedback.yml count/attribution miscount, the survivor/unevaluated conflation, the stale-reasoning sweep, and this merge's bogus cross-reference — was fixed and independently re-verified against the live repo, not just against the commit message describing the fix. This PR is in good shape to merge.

Branch: docs/mutation-testing-plan ·

@astubbs
astubbs merged commit 5899150 into master Aug 4, 2026
25 of 27 checks passed
@astubbs
astubbs deleted the docs/mutation-testing-plan branch August 4, 2026 21:48
astubbs added a commit that referenced this pull request Aug 5, 2026
The first sweep completed, but three places still told a future reader the
runtime was unknown - including the mutation-full-sweep.yml header block, which
is the first thing anyone reads before dispatching, and which was headed
UNMEASURED.

- docs/inflight/ci-mutation-testing.md: one bullet opened "now unblocked, at a
  known 22 minutes per run" and closed "Deliberately NOT wired until the runtime
  is known". It still is not wired, so that fact stays; the stale reason goes.
- docs/plans/2026-08-03-002-mutation-testing-plan.md: "Do not quote a mutation
  score for this project until one has" - correct when written, now the opposite
  of the truth. Points at the baseline instead.
- .github/workflows/mutation-full-sweep.yml: comments only - no trigger, runner,
  permission or step change. Also corrects the coverage pass from an estimated
  ~332s to the measured 311s, and drops the "until this merges, dispatch fails"
  note that #111 made obsolete.

Also fixes the convention that made this PR's own title collide. AGENTS.md and
.gitmessage both taught a trailing "(#NNN)" issue ref, but GitHub appends the PR
number to exactly that slot on squash-merge, so a title ending "(#41)" merges as
"(#41) (#123)" - two bare numbers with nothing to tell them apart. Both now put
a fork issue at the front, as this commit does, matching Apache Kafka and our
own pre-fork confluentincGH-725 history. Upstream refs stay inline and worded.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
astubbs added a commit that referenced this pull request Aug 5, 2026
The first sweep completed, but three places still told a future reader the
runtime was unknown - including the mutation-full-sweep.yml header block, which
is the first thing anyone reads before dispatching, and which was headed
UNMEASURED.

- docs/inflight/ci-mutation-testing.md: one bullet opened "now unblocked, at a
  known 22 minutes per run" and closed "Deliberately NOT wired until the runtime
  is known". It still is not wired, so that fact stays; the stale reason goes.
- docs/plans/2026-08-03-002-mutation-testing-plan.md: "Do not quote a mutation
  score for this project until one has" - correct when written, now the opposite
  of the truth. Points at the baseline instead.
- .github/workflows/mutation-full-sweep.yml: comments only - no trigger, runner,
  permission or step change. Also corrects the coverage pass from an estimated
  ~332s to the measured 311s, and drops the "until this merges, dispatch fails"
  note that #111 made obsolete.

Also fixes the convention that made this PR's own title collide. AGENTS.md and
.gitmessage both taught a trailing "(#NNN)" issue ref, but GitHub appends the PR
number to exactly that slot on squash-merge, so a title ending "(#41)" merges as
"(#41) (#123)" - two bare numbers with nothing to tell them apart.

Issue refs now go at the FRONT, as this commit's subject does, matching Apache
Kafka and our own pre-fork confluentincGH-725 history. That holds for upstream refs too:
they just need the word, as in "fix(core) upstream confluentinc#909: subject", because a
bare "confluentinc#909" autolinks to FORK issue 909 rather than the upstream one meant.
Where a fork mirror exists, prefer its number (#119 mirrors upstream confluentinc#857) and
leave the upstream number to the Upstream-Issue trailer, which is what tooling
reads.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
astubbs added a commit that referenced this pull request Aug 5, 2026
#123)

The offsets.* sweep completes in 21m55s and scores 83% (185 mutants generated,
153 killed, 19 with no coverage, 92% test strength, 1392 tests at 7.52 per
mutation). The internal.* sweep it replaced never finished, in 42+ minutes on
CI or 83+ locally, so this is the first mutation number this project has ever
had. Run #1 of mutation-full-sweep, against master at 5899150.

Recorded in the repo because nothing else keeps it. The PIT report is a 14-day
artifact and the statistics exist only in a job log - which ages out, and which
a re-run silently replaces, as I proved earlier this week by re-running a job
whose logs I had not saved. A baseline nobody can find is not a baseline.

TWO DECISIONS THE NUMBER SETTLES

- The sweep is schedulable. `push: branches: [master]` was left unwired
  pending a runtime, and 22 minutes on the highcpu box is affordable. It is
  still unwired, but that is now a cost decision rather than a blocked one.
- Narrowing target-tests is NOT worth doing. Coverage is 311s of 1315s, about
  24%, so the accuracy it costs - mutants killed outside offsets.* reported as
  no-coverage - buys little. That had been carried as a live option since #111.

It also makes the marginal cost of widening PIT_DECIDABLE_PACKAGES explicit:
the coverage pass is paid whatever the target, so adding state. costs only its
own mutants.

THREE PLACES STILL SAID THE RUNTIME WAS UNKNOWN

- docs/inflight/ci-mutation-testing.md: one bullet opened "now unblocked, at a
  known 22 minutes per run" and closed "Deliberately NOT wired until the
  runtime is known". It still is not wired, so that fact stays; the stale
  reason goes.
- docs/plans/2026-08-03-002-mutation-testing-plan.md: "Do not quote a mutation
  score for this project until one has" - correct when written, now the
  opposite of the truth. Points at the baseline instead.
- .github/workflows/mutation-full-sweep.yml: the header block, which is the
  first thing anyone reads before dispatching, was headed UNMEASURED. Comments
  only - no trigger, runner, permission or step change. Also corrects the
  coverage pass from an estimated ~332s to the measured 311s, and drops a
  "until this merges, dispatch fails" note that #111 made obsolete.

ISSUE REFS MOVE TO THE FRONT OF THE SUBJECT

Found while citing #41 in this PR's own title. AGENTS.md and .gitmessage both
taught a trailing "(#NNN)" issue ref, but GitHub appends the PR number to
exactly that slot on squash-merge, so a title ending "(#41)" merges as
"(#41) (#123)" - two bare numbers with nothing to tell them apart.

Issue refs now go at the FRONT, as this subject does, matching Apache Kafka
(KAFKA-14561: ... (#13114)) and our own pre-fork history (confluentincGH-725: ... (confluentinc#727)).
That holds for upstream refs too; they just need the word, as in "fix(core)
upstream confluentinc#909: subject", because a bare "confluentinc#909" autolinks to FORK issue 909
rather than the upstream one meant. Where a fork mirror exists, prefer its
number (#119 mirrors upstream confluentinc#857) and leave the upstream number to the
Upstream-Issue trailer, which is what tooling reads. .gitmessage's worked
example was itself breaking the rule it documented; it now demonstrates it.

Tracks #41, which is reopened rather than closed: the baseline answers that
issue's question - PIT does complete on the self-hosted runner, in 22 minutes -
but the re-widening work behind it continues there.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
astubbs added a commit that referenced this pull request Aug 8, 2026
…tops flagging colours

The gate is purely textual, so #111 and confluentinc#555 in a stylesheet read as unqualified
issue references. Expanding every 3-digit shorthand to its 6-digit form is
visually identical CSS and removes the whole class rather than today's instances.

Same reason the HTML escaper now emits &#x27; instead of the decimal &#39; - the
hex form is what OWASP recommends anyway, so this is a small improvement rather
than only an appeasement.

Not using the issue-refs: N/A escape hatch: it exists for references that
genuinely need no qualifier, and silencing a gate is worse than removing what
trips it when removing it costs nothing.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant