Skip to content

fix(core): revoke sweep NPE when a shard is removed against its read - poller death under KEY ordering - #345

Merged
astubbs merged 16 commits into
masterfrom
fix/revoke-sweep-npe-on-racing-shard-removal
Aug 26, 2026
Merged

astubbs merged 16 commits into
masterfrom
fix/revoke-sweep-npe-on-racing-shard-removal

Conversation

@astubbs

@astubbs astubbs commented Aug 24, 2026 •

Copy link
Copy Markdown
Owner

Fixes a reproduced race: a shard removed between the revoke sweep's two map reads threw NullPointerException out of the ConsumerRebalanceListener into consumer.poll - the poller-death family.

The defect

ShardManager.removeWorkFromShardFor did containsKey then get on processingShards and dereferenced unconditionally. Under KEY ordering the control thread's onSuccess → removeShardIfEmpty removes empty shards; landing between the two reads made get return null.

Which guard owns which null - corrected at merge prep, because this PR previously said it wrong. The body and the commits claimed the window sat inside the guard added for confluentinc#757. git log -S says otherwise: the containsKey test dates from 7e2607560 (2022-01-15, upstream batching work), two years before 757 was filed. What 757 actually added is upstream PR 758's Objects.nonNull(removedWC) check one line lower, against retryQueue.remove(null), with ShardManagerTest.testAssignedQuickRevokeNPE for it - and that test keeps a shard in the map throughout, so it never reaches the already-removed-shard branch. This is the third null on one revoke path: the same symptom family as confluentinc#757, a different null.

Candidate 2 of the torn-read family (docs/inflight/bug-torn-read-family.md, carried on #344's branch): multiple reads of moving shared state combined as one snapshot - same class as confluentinc#894, in a different structure.

The fix

The single-read getShard(key) Optional idiom every other access in the file already uses. Both absent cases - removed-before and removed-against-the-read - now fall into the same guarded, trace-logged branch. Operating on the reference after it left the map is benign: the shard is detached, and removeShardIfEmpty re-reads via the same idiom.

Evidence

  • ShardManagerRevokeSweepNpeTest, cherry-picked from the hunt branch test/torn-read-candidates-reproduction where it was committed expected-red (deterministic 4/4 against unfixed master): fires the real production shard removal between the two reads via a racing map seam.
  • Controls, independently re-verified at dispatch review: red unfixed with the exact predicted NPE; the same removal landing before the sweep passes via the 757 guard (fixture innocence); green fixed; fix reverted uncommitted → red again (also proving the rebuilt class reached the run); seam-fired guard goes red when the arm is deleted.
  • One deliberate test change, stated rather than hidden: the seam originally fired from containsKey - a call the fix deletes - so it was generalised to fire on the first read of the armed key, with the red side re-verified on unfixed code before the fix was applied. The verbatim cherry-pick is preserved as its own commit for provenance.
  • Full all-modules unit suite green.

Defect-class sweep

Whole main tree, untruncated. No other containsKey-then-get-then-deref instance. Re-swept at merge prep, which turned up two live findings the first pass missed - recorded, not fixed here:

  • ShardManager.removeShardIfEmpty is check-then-remove across both threads. getShard(key) → isEmpty() → processingShards.remove(key), reached from the control thread via onSuccess/onFailure and from the broker-poll thread via the revoke sweep. addWorkContainer can computeIfAbsent onto the shard between the isEmpty() and the remove, so the poll thread removes a shard that just gained work - silently orphaned, KEY ordering only. In no ledger; needs its own reproduction.
  • ProcessingShard.addWorkContainer is get-then-put on the same shape, unreachable today only because registerWork is control-thread-only. Lincheck produced a counterexample over it - see docs/inflight/test-lincheck-lane-open-items.md.

Checked and dismissed, with where I looked: PartitionStateManager.onPartitionsAssigned - same shape, but the load-bearing fact is that nothing ever removes from partitionStates (revoke puts a RemovedPartitionState), so the get cannot be null; the counter HashMaps (check-then-put, rebalance path, a duplicate registration at worst); OffsetMapCodecManager, PartitionState.polledOffsets and ProcessingShard.slowWork (all method-local collections, not shared); RetryQueue.contains and PartitionState.isRecordPreviouslyCompleted (one call, no paired get).

Checklist

  • Changelog entry added - N/A: AGENTS.md forbids per-PR changelog entries; the commit bodies carry what the release-time generator reads.
  • Docs updated - docs/inflight/test-lincheck-lane-open-items.md (the inversion contract, reconciled with fix(core): staleness checkpoint 3 checks and acts on one state lookup, closing a stall and a wrong-commit route #346 so both branches carry one identical section), docs/inflight/static-spotbugs-rule-registry.md and static-infer-findings.md and static-archunit-main-code-rules.md (six sites described this seam in the present tense; the rule now reports zero), docs/testing.md, config/spotbugs-exclude.xml. The family dossier on fix(core): the offset encoder read its range top after its snapshot, silently completing records (confluentinc#894 sibling) #344's branch flips this candidate's status when the branches reconcile.
  • Tests added/updated - ShardManagerRevokeSweepNpeTest, controls both directions.
  • Other instances of the same defect - swept, listed above.
  • User-facing feature documentation data added under docs/features/ - N/A: an internal crash fix with no user-facing surface, option or behaviour change.
  • Title & body reflect the final content of this PR - re-checked at merge prep after master b3f018048 was merged.
  • Ran ce-simplify and ce-code-review locally - N/A - asked for @codex review on the PR instead. Neither skill has been run on this branch.

Merge-prep additions

Master merged (no conflicts). Beyond the corrections above:

  • A pre-existing master bug, fixed here: bin/lincheck-test.sh pinned EXPECTED_LINCHECK_CLASSES=5 while six harnesses carry @Tag("lincheck") - so the whole lane has exited 1 on master since RetryQueueLincheckTest landed. Nothing invokes the lane, which is why nothing caught it.
  • ShardManagerLincheckTest did not invert as test(core): a Lincheck lane, calibrated by refinding four real races unaided #347 prescribed. Measured: with the fix in, Lincheck still reports a violation, and it contains no NullPointerException. Controlled both ways. The harness now asserts the NPE is gone - a real regression detector - and the residual is recorded in the reconciled Lincheck note.
  • The Chaos Pain Suite history on this PR, corrected — it went red twice for two different reasons, and the second one mattered. The early red was the CLASS2_STALL/LAG_STAGNATION 154s-against-150s signature on the shared highcpu-4 box, which 637ea3186 demoted to non-gating and 025d0b7ea removed the lane for. Chaos then passed on three later heads. It went red again on fa49683c0 with an entirely different signature: ChaosRevokeUnderWorkCooperativeIT, Timeout waiting for commit response PT10S, with the ambient probe stating outright that the poll thread was BLOCKED on a monitor — contention or a lock-ordering defect, not a slow broker — the commitCommand AtomicBoolean held by the instance's own pc-control thread, reached through onPartitionsRevoked. That is the AB-BA revoke-path cycle whose own write-up records its verification status as "Unproven" and says the fix "addresses a cycle the test cannot reach, while the block the test can reach is untouched". It is not this PR's — the diff touches no locking and no AbstractParallelEoSStreamProcessor line — and it is now recorded as the third capture in docs/inflight/bug-857-family.md, together with the fact that the very next head passed the same suite, which is that file's first direct intermittency datum. No test was loosened, retried or quarantined, and the suite was never re-run to get it green.
  • Two SpotBugs findings on the new test double, fixed rather than suppressed. EQ_DOESNT_OVERRIDE_EQUALS and SE_NO_SERIALVERSIONID on RacingShardMap. Each rule had exactly one instance tree-wide and both were this PR's, so a rule exclusion would have been targeted suppression dressed as policy, which spotbugs-exclude.xml's own header forbids. There is a genuine trilemma here — declare neither and EQ_DOESNT_OVERRIDE_EQUALS fires, declare both and COM_PARENT_DELEGATED_CALL fires, declare equals alone and HE_EQUALS_NO_HASHCODE fires — so the file is not finding-free: one HE_EQUALS_NO_HASHCODE remains, naming a contract violation that provably is not present, since the inherited hashCode is AbstractMap's and consistent with the delegated equals. The zero-finding route is a class-scoped Match, deliberately not taken unilaterally at merge prep.
  • NullPointerException on partitions revoked confluentinc/parallel-consumer#757 is a closed issue, so it needs no fork mirror and no upstream-map.yaml entry (the manifest maps upstream PRs).

Note for merge prep: the two original commits lack the session trailers - a repo hook blocked the amend and bypassing it was correctly refused; add them if re-cutting, or fold into the squash sign-off.

…containsKey and get kills the poller

Settles candidate 2 of the torn-read family dossier: REPRODUCED,
deterministically.

ShardManager.removeWorkFromShardFor checks containsKey, then calls get, and
dereferences the result unconditionally. Under KEY ordering the control
thread's onSuccess -> removeShardIfEmpty removes empty shards from the same
map, while the revoke sweep runs on the broker-poll thread inside
consumer.poll's rebalance callback - nothing serialises the two. A removal
landing between the two adjacent reads makes get return null and the next
line throw:

  NullPointerException: Cannot invoke ProcessingShard.remove(long)
  because "shard" is null

out of the ConsumerRebalanceListener into consumer.poll - the poller-death
family. The window sits inside the guard added for confluentinc#757
(testAssignedQuickRevokeNPE), which closed the shard-already-gone case but
left the gap between its own two reads. Every other access in the file
already uses the single-read getShard(key) Optional idiom.

The reproduction (ShardManagerRevokeSweepNpeTest):

- revokeSweepMustSurviveAShardRemovedBetweenItsTwoReads - RED on master, by
  design: the shard map is swapped for a double whose containsKey fires the
  interfering mutation at the seam, and the mutation is the real production
  path (sm.onSuccess on the shard's last container), not a hand-rolled map
  edit. 4/4 deterministic across runs; no load or repetition needed.
- sameShardRemovalBeforeTheSweepIsHandledGracefully - GREEN: the identical
  mutation fired before the sweep instead of between the reads takes the
  guarded already-removed branch. Same magnitude, different position, so the
  failure is the interleaving's, not the fixture's.

Seam guard (raceFired, set at firing time) proven by mutation: with the arm
deleted, the armed test goes red at the guard (1/1) instead of silently
green.

NOTE this branch carries reproductions, not fixes - the armed test is
EXPECTED RED here and becomes the regression test of the fix branch.

Prediction record: prediction 1 (NPE at ProcessingShard.remove) held exactly;
prediction 2 (early-fire control green) held; refutation prediction 3 was
falsified - no hidden serialisation exists between the sweep and onSuccess.

(cherry picked from commit 06e3c464b6c2c67ffe898ae89ca5b1b3b6b53dec)
…inst its read - single-read getShard replaces the torn containsKey/get pair

Closes candidate 2 of the torn-read family dossier
(docs/inflight/bug-torn-read-family.md, carried by the encoder-tear branch):
the last check-then-get pair in ShardManager, reproduced deterministically by
the previous commit's test.

What a user saw: under KEY ordering, a record's success landing on the
control thread while a rebalance revokes its partition could remove the
now-empty shard between removeWorkFromShardFor's containsKey and its get.
The sweep then dereferenced null and the NPE flew out of the
ConsumerRebalanceListener into consumer.poll on the broker-poll thread -
the poller-death family. Narrow window, hot path, fatal consequence. The
guard added for confluentinc#757 closed the shard-already-gone case but sat
on two reads of a moving map, leaving this gap between them.

The fix is the single-read getShard(key) Optional idiom every other access
in the file already uses: one read, and both absent cases - already removed
before the sweep (the 757 case) and removed against the sweep's read (this
one) - fall into the same guarded trace-logged branch. Operating on the
shard reference after it left the map is benign: removing work from a
detached shard mutates nothing shared, and removeShardIfEmpty re-reads
through the same Optional idiom.

Controls, all on this branch:
- reproduction test RED on the unfixed tree (NPE at ProcessingShard.remove,
  the dossier's exact frame), control arm green - 4/4 deterministic on the
  hunt branch, 2/2 red-side runs here
- fix applied: green; fix reverted (main code only, test untouched): red
  again 1/1 - the flip on a main-code-only change also proves the rebuilt
  class reached the run
- test's seam-fired guard proven by mutation: arm deleted, armed test red at
  the guard 1/1
- full default unit suite green across all modules

Also in this commit, inseparable from the fix's shape: the reproduction
test's racing double now fires on the first read of the armed key
(containsKey OR get) instead of only containsKey - the fix deletes the
containsKey call the original seam hung on, and without the generalisation
the seam-fired guard would go red on correct code. On the fixed code the
seam models the removal landing immediately after the single read, which the
sweep must (and now does) tolerate. Red side re-verified identical after the
generalisation.

Rejected alternatives: serialising the sweep against removeShardIfEmpty
(a new lock on two hot paths to make a benign race impossible instead of
harmless); null-checking after the existing pair (keeps two reads and stays
off the file's idiom).
@github-actions

Copy link
Copy Markdown

Dependency Review

✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.

Scanned Files

None

@astubbs astubbs added the 0.6.0.0 Targeted at the 0.6.0.0 release label Aug 24, 2026
@github-actions

github-actions Bot commented Aug 24, 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 31 31 ➖ 0
Duplicated lines 971 971 ➖ 0
Duplication 0.13% 0.13% ➖ 0
Rule Limit Status
Max duplication 0.5% ✅ Pass (0.13%)
Max increase vs base +0.1% ✅ Pass (+0.00%)

No new clones introduced by this PR.

✅ jscpd (language-agnostic)

PR Base Change
Clones 83 82 🫤 +1
Duplicated lines 1213 1206 :face_with_monocle: +7
Duplication 1.09% 1.09% ➖ 0
Rule Limit Status
Max duplication 2% ✅ Pass (1.09%)
Max increase vs base +0.1% ✅ Pass (+0.00%)
⚠️ 1 new clones introduced
  • 8 lines: parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/internal/SubmitWorkToPoolShutdownRaceTest.java:14 <-> parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/state/WorkManagerTest.java:18

Powered by astubbs/duplicate-code-cross-check

@github-actions

github-actions Bot commented Aug 24, 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:

🆕 New file similarities introduced

File A File B Similarity (%)
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/state/LincheckHarness.java parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/state/ShardManagerLincheckTest.java 32.9
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/state/ShardManagerLincheckTest.java parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/state/WorkManagerLincheckTest.java 30.9
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/state/ShardManagerLincheckTest.java parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/state/ShardManagerRevokeSweepNpeTest.java 30.5

🔺 Increased similarities

File A File B Base (%) PR (%) Change
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/state/LincheckToolchainProbeTest.java parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/state/ShardManagerLincheckTest.java 34.8 38.1 +3.3
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/state/RetryQueueLincheckTest.java parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/state/ShardManagerLincheckTest.java 42.9 44.0 +1.1
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/state/PartitionStateLincheckTest.java parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/state/ShardManagerLincheckTest.java 31.3 32.0 +0.7
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/internal/InternalException.java parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/NoEncodingPossibleException.java 47.6 47.8 +0.2
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/BitSetEncodingNotSupportedException.java parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/EncodingNotSupportedException.java 49.0 49.2 +0.2
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/ExceptionInUserFunctionException.java parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/ParallelConsumerException.java 52.6 52.8 +0.2
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/EncodingNotSupportedException.java parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/NoEncodingPossibleException.java 44.8 45.0 +0.2
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/internal/InternalException.java parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/internal/InternalRuntimeException.java 40.4 40.5 +0.2
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/internal/InternalException.java parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/OffsetDecodingError.java 50.3 50.5 +0.2
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/EncodingNotSupportedException.java parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/OffsetDecodingError.java 47.4 47.6 +0.2
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/state/PartitionStateCommitEncodeShift894Test.java parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/state/PartitionStateLincheckTest.java 35.8 36.0 +0.2
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/ExceptionInUserFunctionException.java parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/internal/InternalException.java 37.5 37.7 +0.2
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/EncodingNotSupportedException.java parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/RunLengthV1EncodingNotSupported.java 46.1 46.2 +0.2
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/EncodingNotSupportedException.java parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/RunLengthV2EncodingNotSupported.java 44.9 45.1 +0.2
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/truth/CommitHistorySubject.java parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/truth/LongPollingMockConsumerSubject.java 36.3 36.4 +0.2
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/PCRetriableException.java parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/internal/InternalException.java 32.1 32.3 +0.2
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/ParallelConsumerException.java parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/BitSetEncodingNotSupportedException.java 32.6 32.8 +0.2
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/ParallelConsumerException.java parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/internal/InternalRuntimeException.java 31.7 31.8 +0.2
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/internal/InternalRuntimeException.java parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/EncodingNotSupportedException.java 30.9 31.1 +0.2
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/ExceptionInUserFunctionException.java parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/EncodingNotSupportedException.java 33.8 34.0 +0.2

...and 66 more

Full similarity report
jcstress-poc/src/main/java/bz/stub/parallelconsumer/jcstress/BootstrapResetTripleWriteProbes.java

📄 jcstress-poc/src/main/java/bz/stub/parallelconsumer/jcstress/BootstrapResetTripleWriteProbes.java

File Similarity (%)
jcstress-poc/src/main/java/bz/stub/parallelconsumer/jcstress/CommitPathVisibilityProbes.java 42.68
jcstress-poc/src/main/java/bz/stub/parallelconsumer/jcstress/SeenSucceededOrderingProbes.java 38.15
jcstress-poc/src/main/java/bz/stub/parallelconsumer/jcstress/CalibrationProbes.java

📄 jcstress-poc/src/main/java/bz/stub/parallelconsumer/jcstress/CalibrationProbes.java

File Similarity (%)
jcstress-poc/src/main/java/bz/stub/parallelconsumer/jcstress/SeenSucceededOrderingProbes.java 37.29
jcstress-poc/src/main/java/bz/stub/parallelconsumer/jcstress/CommitPathVisibilityProbes.java 37.17
jcstress-poc/src/main/java/bz/stub/parallelconsumer/jcstress/CommitPathVisibilityProbes.java

📄 jcstress-poc/src/main/java/bz/stub/parallelconsumer/jcstress/CommitPathVisibilityProbes.java

File Similarity (%)
jcstress-poc/src/main/java/bz/stub/parallelconsumer/jcstress/SeenSucceededOrderingProbes.java 56.85 ⚠️
jcstress-poc/src/main/java/bz/stub/parallelconsumer/jcstress/BootstrapResetTripleWriteProbes.java 42.68
jcstress-poc/src/main/java/bz/stub/parallelconsumer/jcstress/CalibrationProbes.java 37.17
jcstress-poc/src/main/java/bz/stub/parallelconsumer/jcstress/SeenSucceededOrderingProbes.java

📄 jcstress-poc/src/main/java/bz/stub/parallelconsumer/jcstress/SeenSucceededOrderingProbes.java

File Similarity (%)
jcstress-poc/src/main/java/bz/stub/parallelconsumer/jcstress/CommitPathVisibilityProbes.java 56.85 ⚠️
jcstress-poc/src/main/java/bz/stub/parallelconsumer/jcstress/BootstrapResetTripleWriteProbes.java 38.15
jcstress-poc/src/main/java/bz/stub/parallelconsumer/jcstress/CalibrationProbes.java 37.29
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/ExceptionInUserFunctionException.java

📄 parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/ExceptionInUserFunctionException.java

File Similarity (%)
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/ParallelConsumerException.java 52.8 ⚠️
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/internal/InternalException.java 37.73
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/PCRetriableException.java 34.59
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/EncodingNotSupportedException.java 33.97
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/BitSetEncodingNotSupportedException.java 32.47
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/OffsetDecodingError.java 32.46
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/RunLengthV1EncodingNotSupported.java 31.85
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/RunLengthV2EncodingNotSupported.java 31.05
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/JStreamParallelEoSStreamProcessor.java

📄 parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/JStreamParallelEoSStreamProcessor.java

File Similarity (%)
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/JStreamParallelStreamProcessor.java 64.06 ⚠️
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/ParallelEoSStreamProcessor.java 57.91 ⚠️
parallel-consumer-vertx/src/main/java/bz/stub/parallelconsumer/vertx/JStreamVertxParallelEoSStreamProcessor.java 42.51
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/ParallelStreamProcessor.java 40.8
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/PollContextInternal.java 35.41
parallel-consumer-vertx/src/main/java/bz/stub/parallelconsumer/vertx/JStreamVertxParallelStreamProcessor.java 33.22
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/internal/PCModule.java 32.74
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/internal/TestParallelEoSStreamProcessor.java 31.01
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/JStreamParallelStreamProcessor.java

📄 parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/JStreamParallelStreamProcessor.java

File Similarity (%)
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/JStreamParallelEoSStreamProcessor.java 64.06 ⚠️
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/ParallelEoSStreamProcessor.java 53.9 ⚠️
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/ParallelStreamProcessor.java 40.08
parallel-consumer-vertx/src/main/java/bz/stub/parallelconsumer/vertx/JStreamVertxParallelEoSStreamProcessor.java 34.88
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/PollContextInternal.java 34.38
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/internal/PCModule.java 32.94
parallel-consumer-vertx/src/main/java/bz/stub/parallelconsumer/vertx/JStreamVertxParallelStreamProcessor.java 32.37
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/PCRetriableException.java

📄 parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/PCRetriableException.java

File Similarity (%)
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/ExceptionInUserFunctionException.java 34.59
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/internal/InternalException.java 32.27
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/ParallelConsumerException.java

📄 parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/ParallelConsumerException.java

File Similarity (%)
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/ExceptionInUserFunctionException.java 52.8 ⚠️
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/internal/InternalException.java 51.38 ⚠️
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/EncodingNotSupportedException.java 41.83
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/BitSetEncodingNotSupportedException.java 32.77
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/OffsetDecodingError.java 31.93
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/internal/InternalRuntimeException.java 31.82
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/ParallelConsumerOptions.java

📄 parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/ParallelConsumerOptions.java

File Similarity (%)
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/internal/ProducerManager.java 30.84
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/ParallelEoSStreamProcessor.java

📄 parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/ParallelEoSStreamProcessor.java

File Similarity (%)
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/JStreamParallelEoSStreamProcessor.java 57.91 ⚠️
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/JStreamParallelStreamProcessor.java 53.9 ⚠️
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/ParallelStreamProcessor.java 48.52
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/PollContextInternal.java 36.32
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/internal/TestParallelEoSStreamProcessor.java 34.06
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/internal/PCModule.java 32.6
parallel-consumer-vertx/src/main/java/bz/stub/parallelconsumer/vertx/JStreamVertxParallelEoSStreamProcessor.java 32.24
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/ParallelStreamProcessor.java

📄 parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/ParallelStreamProcessor.java

File Similarity (%)
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/ParallelEoSStreamProcessor.java 48.52
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/JStreamParallelEoSStreamProcessor.java 40.8
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/JStreamParallelStreamProcessor.java 40.08
parallel-consumer-vertx/src/main/java/bz/stub/parallelconsumer/vertx/JStreamVertxParallelStreamProcessor.java 35.57
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/PollContext.java

📄 parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/PollContext.java

File Similarity (%)
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/RecordContextInternal.java 42.23
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/PollContextInternal.java 30.81
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/PollContextInternal.java

📄 parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/PollContextInternal.java

File Similarity (%)
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/ParallelEoSStreamProcessor.java 36.32
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/JStreamParallelEoSStreamProcessor.java 35.41
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/JStreamParallelStreamProcessor.java 34.38
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/RecordContextInternal.java 33.92
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/PollContext.java 30.81
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/RecordContextInternal.java

📄 parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/RecordContextInternal.java

File Similarity (%)
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/PollContext.java 42.23
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/PollContextInternal.java 33.92
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/internal/AbstractParallelEoSStreamProcessor.java

📄 parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/internal/AbstractParallelEoSStreamProcessor.java

File Similarity (%)
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/internal/SubmitWorkToPoolShutdownRaceTest.java 44.36
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/internal/BrokerPollSystem.java 33.33
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/AbstractParallelEoSStreamProcessorConfigurationTest.java 32.65
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/internal/BrokerPollSystem.java

📄 parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/internal/BrokerPollSystem.java

File Similarity (%)
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/internal/AbstractParallelEoSStreamProcessor.java 33.33
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/internal/ConsumerManager.java

📄 parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/internal/ConsumerManager.java

File Similarity (%)
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/internal/ConsumerManagerCommitRetryBudgetTest.java 30.63
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/internal/ConsumerOffsetCommitter.java

📄 parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/internal/ConsumerOffsetCommitter.java

File Similarity (%)
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/CommitResponseTimeoutSymptomTest.java 33.7
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/internal/ExternalEngine.java

📄 parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/internal/ExternalEngine.java

File Similarity (%)
parallel-consumer-vertx/src/main/java/bz/stub/parallelconsumer/vertx/VertxParallelEoSStreamProcessor.java 39.99
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/internal/InternalException.java

📄 parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/internal/InternalException.java

File Similarity (%)
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/EncodingNotSupportedException.java 57.67 ⚠️
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/ParallelConsumerException.java 51.38 ⚠️
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/OffsetDecodingError.java 50.48 ⚠️
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/NoEncodingPossibleException.java 47.8
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/internal/InternalRuntimeException.java 40.55
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/ExceptionInUserFunctionException.java 37.73
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/BitSetEncodingNotSupportedException.java 34.22
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/PCRetriableException.java 32.27
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/RunLengthV1EncodingNotSupported.java 31.1
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/RunLengthV2EncodingNotSupported.java 30.33
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/internal/InternalRuntimeException.java

📄 parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/internal/InternalRuntimeException.java

File Similarity (%)
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/internal/InternalException.java 40.55
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/ParallelConsumerException.java 31.82
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/EncodingNotSupportedException.java 31.11
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/internal/PCModule.java

📄 parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/internal/PCModule.java

File Similarity (%)
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/JStreamParallelStreamProcessor.java 32.94
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/JStreamParallelEoSStreamProcessor.java 32.74
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/ParallelEoSStreamProcessor.java 32.6
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/internal/PCModuleTestEnv.java 31.82
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/internal/PollThreadStallDiagnosis.java

📄 parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/internal/PollThreadStallDiagnosis.java

File Similarity (%)
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/internal/PollThreadStallDiagnosisTest.java 33.26
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/AmbientProbeExtension.java 33.14
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/internal/ProducerManager.java

📄 parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/internal/ProducerManager.java

File Similarity (%)
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/ParallelConsumerOptions.java 30.84
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/internal/utils/Java8StreamUtils.java

📄 parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/internal/utils/Java8StreamUtils.java

File Similarity (%)
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/internal/utils/JavaUtils.java 33.77
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/internal/utils/CollectionUtils.java 31.48
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/internal/utils/JavaUtils.java

📄 parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/internal/utils/JavaUtils.java

File Similarity (%)
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/internal/utils/CollectionUtils.java 38.41
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/internal/utils/Java8StreamUtils.java 33.77
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/BitSetEncodingNotSupportedException.java

📄 parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/BitSetEncodingNotSupportedException.java

File Similarity (%)
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/EncodingNotSupportedException.java 49.2
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/RunLengthV1EncodingNotSupported.java 35.37
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/RunLengthV2EncodingNotSupported.java 34.49
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/internal/InternalException.java 34.22
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/ParallelConsumerException.java 32.77
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/ExceptionInUserFunctionException.java 32.47
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/OffsetDecodingError.java 31.15
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/EncodingNotSupportedException.java

📄 parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/EncodingNotSupportedException.java

File Similarity (%)
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/internal/InternalException.java 57.67 ⚠️
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/BitSetEncodingNotSupportedException.java 49.2
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/OffsetDecodingError.java 47.56
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/RunLengthV1EncodingNotSupported.java 46.25
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/RunLengthV2EncodingNotSupported.java 45.1
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/NoEncodingPossibleException.java 45.0
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/ParallelConsumerException.java 41.83
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/ExceptionInUserFunctionException.java 33.97
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/internal/InternalRuntimeException.java 31.11
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/NoEncodingPossibleException.java

📄 parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/NoEncodingPossibleException.java

File Similarity (%)
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/internal/InternalException.java 47.8
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/OffsetDecodingError.java 45.76
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/EncodingNotSupportedException.java 45.0
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/RunLengthV1EncodingNotSupported.java 35.62
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/RunLengthV2EncodingNotSupported.java 34.73
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/OffsetDecodingError.java

📄 parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/OffsetDecodingError.java

File Similarity (%)
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/internal/InternalException.java 50.48 ⚠️
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/EncodingNotSupportedException.java 47.56
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/NoEncodingPossibleException.java 45.76
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/ExceptionInUserFunctionException.java 32.46
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/ParallelConsumerException.java 31.93
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/BitSetEncodingNotSupportedException.java 31.15
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/RunLengthV1EncodingNotSupported.java

📄 parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/RunLengthV1EncodingNotSupported.java

File Similarity (%)
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/RunLengthV2EncodingNotSupported.java 61.35 ⚠️
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/EncodingNotSupportedException.java 46.25
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/NoEncodingPossibleException.java 35.62
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/BitSetEncodingNotSupportedException.java 35.37
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/ExceptionInUserFunctionException.java 31.85
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/internal/InternalException.java 31.1
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/RunLengthV2EncodingNotSupported.java

📄 parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/RunLengthV2EncodingNotSupported.java

File Similarity (%)
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/RunLengthV1EncodingNotSupported.java 61.35 ⚠️
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/EncodingNotSupportedException.java 45.1
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/NoEncodingPossibleException.java 34.73
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/BitSetEncodingNotSupportedException.java 34.49
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/ExceptionInUserFunctionException.java 31.05
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/internal/InternalException.java 30.33
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/state/PartitionState.java

📄 parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/state/PartitionState.java

File Similarity (%)
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/state/PartitionStateManager.java 32.29
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/state/PartitionStateManager.java

📄 parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/state/PartitionStateManager.java

File Similarity (%)
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/state/WorkManager.java 39.99
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/state/PartitionState.java 32.29
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/state/ProcessingShard.java

📄 parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/state/ProcessingShard.java

File Similarity (%)
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/state/ShardManager.java 34.15
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/state/ShardManager.java

📄 parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/state/ShardManager.java

File Similarity (%)
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/state/ProcessingShard.java 34.15
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/state/WorkManager.java

📄 parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/state/WorkManager.java

File Similarity (%)
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/state/PartitionStateManager.java 39.99
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/AmbientProbeExtension.java

📄 parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/AmbientProbeExtension.java

File Similarity (%)
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/internal/PollThreadStallDiagnosis.java 33.14
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/AmbientProbeExtensionTest.java 31.09
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/KafkaSanityTests.java

📄 parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/KafkaSanityTests.java

File Similarity (%)
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/internal/utils/LoopingResumingIteratorTest.java 32.6
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/ManagedPCInstanceLifecycleIT.java

📄 parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/ManagedPCInstanceLifecycleIT.java

File Similarity (%)
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/utils/ManagedPCInstance.java 30.74
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/MultiInstanceHighVolumeTest.java

📄 parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/MultiInstanceHighVolumeTest.java

File Similarity (%)
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/VeryLargeMessageVolumeTest.java 57.14 ⚠️
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/TransactionAndCommitModeTest.java 43.73
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/MultiInstanceRebalanceTest.java 35.93
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/MultiInstanceRebalanceTest.java

📄 parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/MultiInstanceRebalanceTest.java

File Similarity (%)
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/VeryLargeMessageVolumeTest.java 39.92
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/TransactionAndCommitModeTest.java 39.28
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/MultiInstanceHighVolumeTest.java 35.93
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/RebalanceEoSDeadlockTest.java

📄 parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/RebalanceEoSDeadlockTest.java

File Similarity (%)
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/RebalanceTest.java 35.73
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/RebalanceTest.java

📄 parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/RebalanceTest.java

File Similarity (%)
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/RebalanceEoSDeadlockTest.java 35.73
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/TransactionAndCommitModeTest.java

📄 parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/TransactionAndCommitModeTest.java

File Similarity (%)
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/VeryLargeMessageVolumeTest.java 54.24 ⚠️
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/MultiInstanceHighVolumeTest.java 43.73
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/MultiInstanceRebalanceTest.java 39.28
parallel-consumer-vertx/src/test-integration/java/bz/stub/parallelconsumer/vertx/integrationTests/VertxConcurrencyIT.java 31.11
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/VeryLargeMessageVolumeTest.java

📄 parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/VeryLargeMessageVolumeTest.java

File Similarity (%)
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/MultiInstanceHighVolumeTest.java 57.14 ⚠️
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/TransactionAndCommitModeTest.java 54.24 ⚠️
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/MultiInstanceRebalanceTest.java 39.92
parallel-consumer-vertx/src/test-integration/java/bz/stub/parallelconsumer/vertx/integrationTests/VertxConcurrencyIT.java 35.59
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/chaostests/AbstractRevokeUnderWorkScenario.java

📄 parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/chaostests/AbstractRevokeUnderWorkScenario.java

File Similarity (%)
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/chaostests/ChaosRevokeUnderWorkKeyOrderIT.java 40.24
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/chaostests/ChaosKeyOrderIT.java 39.99
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/chaostests/ChaosChurnStormIT.java 38.51
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/chaostests/ProgressProbe.java 36.39
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/chaostests/ChaosRevokeUnderWorkIT.java 33.75
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/chaostests/ChaosChurnStormIT.java

📄 parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/chaostests/ChaosChurnStormIT.java

File Similarity (%)
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/chaostests/ChaosKeyOrderIT.java 46.82
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/chaostests/AbstractRevokeUnderWorkScenario.java 38.51
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/chaostests/ChaosScenarioBase.java 32.49
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/chaostests/ChaosKeyOrderIT.java

📄 parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/chaostests/ChaosKeyOrderIT.java

File Similarity (%)
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/chaostests/ChaosRevokeUnderWorkKeyOrderIT.java 53.81 ⚠️
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/chaostests/ChaosChurnStormIT.java 46.82
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/chaostests/AbstractRevokeUnderWorkScenario.java 39.99
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/chaostests/ChaosScenarioBase.java 36.02
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/chaostests/ProgressProbe.java 33.08
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/chaostests/KeyOrderLedger.java 32.0
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/chaostests/ChaosRevokeUnderWorkCooperativeDrainIT.java

📄 parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/chaostests/ChaosRevokeUnderWorkCooperativeDrainIT.java

File Similarity (%)
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/chaostests/ChaosRevokeUnderWorkDrainIT.java 39.52
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/chaostests/ChaosRevokeUnderWorkCooperativeIT.java

📄 parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/chaostests/ChaosRevokeUnderWorkCooperativeIT.java

File Similarity (%)
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/chaostests/ChaosRevokeUnderWorkIT.java 43.36
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/chaostests/ChaosRevokeUnderWorkDrainIT.java

📄 parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/chaostests/ChaosRevokeUnderWorkDrainIT.java

File Similarity (%)
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/chaostests/ChaosRevokeUnderWorkCooperativeDrainIT.java 39.52
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/chaostests/ChaosRevokeUnderWorkIT.java 30.19
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/chaostests/ChaosRevokeUnderWorkIT.java

📄 parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/chaostests/ChaosRevokeUnderWorkIT.java

File Similarity (%)
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/chaostests/ChaosRevokeUnderWorkCooperativeIT.java 43.36
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/chaostests/AbstractRevokeUnderWorkScenario.java 33.75
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/chaostests/ChaosRevokeUnderWorkDrainIT.java 30.19
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/chaostests/ChaosRevokeUnderWorkKeyOrderIT.java

📄 parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/chaostests/ChaosRevokeUnderWorkKeyOrderIT.java

File Similarity (%)
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/chaostests/ChaosKeyOrderIT.java 53.81 ⚠️
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/chaostests/AbstractRevokeUnderWorkScenario.java 40.24
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/chaostests/ChaosScenarioBase.java

📄 parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/chaostests/ChaosScenarioBase.java

File Similarity (%)
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/chaostests/ChaosKeyOrderIT.java 36.02
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/chaostests/ChaosChurnStormIT.java 32.49
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/chaostests/DiagnosticQuietCap.java

📄 parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/chaostests/DiagnosticQuietCap.java

File Similarity (%)
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/chaostests/DiagnosticQuietCapIT.java 53.07 ⚠️
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/chaostests/DiagnosticQuietCapIT.java

📄 parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/chaostests/DiagnosticQuietCapIT.java

File Similarity (%)
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/chaostests/DiagnosticQuietCap.java 53.07 ⚠️
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/chaostests/KeyOrderLedger.java

📄 parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/chaostests/KeyOrderLedger.java

File Similarity (%)
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/chaostests/KeyOrderLedgerIT.java 33.16
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/chaostests/ChaosKeyOrderIT.java 32.0
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/chaostests/KeyOrderLedgerIT.java

📄 parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/chaostests/KeyOrderLedgerIT.java

File Similarity (%)
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/chaostests/KeyOrderLedger.java 33.16
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/chaostests/ProgressProbe.java

📄 parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/chaostests/ProgressProbe.java

File Similarity (%)
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/chaostests/AbstractRevokeUnderWorkScenario.java 36.39
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/chaostests/ChaosKeyOrderIT.java 33.08
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/utils/ManagedPCInstance.java

📄 parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/utils/ManagedPCInstance.java

File Similarity (%)
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/ManagedPCInstanceLifecycleIT.java 30.74
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/AbstractParallelEoSStreamProcessorConfigurationTest.java

📄 parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/AbstractParallelEoSStreamProcessorConfigurationTest.java

File Similarity (%)
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/internal/SubmitWorkToPoolShutdownRaceTest.java 41.48
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/internal/AbstractParallelEoSStreamProcessor.java 32.65
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/AbstractParallelEoSStreamProcessorTestBase.java

📄 parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/AbstractParallelEoSStreamProcessorTestBase.java

File Similarity (%)
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/internal/utils/KafkaTestUtils.java 31.75
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/AmbientProbeExtensionTest.java

📄 parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/AmbientProbeExtensionTest.java

File Similarity (%)
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/AmbientProbeExtension.java 31.09
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/BatchTestBase.java

📄 parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/BatchTestBase.java

File Similarity (%)
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/CoreBatchTest.java 30.14
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/CheckQuarantineOwnersScriptTest.java

📄 parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/CheckQuarantineOwnersScriptTest.java

File Similarity (%)
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/QuarantineLaneReportScriptTest.java 47.97
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/QuarantineRegistryScriptTest.java 45.37
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/CommitRejectionTestBase.java

📄 parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/CommitRejectionTestBase.java

File Similarity (%)
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/CommitResponseTimeoutSymptomTest.java 32.69
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/CommitResponseTimeoutSymptomTest.java

📄 parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/CommitResponseTimeoutSymptomTest.java

File Similarity (%)
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/MockConsumerTestBase.java 39.27
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/internal/ConsumerOffsetCommitter.java 33.7
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/CommitRejectionTestBase.java 32.69
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/CoreBatchTest.java

📄 parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/CoreBatchTest.java

File Similarity (%)
parallel-consumer-reactor/src/test/java/bz/stub/parallelconsumer/reactor/ReactorBatchTest.java 51.81 ⚠️
parallel-consumer-mutiny/src/test/java/bz/stub/parallelconsumer/mutiny/MutinyBatchTest.java 50.21 ⚠️
parallel-consumer-vertx/src/test/java/bz/stub/parallelconsumer/vertx/VertxBatchTest.java 44.73
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/BatchTestBase.java 30.14
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/MockConsumerCommitTimeoutTest.java

📄 parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/MockConsumerCommitTimeoutTest.java

File Similarity (%)
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/MockConsumerSaslAuthenticationTest.java 44.34
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/MockConsumerSaslAuthenticationTest.java

📄 parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/MockConsumerSaslAuthenticationTest.java

File Similarity (%)
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/MockConsumerCommitTimeoutTest.java 44.34
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/MockConsumerTestBase.java

📄 parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/MockConsumerTestBase.java

File Similarity (%)
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/CommitResponseTimeoutSymptomTest.java 39.27
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/ParallelEoSSStreamProcessorRebalancedTest.java

📄 parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/ParallelEoSSStreamProcessorRebalancedTest.java

File Similarity (%)
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/ParallelEoSStreamProcessorTest.java 34.54
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/ParallelEoSStreamProcessorTest.java

📄 parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/ParallelEoSStreamProcessorTest.java

File Similarity (%)
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/ParallelEoSSStreamProcessorRebalancedTest.java 34.54
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/QuarantineLaneReportScriptTest.java

📄 parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/QuarantineLaneReportScriptTest.java

File Similarity (%)
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/CheckQuarantineOwnersScriptTest.java 47.97
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/QuarantineRegistryScriptTest.java 30.65
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/QuarantineRegistryScriptTest.java

📄 parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/QuarantineRegistryScriptTest.java

File Similarity (%)
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/CheckQuarantineOwnersScriptTest.java 45.37
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/QuarantineLaneReportScriptTest.java 30.65
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/TestConventionsArchTest.java

📄 parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/TestConventionsArchTest.java

File Similarity (%)
parallel-consumer-vertx/src/test/java/bz/stub/parallelconsumer/vertx/TestConventionsArchTest.java 87.14 ⚠️
parallel-consumer-mutiny/src/test/java/bz/stub/parallelconsumer/mutiny/TestConventionsArchTest.java 86.2 ⚠️
parallel-consumer-reactor/src/test/java/bz/stub/parallelconsumer/reactor/TestConventionsArchTest.java 86.2 ⚠️
parallel-consumer-examples/parallel-consumer-example-core/src/test/java/bz/stub/parallelconsumer/examples/core/TestConventionsArchTest.java 83.78 ⚠️
parallel-consumer-examples/parallel-consumer-example-reactor/src/test/java/bz/stub/parallelconsumer/examples/reactor/TestConventionsArchTest.java 83.78 ⚠️
parallel-consumer-examples/parallel-consumer-example-vertx/src/test/java/bz/stub/parallelconsumer/examples/vertx/TestConventionsArchTest.java 83.78 ⚠️
parallel-consumer-examples/parallel-consumer-example-metrics/src/test/java/bz/stub/parallelconsumer/examples/metrics/TestConventionsArchTest.java 82.28 ⚠️
parallel-consumer-examples/parallel-consumer-example-streams/src/test/java/bz/stub/parallelconsumer/examples/streams/TestConventionsArchTest.java 82.28 ⚠️
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/internal/ConsumerManagerCommitRetryBudgetTest.java

📄 parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/internal/ConsumerManagerCommitRetryBudgetTest.java

File Similarity (%)
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/internal/ConsumerManager.java 30.63
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/internal/PCModuleTestEnv.java

📄 parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/internal/PCModuleTestEnv.java

File Similarity (%)
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/internal/PCModule.java 31.82
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/internal/PollThreadStallDiagnosisTest.java

📄 parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/internal/PollThreadStallDiagnosisTest.java

File Similarity (%)
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/internal/PollThreadStallDiagnosis.java 33.26
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/internal/SubmitWorkToPoolShutdownRaceTest.java

📄 parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/internal/SubmitWorkToPoolShutdownRaceTest.java

File Similarity (%)
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/internal/AbstractParallelEoSStreamProcessor.java 44.36
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/AbstractParallelEoSStreamProcessorConfigurationTest.java 41.48
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/internal/TestParallelEoSStreamProcessor.java

📄 parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/internal/TestParallelEoSStreamProcessor.java

File Similarity (%)
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/ParallelEoSStreamProcessor.java 34.06
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/JStreamParallelEoSStreamProcessor.java 31.01
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/internal/utils/BlockedThreadAsserter.java

📄 parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/internal/utils/BlockedThreadAsserter.java

File Similarity (%)
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/internal/utils/BlockedThreadAsserterTest.java 32.22
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/internal/utils/BlockedThreadAsserterTest.java

📄 parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/internal/utils/BlockedThreadAsserterTest.java

File Similarity (%)
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/internal/utils/BlockedThreadAsserter.java 32.22
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/internal/utils/CollectionUtils.java

📄 parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/internal/utils/CollectionUtils.java

File Similarity (%)
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/internal/utils/JavaUtils.java 38.41
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/internal/utils/Java8StreamUtils.java 31.48
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/internal/utils/KafkaTestUtils.java

📄 parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/internal/utils/KafkaTestUtils.java

File Similarity (%)
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/AbstractParallelEoSStreamProcessorTestBase.java 31.75
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/internal/utils/LoopingResumingIteratorTest.java

📄 parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/internal/utils/LoopingResumingIteratorTest.java

File Similarity (%)
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/KafkaSanityTests.java 32.6
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/offsets/OffsetEncodingBackPressureTest.java

📄 parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/offsets/OffsetEncodingBackPressureTest.java

File Similarity (%)
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/offsets/OffsetEncodingBackPressureUnitTest.java 37.8
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/offsets/OffsetEncodingBackPressureUnitTest.java

📄 parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/offsets/OffsetEncodingBackPressureUnitTest.java

File Similarity (%)
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/offsets/OffsetEncodingBackPressureTest.java 37.8
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/state/LincheckHarness.java

📄 parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/state/LincheckHarness.java

File Similarity (%)
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/state/ShardManagerLincheckTest.java 32.91
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/state/LincheckToolchainProbeTest.java 32.48
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/state/LincheckToolchainProbeTest.java

📄 parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/state/LincheckToolchainProbeTest.java

File Similarity (%)
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/state/ShardManagerLincheckTest.java 38.11
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/state/LincheckHarness.java 32.48
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/state/PartitionStateCommitEncodeShift894Test.java

📄 parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/state/PartitionStateCommitEncodeShift894Test.java

File Similarity (%)
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/state/PartitionStateCommitShiftCompounding894Test.java 44.97
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/state/PartitionStateLincheckTest.java 35.95
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/state/PartitionStateCommitShiftCompounding894Test.java

📄 parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/state/PartitionStateCommitShiftCompounding894Test.java

File Similarity (%)
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/state/PartitionStateCommitEncodeShift894Test.java 44.97
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/state/PartitionStateLincheckTest.java

📄 parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/state/PartitionStateLincheckTest.java

File Similarity (%)
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/state/PartitionStateCommitEncodeShift894Test.java 35.95
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/state/RetryQueueLincheckTest.java 32.29
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/state/ShardManagerLincheckTest.java 32.02
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/state/RetryQueueLincheckTest.java

📄 parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/state/RetryQueueLincheckTest.java

File Similarity (%)
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/state/ShardManagerLincheckTest.java 44.05
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/state/PartitionStateLincheckTest.java 32.29
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/state/RetryQueueTest.java 30.62
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/state/WorkManagerLincheckTest.java 30.29
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/state/RetryQueueTest.java

📄 parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/state/RetryQueueTest.java

File Similarity (%)
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/state/RetryQueueLincheckTest.java 30.62
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/state/ShardManagerLincheckTest.java

📄 parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/state/ShardManagerLincheckTest.java

File Similarity (%)
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/state/RetryQueueLincheckTest.java 44.05
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/state/LincheckToolchainProbeTest.java 38.11
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/state/LincheckHarness.java 32.91
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/state/PartitionStateLincheckTest.java 32.02
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/state/WorkManagerLincheckTest.java 30.95
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/state/ShardManagerRevokeSweepNpeTest.java 30.47
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/state/ShardManagerRevokeSweepNpeTest.java

📄 parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/state/ShardManagerRevokeSweepNpeTest.java

File Similarity (%)
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/state/ShardManagerLincheckTest.java 30.47
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/state/WorkManagerLincheckTest.java

📄 parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/state/WorkManagerLincheckTest.java

File Similarity (%)
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/state/ShardManagerLincheckTest.java 30.95
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/state/RetryQueueLincheckTest.java 30.29
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/truth/CommitHistorySubject.java

📄 parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/truth/CommitHistorySubject.java

File Similarity (%)
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/truth/LongPollingMockConsumerSubject.java 36.43
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/truth/LongPollingMockConsumerSubject.java

📄 parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/truth/LongPollingMockConsumerSubject.java

File Similarity (%)
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/truth/CommitHistorySubject.java 36.43
parallel-consumer-examples/parallel-consumer-example-core/src/main/java/bz/stub/parallelconsumer/examples/core/CoreApp.java

📄 parallel-consumer-examples/parallel-consumer-example-core/src/main/java/bz/stub/parallelconsumer/examples/core/CoreApp.java

File Similarity (%)
parallel-consumer-examples/parallel-consumer-example-reactor/src/main/java/bz/stub/parallelconsumer/examples/reactor/ReactorApp.java 36.89
parallel-consumer-examples/parallel-consumer-example-core/src/test/java/bz/stub/parallelconsumer/examples/core/CoreAppTest.java

📄 parallel-consumer-examples/parallel-consumer-example-core/src/test/java/bz/stub/parallelconsumer/examples/core/CoreAppTest.java

File Similarity (%)
parallel-consumer-examples/parallel-consumer-example-reactor/src/test/java/bz/stub/parallelconsumer/examples/reactor/ReactorAppTest.java 39.85
parallel-consumer-examples/parallel-consumer-example-metrics/src/test/java/bz/stub/parallelconsumer/examples/metrics/integrationTests/CoreAppMetricsIntegrationTest.java 36.29
parallel-consumer-examples/parallel-consumer-example-vertx/src/test/java/bz/stub/parallelconsumer/examples/vertx/VertxAppTest.java 35.61
parallel-consumer-examples/parallel-consumer-example-core/src/test/java/bz/stub/parallelconsumer/examples/core/TestConventionsArchTest.java

📄 parallel-consumer-examples/parallel-consumer-example-core/src/test/java/bz/stub/parallelconsumer/examples/core/TestConventionsArchTest.java

File Similarity (%)
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/TestConventionsArchTest.java 83.78 ⚠️
parallel-consumer-vertx/src/test/java/bz/stub/parallelconsumer/vertx/TestConventionsArchTest.java 83.54 ⚠️
parallel-consumer-mutiny/src/test/java/bz/stub/parallelconsumer/mutiny/TestConventionsArchTest.java 82.64 ⚠️
parallel-consumer-reactor/src/test/java/bz/stub/parallelconsumer/reactor/TestConventionsArchTest.java 82.64 ⚠️
parallel-consumer-examples/parallel-consumer-example-reactor/src/test/java/bz/stub/parallelconsumer/examples/reactor/TestConventionsArchTest.java 80.31 ⚠️
parallel-consumer-examples/parallel-consumer-example-vertx/src/test/java/bz/stub/parallelconsumer/examples/vertx/TestConventionsArchTest.java 80.31 ⚠️
parallel-consumer-examples/parallel-consumer-example-metrics/src/test/java/bz/stub/parallelconsumer/examples/metrics/TestConventionsArchTest.java 78.88 ⚠️
parallel-consumer-examples/parallel-consumer-example-streams/src/test/java/bz/stub/parallelconsumer/examples/streams/TestConventionsArchTest.java 78.88 ⚠️
parallel-consumer-examples/parallel-consumer-example-metrics/src/test/java/bz/stub/parallelconsumer/examples/metrics/TestConventionsArchTest.java

📄 parallel-consumer-examples/parallel-consumer-example-metrics/src/test/java/bz/stub/parallelconsumer/examples/metrics/TestConventionsArchTest.java

File Similarity (%)
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/TestConventionsArchTest.java 82.28 ⚠️
parallel-consumer-vertx/src/test/java/bz/stub/parallelconsumer/vertx/TestConventionsArchTest.java 82.05 ⚠️
parallel-consumer-mutiny/src/test/java/bz/stub/parallelconsumer/mutiny/TestConventionsArchTest.java 81.16 ⚠️
parallel-consumer-reactor/src/test/java/bz/stub/parallelconsumer/reactor/TestConventionsArchTest.java 81.16 ⚠️
parallel-consumer-examples/parallel-consumer-example-core/src/test/java/bz/stub/parallelconsumer/examples/core/TestConventionsArchTest.java 78.88 ⚠️
parallel-consumer-examples/parallel-consumer-example-reactor/src/test/java/bz/stub/parallelconsumer/examples/reactor/TestConventionsArchTest.java 78.88 ⚠️
parallel-consumer-examples/parallel-consumer-example-vertx/src/test/java/bz/stub/parallelconsumer/examples/vertx/TestConventionsArchTest.java 78.88 ⚠️
parallel-consumer-examples/parallel-consumer-example-streams/src/test/java/bz/stub/parallelconsumer/examples/streams/TestConventionsArchTest.java 77.47 ⚠️
parallel-consumer-examples/parallel-consumer-example-metrics/src/test/java/bz/stub/parallelconsumer/examples/metrics/integrationTests/CoreAppMetricsIntegrationTest.java

📄 parallel-consumer-examples/parallel-consumer-example-metrics/src/test/java/bz/stub/parallelconsumer/examples/metrics/integrationTests/CoreAppMetricsIntegrationTest.java

File Similarity (%)
parallel-consumer-examples/parallel-consumer-example-core/src/test/java/bz/stub/parallelconsumer/examples/core/CoreAppTest.java 36.29
parallel-consumer-examples/parallel-consumer-example-reactor/src/main/java/bz/stub/parallelconsumer/examples/reactor/ReactorApp.java

📄 parallel-consumer-examples/parallel-consumer-example-reactor/src/main/java/bz/stub/parallelconsumer/examples/reactor/ReactorApp.java

File Similarity (%)
parallel-consumer-examples/parallel-consumer-example-vertx/src/main/java/bz/stub/parallelconsumer/examples/vertx/VertxApp.java 69.76 ⚠️
parallel-consumer-examples/parallel-consumer-example-core/src/main/java/bz/stub/parallelconsumer/examples/core/CoreApp.java 36.89
parallel-consumer-examples/parallel-consumer-example-reactor/src/test/java/bz/stub/parallelconsumer/examples/reactor/ReactorAppTest.java

📄 parallel-consumer-examples/parallel-consumer-example-reactor/src/test/java/bz/stub/parallelconsumer/examples/reactor/ReactorAppTest.java

File Similarity (%)
parallel-consumer-examples/parallel-consumer-example-vertx/src/test/java/bz/stub/parallelconsumer/examples/vertx/VertxAppTest.java 46.67
parallel-consumer-examples/parallel-consumer-example-core/src/test/java/bz/stub/parallelconsumer/examples/core/CoreAppTest.java 39.85
parallel-consumer-examples/parallel-consumer-example-reactor/src/test/java/bz/stub/parallelconsumer/examples/reactor/TestConventionsArchTest.java

📄 parallel-consumer-examples/parallel-consumer-example-reactor/src/test/java/bz/stub/parallelconsumer/examples/reactor/TestConventionsArchTest.java

File Similarity (%)
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/TestConventionsArchTest.java 83.78 ⚠️
parallel-consumer-vertx/src/test/java/bz/stub/parallelconsumer/vertx/TestConventionsArchTest.java 83.54 ⚠️
parallel-consumer-mutiny/src/test/java/bz/stub/parallelconsumer/mutiny/TestConventionsArchTest.java 82.64 ⚠️
parallel-consumer-reactor/src/test/java/bz/stub/parallelconsumer/reactor/TestConventionsArchTest.java 82.64 ⚠️
parallel-consumer-examples/parallel-consumer-example-core/src/test/java/bz/stub/parallelconsumer/examples/core/TestConventionsArchTest.java 80.31 ⚠️
parallel-consumer-examples/parallel-consumer-example-vertx/src/test/java/bz/stub/parallelconsumer/examples/vertx/TestConventionsArchTest.java 80.31 ⚠️
parallel-consumer-examples/parallel-consumer-example-metrics/src/test/java/bz/stub/parallelconsumer/examples/metrics/TestConventionsArchTest.java 78.88 ⚠️
parallel-consumer-examples/parallel-consumer-example-streams/src/test/java/bz/stub/parallelconsumer/examples/streams/TestConventionsArchTest.java 78.88 ⚠️
parallel-consumer-examples/parallel-consumer-example-streams/src/test/java/bz/stub/parallelconsumer/examples/streams/TestConventionsArchTest.java

📄 parallel-consumer-examples/parallel-consumer-example-streams/src/test/java/bz/stub/parallelconsumer/examples/streams/TestConventionsArchTest.java

File Similarity (%)
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/TestConventionsArchTest.java 82.28 ⚠️
parallel-consumer-vertx/src/test/java/bz/stub/parallelconsumer/vertx/TestConventionsArchTest.java 82.05 ⚠️
parallel-consumer-mutiny/src/test/java/bz/stub/parallelconsumer/mutiny/TestConventionsArchTest.java 81.16 ⚠️
parallel-consumer-reactor/src/test/java/bz/stub/parallelconsumer/reactor/TestConventionsArchTest.java 81.16 ⚠️
parallel-consumer-examples/parallel-consumer-example-core/src/test/java/bz/stub/parallelconsumer/examples/core/TestConventionsArchTest.java 78.88 ⚠️
parallel-consumer-examples/parallel-consumer-example-reactor/src/test/java/bz/stub/parallelconsumer/examples/reactor/TestConventionsArchTest.java 78.88 ⚠️
parallel-consumer-examples/parallel-consumer-example-vertx/src/test/java/bz/stub/parallelconsumer/examples/vertx/TestConventionsArchTest.java 78.88 ⚠️
parallel-consumer-examples/parallel-consumer-example-metrics/src/test/java/bz/stub/parallelconsumer/examples/metrics/TestConventionsArchTest.java 77.47 ⚠️
parallel-consumer-examples/parallel-consumer-example-vertx/src/main/java/bz/stub/parallelconsumer/examples/vertx/VertxApp.java

📄 parallel-consumer-examples/parallel-consumer-example-vertx/src/main/java/bz/stub/parallelconsumer/examples/vertx/VertxApp.java

File Similarity (%)
parallel-consumer-examples/parallel-consumer-example-reactor/src/main/java/bz/stub/parallelconsumer/examples/reactor/ReactorApp.java 69.76 ⚠️
parallel-consumer-examples/parallel-consumer-example-vertx/src/test/java/bz/stub/parallelconsumer/examples/vertx/TestConventionsArchTest.java

📄 parallel-consumer-examples/parallel-consumer-example-vertx/src/test/java/bz/stub/parallelconsumer/examples/vertx/TestConventionsArchTest.java

File Similarity (%)
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/TestConventionsArchTest.java 83.78 ⚠️
parallel-consumer-vertx/src/test/java/bz/stub/parallelconsumer/vertx/TestConventionsArchTest.java 83.54 ⚠️
parallel-consumer-mutiny/src/test/java/bz/stub/parallelconsumer/mutiny/TestConventionsArchTest.java 82.64 ⚠️
parallel-consumer-reactor/src/test/java/bz/stub/parallelconsumer/reactor/TestConventionsArchTest.java 82.64 ⚠️
parallel-consumer-examples/parallel-consumer-example-core/src/test/java/bz/stub/parallelconsumer/examples/core/TestConventionsArchTest.java 80.31 ⚠️
parallel-consumer-examples/parallel-consumer-example-reactor/src/test/java/bz/stub/parallelconsumer/examples/reactor/TestConventionsArchTest.java 80.31 ⚠️
parallel-consumer-examples/parallel-consumer-example-metrics/src/test/java/bz/stub/parallelconsumer/examples/metrics/TestConventionsArchTest.java 78.88 ⚠️
parallel-consumer-examples/parallel-consumer-example-streams/src/test/java/bz/stub/parallelconsumer/examples/streams/TestConventionsArchTest.java 78.88 ⚠️
parallel-consumer-examples/parallel-consumer-example-vertx/src/test/java/bz/stub/parallelconsumer/examples/vertx/VertxAppTest.java

📄 parallel-consumer-examples/parallel-consumer-example-vertx/src/test/java/bz/stub/parallelconsumer/examples/vertx/VertxAppTest.java

File Similarity (%)
parallel-consumer-examples/parallel-consumer-example-reactor/src/test/java/bz/stub/parallelconsumer/examples/reactor/ReactorAppTest.java 46.67
parallel-consumer-examples/parallel-consumer-example-core/src/test/java/bz/stub/parallelconsumer/examples/core/CoreAppTest.java 35.61
parallel-consumer-mutiny/src/main/java/bz/stub/parallelconsumer/mutiny/MutinyProcessor.java

📄 parallel-consumer-mutiny/src/main/java/bz/stub/parallelconsumer/mutiny/MutinyProcessor.java

File Similarity (%)
parallel-consumer-reactor/src/main/java/bz/stub/parallelconsumer/reactor/ReactorProcessor.java 51.54 ⚠️
parallel-consumer-mutiny/src/test/java/bz/stub/parallelconsumer/mutiny/MutinyBatchTest.java

📄 parallel-consumer-mutiny/src/test/java/bz/stub/parallelconsumer/mutiny/MutinyBatchTest.java

File Similarity (%)
parallel-consumer-reactor/src/test/java/bz/stub/parallelconsumer/reactor/ReactorBatchTest.java 79.05 ⚠️
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/CoreBatchTest.java 50.21 ⚠️
parallel-consumer-vertx/src/test/java/bz/stub/parallelconsumer/vertx/VertxBatchTest.java 48.46
parallel-consumer-mutiny/src/test/java/bz/stub/parallelconsumer/mutiny/MutinyPCTest.java

📄 parallel-consumer-mutiny/src/test/java/bz/stub/parallelconsumer/mutiny/MutinyPCTest.java

File Similarity (%)
parallel-consumer-reactor/src/test/java/bz/stub/parallelconsumer/reactor/ReactorPCTest.java 70.87 ⚠️
parallel-consumer-mutiny/src/test/java/bz/stub/parallelconsumer/mutiny/MutinyUnitTestBase.java

📄 parallel-consumer-mutiny/src/test/java/bz/stub/parallelconsumer/mutiny/MutinyUnitTestBase.java

File Similarity (%)
parallel-consumer-reactor/src/test/java/bz/stub/parallelconsumer/reactor/ReactorUnitTestBase.java 32.07
parallel-consumer-mutiny/src/test/java/bz/stub/parallelconsumer/mutiny/TestConventionsArchTest.java

📄 parallel-consumer-mutiny/src/test/java/bz/stub/parallelconsumer/mutiny/TestConventionsArchTest.java

File Similarity (%)
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/TestConventionsArchTest.java 86.2 ⚠️
parallel-consumer-vertx/src/test/java/bz/stub/parallelconsumer/vertx/TestConventionsArchTest.java 85.96 ⚠️
parallel-consumer-reactor/src/test/java/bz/stub/parallelconsumer/reactor/TestConventionsArchTest.java 85.03 ⚠️
parallel-consumer-examples/parallel-consumer-example-core/src/test/java/bz/stub/parallelconsumer/examples/core/TestConventionsArchTest.java 82.64 ⚠️
parallel-consumer-examples/parallel-consumer-example-reactor/src/test/java/bz/stub/parallelconsumer/examples/reactor/TestConventionsArchTest.java 82.64 ⚠️
parallel-consumer-examples/parallel-consumer-example-vertx/src/test/java/bz/stub/parallelconsumer/examples/vertx/TestConventionsArchTest.java 82.64 ⚠️
parallel-consumer-examples/parallel-consumer-example-metrics/src/test/java/bz/stub/parallelconsumer/examples/metrics/TestConventionsArchTest.java 81.16 ⚠️
parallel-consumer-examples/parallel-consumer-example-streams/src/test/java/bz/stub/parallelconsumer/examples/streams/TestConventionsArchTest.java 81.16 ⚠️
parallel-consumer-reactor/src/main/java/bz/stub/parallelconsumer/reactor/ReactorProcessor.java

📄 parallel-consumer-reactor/src/main/java/bz/stub/parallelconsumer/reactor/ReactorProcessor.java

File Similarity (%)
parallel-consumer-mutiny/src/main/java/bz/stub/parallelconsumer/mutiny/MutinyProcessor.java 51.54 ⚠️
parallel-consumer-reactor/src/test/java/bz/stub/parallelconsumer/reactor/ReactorBatchTest.java

📄 parallel-consumer-reactor/src/test/java/bz/stub/parallelconsumer/reactor/ReactorBatchTest.java

File Similarity (%)
parallel-consumer-mutiny/src/test/java/bz/stub/parallelconsumer/mutiny/MutinyBatchTest.java 79.05 ⚠️
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/CoreBatchTest.java 51.81 ⚠️
parallel-consumer-vertx/src/test/java/bz/stub/parallelconsumer/vertx/VertxBatchTest.java 49.99
parallel-consumer-reactor/src/test/java/bz/stub/parallelconsumer/reactor/ReactorPCTest.java

📄 parallel-consumer-reactor/src/test/java/bz/stub/parallelconsumer/reactor/ReactorPCTest.java

File Similarity (%)
parallel-consumer-mutiny/src/test/java/bz/stub/parallelconsumer/mutiny/MutinyPCTest.java 70.87 ⚠️
parallel-consumer-reactor/src/test/java/bz/stub/parallelconsumer/reactor/ReactorUnitTestBase.java

📄 parallel-consumer-reactor/src/test/java/bz/stub/parallelconsumer/reactor/ReactorUnitTestBase.java

File Similarity (%)
parallel-consumer-mutiny/src/test/java/bz/stub/parallelconsumer/mutiny/MutinyUnitTestBase.java 32.07
parallel-consumer-reactor/src/test/java/bz/stub/parallelconsumer/reactor/TestConventionsArchTest.java

📄 parallel-consumer-reactor/src/test/java/bz/stub/parallelconsumer/reactor/TestConventionsArchTest.java

File Similarity (%)
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/TestConventionsArchTest.java 86.2 ⚠️
parallel-consumer-vertx/src/test/java/bz/stub/parallelconsumer/vertx/TestConventionsArchTest.java 85.96 ⚠️
parallel-consumer-mutiny/src/test/java/bz/stub/parallelconsumer/mutiny/TestConventionsArchTest.java 85.03 ⚠️
parallel-consumer-examples/parallel-consumer-example-core/src/test/java/bz/stub/parallelconsumer/examples/core/TestConventionsArchTest.java 82.64 ⚠️
parallel-consumer-examples/parallel-consumer-example-reactor/src/test/java/bz/stub/parallelconsumer/examples/reactor/TestConventionsArchTest.java 82.64 ⚠️
parallel-consumer-examples/parallel-consumer-example-vertx/src/test/java/bz/stub/parallelconsumer/examples/vertx/TestConventionsArchTest.java 82.64 ⚠️
parallel-consumer-examples/parallel-consumer-example-metrics/src/test/java/bz/stub/parallelconsumer/examples/metrics/TestConventionsArchTest.java 81.16 ⚠️
parallel-consumer-examples/parallel-consumer-example-streams/src/test/java/bz/stub/parallelconsumer/examples/streams/TestConventionsArchTest.java 81.16 ⚠️
parallel-consumer-vertx/src/main/java/bz/stub/parallelconsumer/vertx/JStreamVertxParallelEoSStreamProcessor.java

📄 parallel-consumer-vertx/src/main/java/bz/stub/parallelconsumer/vertx/JStreamVertxParallelEoSStreamProcessor.java

File Similarity (%)
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/JStreamParallelEoSStreamProcessor.java 42.51
parallel-consumer-vertx/src/main/java/bz/stub/parallelconsumer/vertx/VertxParallelEoSStreamProcessor.java 41.68
parallel-consumer-vertx/src/main/java/bz/stub/parallelconsumer/vertx/JStreamVertxParallelStreamProcessor.java 41.49
parallel-consumer-vertx/src/main/java/bz/stub/parallelconsumer/vertx/VertxParallelStreamProcessor.java 37.64
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/JStreamParallelStreamProcessor.java 34.88
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/ParallelEoSStreamProcessor.java 32.24
parallel-consumer-vertx/src/main/java/bz/stub/parallelconsumer/vertx/JStreamVertxParallelStreamProcessor.java

📄 parallel-consumer-vertx/src/main/java/bz/stub/parallelconsumer/vertx/JStreamVertxParallelStreamProcessor.java

File Similarity (%)
parallel-consumer-vertx/src/main/java/bz/stub/parallelconsumer/vertx/VertxParallelStreamProcessor.java 41.81
parallel-consumer-vertx/src/main/java/bz/stub/parallelconsumer/vertx/JStreamVertxParallelEoSStreamProcessor.java 41.49
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/ParallelStreamProcessor.java 35.57
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/JStreamParallelEoSStreamProcessor.java 33.22
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/JStreamParallelStreamProcessor.java 32.37
parallel-consumer-vertx/src/main/java/bz/stub/parallelconsumer/vertx/VertxParallelEoSStreamProcessor.java

📄 parallel-consumer-vertx/src/main/java/bz/stub/parallelconsumer/vertx/VertxParallelEoSStreamProcessor.java

File Similarity (%)
parallel-consumer-vertx/src/main/java/bz/stub/parallelconsumer/vertx/VertxParallelStreamProcessor.java 43.84
parallel-consumer-vertx/src/main/java/bz/stub/parallelconsumer/vertx/JStreamVertxParallelEoSStreamProcessor.java 41.68
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/internal/ExternalEngine.java 39.99
parallel-consumer-vertx/src/main/java/bz/stub/parallelconsumer/vertx/VertxParallelStreamProcessor.java

📄 parallel-consumer-vertx/src/main/java/bz/stub/parallelconsumer/vertx/VertxParallelStreamProcessor.java

File Similarity (%)
parallel-consumer-vertx/src/main/java/bz/stub/parallelconsumer/vertx/VertxParallelEoSStreamProcessor.java 43.84
parallel-consumer-vertx/src/main/java/bz/stub/parallelconsumer/vertx/JStreamVertxParallelStreamProcessor.java 41.81
parallel-consumer-vertx/src/main/java/bz/stub/parallelconsumer/vertx/JStreamVertxParallelEoSStreamProcessor.java 37.64
parallel-consumer-vertx/src/test-integration/java/bz/stub/parallelconsumer/vertx/integrationTests/VertxConcurrencyIT.java

📄 parallel-consumer-vertx/src/test-integration/java/bz/stub/parallelconsumer/vertx/integrationTests/VertxConcurrencyIT.java

File Similarity (%)
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/VeryLargeMessageVolumeTest.java 35.59
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/TransactionAndCommitModeTest.java 31.11
parallel-consumer-vertx/src/test/java/bz/stub/parallelconsumer/vertx/TestConventionsArchTest.java

📄 parallel-consumer-vertx/src/test/java/bz/stub/parallelconsumer/vertx/TestConventionsArchTest.java

File Similarity (%)
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/TestConventionsArchTest.java 87.14 ⚠️
parallel-consumer-mutiny/src/test/java/bz/stub/parallelconsumer/mutiny/TestConventionsArchTest.java 85.96 ⚠️
parallel-consumer-reactor/src/test/java/bz/stub/parallelconsumer/reactor/TestConventionsArchTest.java 85.96 ⚠️
parallel-consumer-examples/parallel-consumer-example-core/src/test/java/bz/stub/parallelconsumer/examples/core/TestConventionsArchTest.java 83.54 ⚠️
parallel-consumer-examples/parallel-consumer-example-reactor/src/test/java/bz/stub/parallelconsumer/examples/reactor/TestConventionsArchTest.java 83.54 ⚠️
parallel-consumer-examples/parallel-consumer-example-vertx/src/test/java/bz/stub/parallelconsumer/examples/vertx/TestConventionsArchTest.java 83.54 ⚠️
parallel-consumer-examples/parallel-consumer-example-metrics/src/test/java/bz/stub/parallelconsumer/examples/metrics/TestConventionsArchTest.java 82.05 ⚠️
parallel-consumer-examples/parallel-consumer-example-streams/src/test/java/bz/stub/parallelconsumer/examples/streams/TestConventionsArchTest.java 82.05 ⚠️
parallel-consumer-vertx/src/test/java/bz/stub/parallelconsumer/vertx/VertxBatchTest.java

📄 parallel-consumer-vertx/src/test/java/bz/stub/parallelconsumer/vertx/VertxBatchTest.java

File Similarity (%)
parallel-consumer-reactor/src/test/java/bz/stub/parallelconsumer/reactor/ReactorBatchTest.java 49.99
parallel-consumer-mutiny/src/test/java/bz/stub/parallelconsumer/mutiny/MutinyBatchTest.java 48.46
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/CoreBatchTest.java 44.73

@github-actions

github-actions Bot commented Aug 24, 2026 •

Copy link
Copy Markdown

⚠️ SpotBugs Report

302 bug(s) found (rule-level exclusions only - see docs/inflight/static-spotbugs-rule-registry.md). See the annotations on the Files Changed tab for details.

@github-actions

github-actions Bot commented Aug 24, 2026 •

Copy link
Copy Markdown

🧪🔒 Quarantine Lane Report

Quarantined test Outcome Owner Meaning
PCMetricsTest.metricsRegisterBinding 🟡🎲 passed (flapper) ⚠️ unowned proves nothing - passes most runs by nature
ProducerManagerTest.producedRecordsCantBeInTransactionWithoutItsOffsetDirect 🟡🎲 passed (flapper) #262 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.

astubbs added a commit that referenced this pull request Aug 25, 2026
Register item 13. bin/racerd-test.sh runs RacerD over parallel-consumer-core's main
code: opt-in, non-gating, following the Lincheck lane's precedent.

THE EARLIER "BLOCKED" VERDICT WAS WRONG, in a way worth recording. Infer's Maven
integration runs the build under a JDK of its own choosing while this project
requires 17 - correctly diagnosed with a two-arm control - and that was written up as
RacerD being blocked. It was not blocked. The documented alternative, capturing javac
directly and sidestepping the wrapper that picks the JDK, was simply never tried. A
tool that fails through one integration has not failed.

Thirteen findings from 73 files, in three groups.

PCMetrics.registeredMeters, four: the plain ArrayList mutated from two threads that
the Lincheck PoC turned up unprompted, already tracked and fixed by #57.
RacerD names all four mutating entry points statically, with no harness.

RetryQueue, seven: this.unique read via Map.size() and isEmpty() racing with writes,
and RetryQueueIterator.closed read against write. The Lincheck lane's own open-items
note ranks RetryQueue as the next thing to model and says it is not modelled at all,
and docs/refactoring.md separately names RetryQueue.closed as a current offender. One
corroboration plus six findings beyond it, in ground nothing else covers.

AbstractParallelEoSStreamProcessor.lastCommitTime, two, and this one is NEW. A plain
Instant written in one method and read unsynchronised by isTimeToCommitNow(). Checked
before claiming it: no inflight note, no refactoring.md entry, and the only mention
anywhere is a code excerpt inside an unrelated solutions write-up. It sits on the
commit-timing path in a repo that tracks commit-timeout flakes. Recorded, not fixed.

It does NOT find the four named torn-read races, and that is the wrong expectation
rather than a failure: #345 and #346 are check-then-act on a map and
#337 and #344 are two-read value divergence, while RacerD models
unguarded access to shared state. Different class. fb-contrib reaches the first pair.

No CI lane. Infer is a 220 MB toolchain published for linux-x86_64 and osx-arm64 only,
so its home is the self-hosted highcpu runner where it persists between runs - the
same argument the chaos and mutation sweeps already make. The script exits 2 for
"cannot run" rather than 0, so a missing toolchain can never read as "no races", and
that arm is verified.
astubbs added a commit that referenced this pull request Aug 25, 2026
`ShardManager.processingShards` is shared, unlocked, between the broker-poll thread
(which adds and removes shards) and the controller thread (which reads how much work is
queued). Both sides rely on the reference never moving - it is a ConcurrentHashMap and
identity was never expected to change. Swapping it is strictly worse than any torn read
of its contents: a reader holding the old reference keeps accounting work against a map
nothing will ever drain.

Two doors led to a replacement and nothing but review attention held either shut: the
Lombok `@Setter(AccessLevel.PACKAGE)`, whose only caller anywhere is `ShardManagerTest`,
and a direct assignment inside `ShardManager` that would bypass the setter entirely.
`ShardMapIsNeverReplacedArchTest` shuts both, main code only - tests may still install a
pre-populated map, which is the setter's whole purpose.

Mutation evidence, three arms, each predicted before it was run:

- a production caller of the setter added to `ShardManager` -> rule 1 red, rule 2 GREEN
  (the assignment is inside the setter, so only the call rule should see it);
- a direct `this.processingShards = ...` in a non-constructor method -> rule 2 red,
  rule 1 GREEN. Same magnitude, different position: each arm flips exactly one rule;
- both rules pointed at names that do not exist -> both rules PASS, having asserted
  nothing, and both reflective name-pins go red. That is the false-green the pins exist
  for, and it is now observed rather than assumed.

Reverted after each; green on arrival and green after.

The rule the build-hardening register asked for is NOT writable, which is the more
durable finding and is why that entry now reads as corrected rather than merely done. It
assumed `getShard(key)` was the idiom everywhere bar the one pair that NPE'd. It is not:
exactly one main-code access is `getShard`, nearly all the rest are bulk operations over
`values()` / `keySet()` that `getShard` cannot express, and the keyed ones that remain
include both writes. So "no direct access outside the accessor" is red on arrival, and
the only way to green it is an allowlist of the methods already there - a frozen baseline wearing a source-code
disguise, which is the trap `static-archunit-main-code-rules.md` exists to refuse.
Underneath that sits the granularity limit: ArchUnit sees a field ACCESS, never what is
invoked on the value that access loaded, so it could not have told a keyed lookup from a
bulk read even in principle. The check-then-get seam is fb-contrib's
MUI_CONTAINSKEY_BEFORE_GET, already Tier 1 in the SpotBugs registry, and #345 -
which fixes it - is still open, so that seam is on master today.

Also recorded: four `// visible for testing` accessors on `RetryQueue` and `ShardManager`
have zero callers in the whole tree, so an accessor rule over them would pass vacuously
forever. Queued for deletion in docs/refactoring.md rather than policed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GyqWU2v4hy7NGoxdrfqb74
astubbs added a commit that referenced this pull request Aug 25, 2026
The registry leads on MUI_CONTAINSKEY_BEFORE_GET naming ShardManager's
check-then-get seam, which is the strongest single argument for adopting fb-contrib.
#345 is open, not merged - the seam is on master, which is precisely why the
detector sees it - and when that PR lands the finding reports zero.

That does not weaken the case for the detector. It means the paragraph stops
describing a live finding and starts describing history, and a reader would go
hunting for a race that no longer exists. Recorded at the paragraph so whoever
notices the count change rewords it instead of doubting the tool.

Also merges the ArchUnit work, which established that register entry 8 was wrong
twice over: it asserted #345 was already merged, and its stated rule was not
expressible, because ArchUnit models a field ACCESS and never what is invoked on the
value that access loaded.
astubbs added a commit that referenced this pull request Aug 25, 2026
… seeing nothing

#356 flagged that this work's framing - "no static analysis this repo runs can see the
torn-read class" - is measurably too strong. It is, and it is over-strong in exactly the way this
PR already caught itself being once.

WHAT WAS ACTUALLY MEASURED, AND WHAT WAS CLAIMED. The measurement was stock SpotBugs at
`effort=Max`, which was the only static analysis the repo ran that day, reporting nothing on any of
the four calibration targets - including the nine-line textbook probe. The claim generalised that
one configuration to the whole tool class. #356 turns fb-contrib on and measured its
`MUI_CONTAINSKEY_BEFORE_GET` naming `ShardManager.removeWorkFromShardFor` statically, in seconds,
with no harness: #345's seam, and one of the four targets. Verified here independently rather
than taken on report - that method is a literal `processingShards.containsKey(shardKey)` followed by
`processingShards.get(shardKey)` with the result dereferenced, nothing held across the pair, so the
detector has a real shape to match and the finding is credible on inspection.

So the honest width is three of four, not four of four. #346's seam is a stale-check rather
than `containsKey`-before-`get`, and the two value-divergence torn reads are not what a
check-then-act detector looks for. What survives unqualified is the claim that actually carries the
lane: the seam fb-contrib names is one somebody had already found by hand, whereas the defect
Lincheck turned up was on nobody's list.

WHY THE SAME SHAPE TWICE. This PR's own headline result is that the WorkManager hit rate is
machine-dependent - 2.33% per iteration here against 0.69% on Antony's machine, a likelihood-ratio
test rejecting equality at p = 0.011 - so no single-machine calibration transfers. A rate measured
on one machine is not the rate; a family one analyser cannot see is not a family no analyser can
see. Both are a sample of one generalised to a population, and the second slipped through while the
first was being corrected.

WHERE EACH EDIT LANDS. `docs/testing.md` owns the Lincheck lane and is durable reference, so the
corrected width is stated there in place - it would otherwise be flatly false on master the moment
#356 lands, and #356 `depends on` this PR, so this one lands first.
`docs/plans/` is a dated record whose claims may not be rewritten
(`docs/citations.md`), so the plan doc keeps its claim and gains a flag beside it naming
`docs/testing.md` as the owner of the corrected version.

ALSO FIXED: THE PLAN DOC CONTRADICTED ITSELF ON THE MACHINE QUESTION. Its interim correction
paragraph read the 2-misses-in-8 / 0-in-8 split as "the signature of a bound sitting on the edge
rather than of a difference between machines", and then instructed the reader to read two tables
through that conclusion - which the 48-run fit later in the same section refutes with the
likelihood-ratio test. A reader who stopped at the first complete-looking statement got the finding
backwards. Restated as what the split actually shows: ambiguous alone, and settled by the fit as
both a marginal bound and a real difference between machines. No measurement changed.

No test or assertion changed, and the bound stays at 1,000 - the slower machine's refinement remains
open and Antony's call (`docs/inflight/test-lincheck-lane-open-items.md`). Lincheck lane re-run on
this tree to confirm the master merge left it intact: all five classes selected, 8 tests, fresh
surefire reports, green - which for these harnesses means Lincheck still finds every seam.

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

Adds Lincheck to `parallel-consumer-core` and calibrates it the only way that
means anything: against a master that still contained every torn-read bug found
by hand this month, asking whether Lincheck refinds them **unaided** - no seams
named, no latches, no ordering imposed.

It refound four, one of them off-list. The `WorkManager.handleFutureResult`
double lookup, the `ShardManager` check-then-get NPE and the
confluentinc#894 two-read all fell out in seconds. The encoder
tear came back HALF-FOUND and is not claimed: the model checker placed a switch
between the two reads once in eight attempts but never showed the range-top
divergence. And `PCMetrics.registeredMeters` - a plain `ArrayList` written from
two threads - was found **unprompted**, having been on nobody's list. That last
one is the result that matters, because it is evidence the lane finds seams
nobody named rather than only confirming seams somebody did.

Green currently means "Lincheck found the bug": each harness is
`assertThrows(LincheckAssertionError)` because the fixes have not merged. When
#337/#344/#345/#346 land the lane goes red **by
design**, and the remedy is flipping the affected harness to assert-no-failure -
never reverting a fix, never loosening a bound. That inversion is the point of
adopting it, and it is why the lane must stay non-gating.

`LincheckToolchainProbeTest` is a deliberately broken red control and it earned
its place immediately: the first run reported a clean pass against code that
cannot survive two threads, because `wiremock-jre8` pins ASM 9.4 while Lincheck
needs 9.6+, and its transformer failed per-class while reporting success. Every
calibration verdict would have read "not found". A detector without a red control
is a green lamp wired to nothing.

**Two false-green shapes in the lane's own tooling were found and closed.**
`bin/lincheck-test.sh` counted surefire reports from any previous run, so with
stale reports present a nonexistent test class "passed"; it now deletes matching
reports first. Then the guard that caught zero classes could not catch a *short*
roster - three of five harnesses could silently stop being selected and the lane
still printed a healthy number. It now pins the exact roster, and the number has
to be hand-written: a derived count cannot work, because a dropped tag removes
the class from both the run and the expectation, which cancel to green.

**A bound is a claim about one machine.** The committed `iterations(1_000)` was
originally justified by a point estimate from eight runs; forty more, fitted by
maximum likelihood over 48, moved it by a factor of two to 2.33%/iteration
(95% profile-likelihood interval 1.38-3.72%), and the independent-trials model is
validated by prediction rather than assumed - 17.7 misses predicted of 32 at a
starved `iterations(25)` against 18 observed. The finding that outlives the
number: the hit rate is **machine-dependent**, 0.69%/iteration on a second
machine against 2.33% here, with a likelihood-ratio test rejecting equality at
p = 0.011. So no single-machine calibration of a stress arm transfers, and
pricing that properly gates adding further harnesses. The bound for the slower
machine is deliberately left unset rather than guessed - inflating it to cover
the tail of an eight-sample estimate would be the same unfounded precision
pointing the other way.

Model checking is unavailable for now, established rather than assumed: it is
blocked by a Lombok `@EqualsAndHashCode(callSuper = true)` interaction, settled
by a two-arm control experiment that doubles as an upstream-fix tripwire, and by
replay non-determinism on the commit path. Two tripwire tests keep its viability
under watch instead of dropping it. Jabel's 17-source/8-bytecode split is a
non-issue, also established.

Corrections made rather than defended, both of the same shape - generalising from
one measurement. A claim that no static analysis can see this defect class was
measured with stock SpotBugs alone; fb-contrib's `MUI_CONTAINSKEY_BEFORE_GET`
does reach `ShardManager.removeWorkFromShardFor`, so the claim is narrowed. And
the ranked "where to point it next" led with `ProcessingShard`'s drifting
counter on the strength of a clamp commented `// in case of possible race
condition` - #336 measured it and there is no race, both
paths being single-threaded conditional mismatches. Recorded rather than quietly
dropped, because the wrong inference was made twice by reading a comment instead
of measuring.

The lane is excluded from every gating suite at all five points, verified rather
than asserted: a gating run selects zero Lincheck classes. Where to point it
next, led by the selection rule rather than a list, is in
`docs/inflight/test-lincheck-lane-open-items.md`.
astubbs and others added 7 commits August 26, 2026 04:45
…ole lane exits 1

`bin/lincheck-test.sh` asserts the exact number of harness classes selected, precisely so
a harness that silently stops being selected cannot pass as a healthy run. It expected 5.
There have been 6 tagged `@Tag("lincheck")` classes since `RetryQueueLincheckTest` arrived
with the RetryQueue off-lock fix, and that commit did not bump the pin - so
`bin/lincheck-test.sh` with no `LINCHECK_TEST` filter has exited 1 on master ever since,
after a green Maven run, printing "the lane selected the wrong roster".

Nothing caught it because nothing runs the lane: it is excluded from every gating suite
by design and no workflow invokes it, which
`docs/inflight/test-lincheck-lane-open-items.md` already records as an open item under
"Nothing runs the lane, so the tripwire it promises cannot fire". A guard whose only
caller is a human is exactly the guard that rots.

The hand-maintained number is deliberate and stays hand-maintained - the script's own
header explains why deriving it from a `grep` for the tag would make the guard blind to a
dropped tag, since the same absence removes the class from both the run and the
expectation. The friction IS the check; this is that friction being paid, late.

Verified: `bin/lincheck-test.sh` now exits 0, "Lincheck report files: 6", 9 tests across
6 classes green.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C3UK42akdtYuRgd7jSdcVk
…at fixing it unmasked

`ShardManagerLincheckTest` was the Lincheck lane's calibration arm for this branch's
defect: it asserted that Lincheck FINDS a violation and that the report contains
`NullPointerException`. This branch fixes that NPE, so the harness goes red - which the
lane's own commit predicted, naming this PR, and prescribed flipping to assert-no-failure.

THE PRESCRIBED FLIP DOES NOT PASS, measured rather than assumed. On the fixed tree
Lincheck still reports `= Invalid execution results =`, with no `NullPointerException`
anywhere in it. Controlled both ways in one sitting: revert only the main-code hunk and
the NPE counterexample comes back and the harness is green (BUILD SUCCESS); restore it
and the new counterexample appears (BUILD FAILURE on the `contains` assertion). So the
second violation was always there, masked because Lincheck stops at the first thing it
finds. Asserting no-failure would have been red on arrival; asserting nothing would have
been the vacuous green this lane exists to prevent.

The counterexample is `revokeSweep(0)` in the prefix, then `addWork(0)` against
`addWork(0)` in parallel - the `entries.get` / `entries.put` + `incrementAndGet`
check-then-act in `ProcessingShard.addWorkContainer`, i.e. the lane's own "concurrent
collection plus a derived counter" signature. NOT claimed as a product defect: production
registers work from the broker-poll thread alone, so two concurrent `addWork` calls are
not an interleaving the library can take today, and the harness declares an operation set
wider than the real thread model. That is a question about the harness's contract, and it
is recorded in `docs/inflight/test-lincheck-lane-open-items.md` rather than answered here.

So the harness asserts the strongest claim the evidence supports - that no report over
these operations mentions `NullPointerException` again - which makes it a real regression
detector for this fix instead of a calibration arm with nothing left to calibrate. The
method is renamed to say so; nothing outside the file cited the old name.

The note also narrows, rather than overturns, that file's existing ruling that
`ProcessingShard.availableWorkContainerCnt` is not a Lincheck target. That ruling rests on
#336 measuring the counter DRIFT as single-threaded conditional mismatches and it
stands; what is new is a machine-produced interleaving over the same field, arriving
unaided from a harness pointed somewhere else, which is a different claim.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C3UK42akdtYuRgd7jSdcVk
…ll belongs to which fix

This branch's own javadoc and code comment said the torn `containsKey`/`get` pair "sits
inside the guard that was itself added for confluentinc#757". It does not, and the record
is worth getting right because the next reader will use it to decide what is already
covered.

WHAT THE HISTORY SAYS. `git log -S` on the two guards:

- the `containsKey` test has been in `removeWorkFromShardFor` since upstream's 2022-01-15
  batching work (7e26075), two years before confluentinc#757 was filed;
- confluentinc#757 - "NullPointerException on partitions revoked", CLOSED - was fixed by
  upstream PR 758 (dc0b921, 2024-05-08), which added `Objects.nonNull(removedWC)` one
  line further down, against `retryQueue.remove(null)`, plus
  `ShardManagerTest.testAssignedQuickRevokeNPE` for it. That test installs a shard for the
  key, so `containsKey` is TRUE throughout: it never reaches the already-removed-shard
  branch at all.

So the method carries three nulls on one revoke path - already-removed WORK (757),
already-removed SHARD (2022), and the shard that was present for `containsKey` and gone by
`get` (this branch) - and only the first two were previously guarded. Same symptom family
as confluentinc#757, a different null, which is why the reference is still worth citing;
it just is not the guard this one sat inside.

Comments and javadoc only - no behaviour change, and both tests are unaffected.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C3UK42akdtYuRgd7jSdcVk
Four documents and two build files describe `MUI_CONTAINSKEY_BEFORE_GET` naming
`ShardManager.removeWorkFromShardFor` in the present tense. This branch deletes that seam,
so from the moment it lands the rule reports ZERO there and every one of those sentences
sends a reader hunting for a race that no longer exists.

`docs/inflight/static-spotbugs-rule-registry.md` asked for this in writing - "this finding
has a shelf life, and the note should not outlive it... somebody should reword it" - which
is the instruction this commit is answering. The wording now says what the detector found,
that it found it unaided and statically in seconds, and that reporting zero is the
expected state rather than the rule having gone quiet. The case for keeping fb-contrib on
is unchanged and is restated as forward-looking: the next instance of the shape is what it
is there to catch, and `LincheckToolchainProbeTest` remains the red control proving it
still fires.

`bin/check-branch-self-reference.sh` is what forces this at the one moment it is cheap:
the three `docs/inflight/` notes naming #345 all fail it after the merge, because a
note is a claim about NOW and this merge falsifies theirs. Each rewritten passage carries
`post-merge: checked` markers; the gate is green.

The other four sites are not gated by anything and would have rotted silently:
`pom.xml`'s fb-contrib justification, `config/spotbugs-exclude.xml`'s class-scoped
suppression rationale, `docs/testing.md`'s Lincheck-lane section, and the registry's own
"the one CLASS-scoped suppression" paragraph. The dated plan under `docs/plans/` is left
alone deliberately - it records a measurement taken on a tree that had the seam, and
`docs/citations.md` owns why those are not rewritten to match today's code.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C3UK42akdtYuRgd7jSdcVk
… all four fixes it binds

#345 and #346 each measured their own harness against a fixed tree and each wrote
the result into this note independently. The two accounts disagreed: the one written from
WorkManagerLincheckTest prescribed inverting ShardManagerLincheckTest alongside it, which the
other had already measured as red. Two adjacent sections, one of them falsified by the other.

Replaced by a single section that both branches carry byte-identically, so whichever lands first
the second merges it cleanly rather than conflicting - and there is one place to correct when the
remaining two fixes are measured.

What it now records that neither half did alone: the contract from #347 assumed one bug per
harness, and that assumption is what failed. A harness pointed at one seam explores the others, so
it can stop finding its own bug without becoming quiet - ShardManagerLincheckTest surfaces a
second violation with no NPE in it, WorkManagerLincheckTest passes while actually detecting
#345's NPE through an assertion that cannot tell the two apart. The falsified prescription
is kept as the argument for the rule rather than deleted: a harness's next assertion is not
derivable from its own diff.

It also names the half nobody has measured. PartitionStateLincheckTest is the harness #337
and #344 invert, it has never run against a tree carrying either fix, and its javadoc still
promises an inversion - so the obligation is on whoever lands any of the four to re-run the whole
lane, not only the harness their own PR is named for.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C3UK42akdtYuRgd7jSdcVk
… not fight over it

#345 and #346 each had to rewrite this paragraph - it named both PRs in the present
tense as unfixed, which bin/check-branch-self-reference.sh fails on each branch - and they wrote
two different replacements for the same four sentences. Whichever landed second would have
conflicted.

The kept wording is the one that does not need rewriting again: the blind spot is the CLASS, not
the instances, so which of the four are still open does not move what RacerD can see. Naming the
four by their fixing PRs keeps the citation valid after each lands, which is the property the
previous phrasing lacked.
astubbs added a commit that referenced this pull request Aug 26, 2026
The draft response listed the four sibling fixes as
`(#344, #345, #346, #349)` - qualified once and then
elided. `bin/check-issue-refs.sh` reads each reference on its own, so the three
elided ones are bare numbers below the threshold and it failed the branch.

Writing all four out in full is also what the drafts need on their own terms:
they are posted to GitHub, where the short `astubbs#NN` form does not autolink
either.
… not the poller

The shared Lincheck section argued that two concurrent addWork calls are unreachable because
"production registers work from the broker-poll thread alone". The conclusion holds and the
reason for it holds - exactly one thread registers - but the thread is misnamed.

Traced: BrokerPollSystem calls pc.registerWork, which only enqueues onto workMailBox. The
control thread reaches wm.registerWork after workMailBox.drainTo, inside
processWorkCompleteMailBox. So registration is the control thread's, and the poller never
touches ShardManager on that path.

It matters beyond pedantry because the paragraph exists to tell a future harness author which
operation set to model. A harness built against the wrong thread would constrain the wrong
operations and reproduce nothing. The correction is left visible in the text rather than
silently swapped, so a reader who met the old claim elsewhere can see it was retired - the same
sentence is in commit 3ba30db's body, which is not rewritable now that reviews are open.

Applied byte-identically on #345 and #346, so
the two branches keep merging cleanly in either order.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C3UK42akdtYuRgd7jSdcVk
astubbs added a commit that referenced this pull request Aug 26, 2026
… and two notes had to read post-merge

Three repairs the merge with master made necessary, none of them behaviour changes.

THE INVERSION THIS BRANCH WAS INSTRUCTED TO DO IS BLOCKED, AND THAT IS MEASURED.
#347's commit body says the Lincheck lane goes red by design when this fix lands
and "the remedy is flipping the affected harness to assert-no-failure". Run against the
merged tree - LINCHECK_TEST=WorkManagerLincheckTest bin/lincheck-test.sh, 2m05s - and
Lincheck still reports a violation, so the harness never goes red. It is a DIFFERENT
violation: the checkpoint-3 signature (PartitionState.onSuccess's
assert removedFromIncompletes, thrown out of completeWork) is gone, and what surfaces is
#345's NullPointerException from ShardManager.removeWorkFromShardFor, reached
through the same revokeAndReassign operation. The harness's own assertion cannot separate
them: contains("completeWork") matches the interleaving table, which names both operations
whichever one threw.

So the fix IS confirmed by the harness - just not by its assertion. Neither remedy works
while #345 is open. Asserting no violation goes red on a defect this branch does not
fix; asserting the checkpoint-3 signature also goes red, correctly, and would not be a
durable pin either, since Lincheck stops at the first violation and which of the two it
reaches is not ordered. Recording the override rather than performing it, per the
inherit-and-override rule: the inversion belongs in the change that lands #345,
together with ShardManagerLincheckTest's. The measurement and the two rejected moves are in
docs/inflight/test-lincheck-lane-open-items.md; the harness javadoc, which said this test
would go red, now says what actually happens and points there.

TWO INFLIGHT NOTES DESCRIBED THIS BRANCH'S SEAM AS LIVE. check-branch-self-reference.sh
fails on them once master is merged in, which is the moment it is designed to fire -
static-infer-findings.md and static-spotbugs-rule-registry.md both stated in the present
tense that this seam is on master and unfixed. Both rewritten to read correctly after this
merges and marked post-merge: checked. The infer one gains the reason its claim survives
the fix at all: RacerD's blind spot is the defect class, so which instances are still open
does not move it.
astubbs added a commit that referenced this pull request Aug 26, 2026
… all four fixes it binds

#345 and #346 each measured their own harness against a fixed tree and each wrote
the result into this note independently. The two accounts disagreed: the one written from
WorkManagerLincheckTest prescribed inverting ShardManagerLincheckTest alongside it, which the
other had already measured as red. Two adjacent sections, one of them falsified by the other.

Replaced by a single section that both branches carry byte-identically, so whichever lands first
the second merges it cleanly rather than conflicting - and there is one place to correct when the
remaining two fixes are measured.

What it now records that neither half did alone: the contract from #347 assumed one bug per
harness, and that assumption is what failed. A harness pointed at one seam explores the others, so
it can stop finding its own bug without becoming quiet - ShardManagerLincheckTest surfaces a
second violation with no NPE in it, WorkManagerLincheckTest passes while actually detecting
#345's NPE through an assertion that cannot tell the two apart. The falsified prescription
is kept as the argument for the rule rather than deleted: a harness's next assertion is not
derivable from its own diff.

It also names the half nobody has measured. PartitionStateLincheckTest is the harness #337
and #344 invert, it has never run against a tree carrying either fix, and its javadoc still
promises an inversion - so the obligation is on whoever lands any of the four to re-run the whole
lane, not only the harness their own PR is named for.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C3UK42akdtYuRgd7jSdcVk
astubbs added a commit that referenced this pull request Aug 26, 2026
… not fight over it

#345 and #346 each had to rewrite this paragraph - it named both PRs in the present
tense as unfixed, which bin/check-branch-self-reference.sh fails on each branch - and they wrote
two different replacements for the same four sentences. Whichever landed second would have
conflicted.

The kept wording is the one that does not need rewriting again: the blind spot is the CLASS, not
the instances, so which of the four are still open does not move what RacerD can see. Naming the
four by their fixing PRs keeps the citation valid after each lands, which is the property the
previous phrasing lacked.
@astubbs
astubbs deleted the fix/revoke-sweep-npe-on-racing-shard-removal branch August 26, 2026 13:32
astubbs added a commit that referenced this pull request Aug 26, 2026
…-of-family findings their own notes

The encoder fix in the preceding commit came out of a three-way audit of the
commit path, the state managers, and shards/retry/metrics. This commit is
that hunt's durable record, kept separate because it is not the fix's
paperwork - most of it outlives the fix and some of it is about defects the
fix does not touch.

bug-torn-read-family.md states the family precisely (multiple reads of moving
shared state within one logical operation, combined as though they were one
consistent snapshot), carries the three surviving candidates with their
control arms, and records the encoder seam's own residual - including that
the reset window and the dirty-encode window are temporally disjoint by
construction, which is the argument that makes this family's remaining
exposure decidable without waiting on another PR.

FOUR OUT-OF-FAMILY DEFECTS GET THEIR OWN NOTES, and that is the point of the
split rather than tidiness. They were a paragraph inside a dossier whose own
closing instruction is to delete it when the family's work lands - which
would have taken four still-open defects with different owners and lifecycles
with it - and a paragraph cannot be found by anyone listing the directory:
async commit marked successful before broker ack; the unsynchronised
cross-thread counter maps; the resetOffsetMapAndRemoveWork NPE on a
partial-assignment path; and BrokerPollSystem's racy public pause API, which
has zero main-code callers and so is latent rather than live. Each names its
own consequence and points at an existing owner where one exists.

The dossier's hard-coded dismissal tally is gone, replaced by the five
dismissal shapes and a grep that re-derives the set. The audit's report
artifacts are not durable and no command recomputed the number, so it would
have become misleading as candidates were fixed - which is what
docs/inflight/AGENTS.md's counts rule exists to prevent, and which fires
hardest exactly when writing up a measurement just taken.

The Lincheck/jcstress evaluation note is deleted rather than kept as a record
of finished work: both arms executed and were adopted (#347,
#348), so keeping it would have been the FIXED/DONE narrative that
directory forbids, and without an inflight-state the session index kept
presenting it as open. It never reached master, so there is no commit to
point a history pointer at; both dated plans that cite it say so plainly and
name the successor notes, which is what docs/citations.md prescribes when an
item did not survive the move.

Also recorded: the offset-decode test helper is copy-pasted seven times
across two packages. The duplicate-code bot flagged one pair of them; the
pair is not the finding. Extraction is a seven-file change that does not
belong in a concurrency fix, so refactoring.md carries it with every site
named, kept distinct from the racing-double unification the dossier tracks -
that one is about the two Racing*State doubles, this is about the helper, and
conflating them would send the next reader at the wrong mechanism.

release-0.6.0.0.md gains the correctness campaign as announcement material:
five concurrency defects sharing one root shape found in a week, two of them
silent record loss present in every released 0.5.x line, each reproduced
deterministically with control arms.

#345 merged while this branch was being re-cut, so candidate 2 is
marked FIXED rather than "fix before the release" - the dossier would
otherwise have reached master already stale about a fix that is on it.
astubbs added a commit that referenced this pull request Aug 26, 2026
…p fix

The only conflict is the 857 ledger, where master and this branch each appended
a dated section - both are kept, in the order they happened. `ShardManager`
auto-merged: #345 rewrote `removeWorkFromShardFor` to the single-read
`getShard(key)` idiom, which is the method that calls `ProcessingShard#remove`
and therefore the `uncount` this branch added. The two changes are orthogonal -
#345 fixes WHICH shard reference the sweep operates on, this branch fixes
what removing an entry does to the count - and the merged form is right without
adjustment: a detached shard still accounts its own removal correctly, because
the counter it moves is its own.

Worth stating because it was NOT obvious from the clean auto-merge: this branch
is why `getNumberOfWorkQueuedInShardsAwaitingSelection`'s read-order comment
differs from master's, and that hunk landing beside #345's changes in the
same file is coincidence rather than interaction.

The PR was CONFLICTING while this sat unmerged, which is why GitHub ran no
`pull_request` workflow against the last two heads - the checks were not failing,
they were never dispatched.
astubbs added a commit that referenced this pull request Aug 26, 2026
…-of-family findings their own notes

The encoder fix in the preceding commit came out of a three-way audit of the
commit path, the state managers, and shards/retry/metrics. This commit is
that hunt's durable record, kept separate because it is not the fix's
paperwork - most of it outlives the fix and some of it is about defects the
fix does not touch.

bug-torn-read-family.md states the family precisely (multiple reads of moving
shared state within one logical operation, combined as though they were one
consistent snapshot), carries the three surviving candidates with their
control arms, and records the encoder seam's own residual - including that
the reset window and the dirty-encode window are temporally disjoint by
construction, which is the argument that makes this family's remaining
exposure decidable without waiting on another PR.

FOUR OUT-OF-FAMILY DEFECTS GET THEIR OWN NOTES, and that is the point of the
split rather than tidiness. They were a paragraph inside a dossier whose own
closing instruction is to delete it when the family's work lands - which
would have taken four still-open defects with different owners and lifecycles
with it - and a paragraph cannot be found by anyone listing the directory:
async commit marked successful before broker ack; the unsynchronised
cross-thread counter maps; the resetOffsetMapAndRemoveWork NPE on a
partial-assignment path; and BrokerPollSystem's racy public pause API, which
has zero main-code callers and so is latent rather than live. Each names its
own consequence and points at an existing owner where one exists.

The dossier's hard-coded dismissal tally is gone, replaced by the five
dismissal shapes and a grep that re-derives the set. The audit's report
artifacts are not durable and no command recomputed the number, so it would
have become misleading as candidates were fixed - which is what
docs/inflight/AGENTS.md's counts rule exists to prevent, and which fires
hardest exactly when writing up a measurement just taken.

The Lincheck/jcstress evaluation note is deleted rather than kept as a record
of finished work: both arms executed and were adopted (#347,
#348), so keeping it would have been the FIXED/DONE narrative that
directory forbids, and without an inflight-state the session index kept
presenting it as open. It never reached master, so there is no commit to
point a history pointer at; both dated plans that cite it say so plainly and
name the successor notes, which is what docs/citations.md prescribes when an
item did not survive the move.

Also recorded: the offset-decode test helper is copy-pasted seven times
across two packages. The duplicate-code bot flagged one pair of them; the
pair is not the finding. Extraction is a seven-file change that does not
belong in a concurrency fix, so refactoring.md carries it with every site
named, kept distinct from the racing-double unification the dossier tracks -
that one is about the two Racing*State doubles, this is about the helper, and
conflating them would send the next reader at the wrong mechanism.

release-0.6.0.0.md gains the correctness campaign as announcement material:
five concurrency defects sharing one root shape found in a week, two of them
silent record loss present in every released 0.5.x line, each reproduced
deterministically with control arms.

#345 merged while this branch was being re-cut, so candidate 2 is
marked FIXED rather than "fix before the release" - the dossier would
otherwise have reached master already stale about a fix that is on it.
astubbs added a commit that referenced this pull request Aug 26, 2026
…its green is

#347 committed this harness asserting the checkpoint-3 tear EXISTS, naming this fix as the
one that inverts it. The previous head could not: #345's NullPointerException out of
ShardManager.removeWorkFromShardFor was reached through the same revokeAndReassign operation, and
`assertThat(report).contains("completeWork")` cannot tell one from the other. #345 has landed,
so that blocker is gone and the lane was re-run rather than reasoned about, as
docs/inflight/test-lincheck-lane-open-items.md requires.

MEASURED, on this tree, at the committed iterations(1_000):

  - Seven valid runs, every one exhausting the whole bound with no violation, 120.3s-143.1s. A hit
    used to land in 9-13s, so none of these is a near miss. The designed-red arm therefore fails
    every run and cannot stay as it is.
  - CONTROL, the same sitting: a compiling mutant that re-resolves the partition state at
    handleFutureResult's two action sites - the checkpoint-3 tear put back, nothing else changed -
    hit ONCE IN SIX runs. The hit is exactly the calibrated signature: AssertionError at
    PartitionState.onSuccess, through PartitionStateManager.onSuccess and WorkManager.onSuccessResult
    out of handleFutureResult, completeWork racing revokeAndReassign, and no NullPointerException
    anywhere. So the harness still reaches its seam - it has not gone quiet.

The honest reading of those two together, which the javadoc now carries: seven clean runs is WEAK
evidence of absence when the positive control itself misses five runs in six. What pins this fix is
WorkManagerStaleCheckDoubleLookupTest, which forces the interleaving deterministically; the Lincheck
arm is a search running beside it, and a pass here must never be read as a proof.

So: renamed to stressMustNotRediscoverTheCheckpointThreeTear and flipped to Lincheck's own
linearizability check, the shape RetryQueueLincheckTest already uses. The bound is left exactly where
it was measured - re-pricing needs the starve-and-count procedure the note prescribes, and neither
raising nor lowering it on this handful of runs would be better founded than the estimate it
replaces.

THE COST, because it is now the lane's largest number. An inverted arm cannot stop at a first
violation, so it always pays its whole bound: this arm is ~2 minutes every run and the whole lane
went from 26-29s to 2m32s-2m37s (measured twice, green both times). bin/lincheck-test.sh's header and
docs/testing.md said "well under a minute" and now say what it costs.

THE OTHER HARNESSES, re-checked in the same sitting as that rule requires:

  - ShardManagerLincheckTest is unchanged by #335 landing - same counterexample the note
    records, revokeSweep(0) then addWork(0) against addWork(0). Nothing in the note's item 1 moves.
  - PartitionStateLincheckTest has now been run against a tree carrying #337's fix for the
    first time, and does NOT invert. It still reports a violation naming commit(), but the report is
    not stable between runs - mostly a value divergence between commit() and succeed(), once an
    ArrayIndexOutOfBoundsException out of two concurrent commit() calls printed with no frames.
    #344 remains its trigger; recorded as a sighting, not a finding.
  - RetryQueueLincheckTest and both toolchain controls green and unchanged - the model checker is
    still blocked on the Lombok callSuper defect, so the note's item 8 arms are still not free.

docs/testing.md's "every harness asserts a bug EXISTS" bullet was already wrong before this change
(RetryQueueLincheckTest never did, ShardManagerLincheckTest stopped when #345 landed); it now
names the three shapes in the lane and why the third exists.
astubbs added a commit that referenced this pull request Aug 26, 2026
…a copy each

The duplicate-code check flagged 22 lines shared between this branch's
WorkManagerStaleCheckDoubleLookupTest and ShardManagerRevokeSweepNpeTest, which arrived on master
with #345. The clone is this PR's to remove: the other half was already on the base branch.

Both needed the same fixture - assign the partition, register one record through the production
path, take it as work - and both had asserted the same thing about it, that exactly one container
comes back. Extracted verbatim to ModelUtils.registerOneRecordAndTakeIt, which is where this
package's shared model helpers already live, rather than a third copy or a new utility class.

Static and taking the work manager, because neither caller can use the module's own: one installs a
WorkManager subclass that fires a rebalance inside the staleness seam, the other a ProcessingShard
map that fires a completion between two reads. The shard-map caller keeps its own one-line wrapper,
since its double must be installed BEFORE the assignment that creates the shard.

The size assertion moves with the body deliberately. It is a property of the fixture, not of either
test: a scenario that silently registered zero selectable records would make both reproductions
vacuous, which is exactly the failure mode a drifted copy would introduce on one side only.

Core unit suite green on the result: 437 tests, 0 failures, 8 pre-existing skips.
astubbs added a commit that referenced this pull request Aug 26, 2026
…efore its log expires

`ChaosChurnStormIT.churnStormMeetsSlosAndBalancesLedger` was killed fail-fast by
the probe on this branch's CI, with the same `ZOMBIE_MEMBER/REBALANCE_BLOCKED`
autopsy as the fourth, fifth and eighth entries in the family ledger - a group
dwelling the full 15s bound in PreparingRebalance with a member not answering the
protocol, and the whole assignment frozen for well over two minutes rather than a
single shard.

Recorded now because the ledger's own closing argument applies exactly: the
sighting is easy to lose. The red belongs to a head that will not be the tip for
long, the log expires, and the seed goes with it - which is how the entry above
this one describes #345 losing its capture entirely.

THE REASON THIS ONE IS NOT JUST ANOTHER TALLY MARK. Every previous capture of
this arm predates the dispatch ceiling, which landed on master hours before this
run. The commit immediately after the ceiling says in its own body that a leaked
dispatch permit now takes the engine to a full stop rather than a stuck record,
and a member that has stopped answering the rebalance protocol is what that would
look like from outside. So the old intermittency and a new cause are both
consistent with this autopsy, and the probe output cannot separate them.

The entry says what would settle it, since nothing here does: replay the recorded
seed at the ceiling commit and at its parent. Same seed, different position, which
is the control this file keeps asking for and rarely gets.

No test is quarantined and no assertion is touched. This commit adds a record and
nothing else - the failing test is left failing, because a flake that fails the
build is the deliberate design and the lever for changing that is quarantine with
evidence, not a retry.
astubbs added a commit that referenced this pull request Aug 26, 2026
…d PartitionStateLincheckTest still does not invert

Merging master brought #344 in beside #337, so both fixes the contract named for
PartitionStateLincheckTest are now in one tree. The rule that note carries is re-run the lane and
re-read EVERY harness's assertion, not only your own, so this is that re-run.

MEASURED, whole lane green (2m41s), and the harness does NOT invert. It reports a violation on every
run and `assertThat(report).contains("commit()")` still passes - on reports about neither tear it
names, because the interleaving table names commit() whatever threw. Two shapes recur across runs:

  - ArrayIndexOutOfBoundsException out of ArrayList.add, i.e. the plain-ArrayList defect #57
    fixes. The note recorded this as a frameless sighting one revision ago; it now has a frame
    naming it, so the lane has re-found it from a second harness pointed elsewhere.
  - PartitionState.onSuccess's assert, reached from two `succeed` operations in parallel - which
    production cannot perform, because only the control thread completes work.

The second shape is the same artefact-or-defect question the note already parks over
ShardManagerLincheckTest's addWork, arriving now in a second harness. If it is the artefact the fix
is a non-parallel group over `succeed`, not a change to PartitionState. That decision is open, this
arm's next assertion depends on it, and it should be taken for BOTH harnesses at once - so it is
recorded rather than guessed at here.

What IS fixed here is the javadoc, which until now told readers this arm would invert when
#344 landed, and the note, which said #344 was still its outstanding trigger. Both are
now false and both said so confidently. The javadoc also states plainly that this arm does not pin
#337 or #344 - PartitionStateCommitEncodeShift894Test and
OffsetEncoderWidenedRangeRaceTest do - so nobody reads its green as covering them.

The contract's per-PR trigger list is now fully spent, and it went 0 for 4 on its predictions: three
harnesses were left finding something other than the bug named, and the fourth inverted only once
BOTH violations reachable through its operations were gone. The instruction was right; the
one-bug-per-harness assumption behind it was not.

Also settles the self-reference bug-torn-read-family.md now demands of this PR. That note arrived on
master with the hunt's record and maps merges to sections; its #346 line is rewritten in the
post-merge terms the #345 line already uses, and says why the candidate sections stay - the
note remains open for the out-of-family stragglers, the #57 trigger and the next hunt
iteration.

Verified on the merged tree: core unit 451 tests / 0 failures / 8 pre-existing skips, full-reactor
test-compile green, bin/check-all.sh 15/15, bin/infer-test.sh "all 22 finding(s) are known, none
new", Lincheck lane green.
astubbs added a commit that referenced this pull request Aug 26, 2026
…at held is the interesting case

Self-correction on the claim the previous commit wrote into this note. WorkManagerLincheckTest DID
invert when its named trigger landed, so "0 for 4" overstates the failure and understates the more
useful finding: it held only because #345 had already removed the other violation reachable
through the same revokeAndReassign operation. Had the two landed in the other order the prediction
would have failed as well, which is a sharper statement of the same one-bug-per-harness assumption
than a bare miss count.
astubbs added a commit that referenced this pull request Aug 26, 2026
…, closing a stall and a wrong-commit route (#346)

WorkManager.handleFutureResult's staleness checkpoint 3 validated one partitionStates.get(tp)
lookup and acted on another. Nothing serialises the two against the broker-poll thread, so a
revoke(+reassign) completing in the gap meant the check passed against the OLD state object while
the actions ran against its replacement. Both harms were reproduced deterministically before any
fix:

- FAILURE PATH, a confluentinc#857-family permanent stall. The stale container was re-queued into
  the retry queue AFTER the revoke sweep had emptied its shard. removeStaleContainers reaches
  retry-queue entries only through shard contents, so nothing could remove the orphan again; once
  its retry delay elapsed, workIsWaitingToBeProcessed() read true forever with nothing assigned.
- SUCCESS PATH, the only production route into a wrong commit. The completion landed on the freshly
  assigned state, tripping PartitionState.onSuccess's assert under -ea; without -ea it silently
  dirtied a bootstrap-phase state with a dead epoch's completion, which was the gate-opener making
  the bootstrap-reset commit tear reachable.

THE FIX ACCEPTS THAT NO EPOCH CHECK HERE CAN BE ATOMIC WITH THE ACTIONS, and makes the actions safe
by construction instead. The state is resolved ONCE and the staleness answer shares that reference
with the success action, so a completion can only ever mutate the state object whose epoch matched
the container; a concurrently revoked object is already unlinked from the live map, so the write is
invisible to the commit path and the record is redelivered to the partition's next owner.
At-least-once holds in every interleaving. The failure path additionally re-validates against the
LIVE map immediately before the retry re-queue, because that action targets ShardManager structures
the revoke sweep cleans and no captured PartitionState reference can protect; skipping the re-queue
is the safe direction. PartitionStateManager.onSuccess/onFailure now take the caller-resolved state
- WorkManager was their only production caller, and the single-arg overloads that did their own
second lookup are reached from tests alone.

HONEST RESIDUAL, FAILURE PATH ONLY. The re-queue re-validation is still check-then-act, shrunk from
a whole-checkpoint gap a deterministic revoke reproducibly fit inside to a one-context-switch
sliver. The class-level closure is the retryQueue sweep tracked in
docs/inflight/bug-retry-queue-orphaned-by-inline-stale-removal.md. The success path has no residual.

CONTROLS, run rather than assumed. WorkManagerStaleCheckDoubleLookupTest, five tests: both race arms
red on the unfixed tree and green fixed, both serialized control arms green on both, so the failures
belong to the interleaving and not the mutation. A mutant re-resolving the state at the action sites
flips exactly the success arm and the bootstrap-gate probe red; deleting the re-queue re-validation
flips exactly the failure arm red; deleting a test's arm call fails its raceHasFired guard, so the
seam cannot go silently dead.

THE LINCHECK INVERSION IS DISCHARGED, AND THE MEASUREMENT SAYS DO NOT TRUST IT ALONE.
#347 committed WorkManagerLincheckTest asserting the tear EXISTS, to be
inverted when this landed. On the fixed tree it missed all seven runs, each exhausting 1000
iterations - but a control carrying the defect re-introduced hit only once in six, producing exactly
the checkpoint-3 signature and no NullPointerException now that #345 has
landed. So the harness still reaches its seam and is simply a poor detector at this bound: seven
clean runs is weak evidence of absence. The arm is inverted, the bound left where it was measured,
and the javadoc and note both say the deterministic test is what pins this fix. The inverted arm
cannot exit early, so the lane went from about 27s to about 2m35s - corrected in
bin/lincheck-test.sh's header and docs/testing.md, which both claimed well under a minute.

THE CONTRACT'S ONE-BUG-PER-HARNESS ASSUMPTION IS DEAD, and PartitionStateLincheckTest is now a
VACUOUS GREEN. With #337 and #344 both landed it still passes
contains("commit()") - on reports about neither tear it names, because the interleaving table names
commit() whatever threw. Two shapes recur: an ArrayIndexOutOfBoundsException out of ArrayList.add,
the plain-ArrayList defect #57 fixes, which the lane has now re-found from
a second harness pointed elsewhere and with a frame this time; and PartitionState.onSuccess's assert
reached from two parallel succeed operations, which production cannot perform because only the
control thread completes work. Whether that second shape is artefact or defect is the same question
already parked over ShardManagerLincheckTest's addWork, and it should be settled for both harnesses
at once and AFTER #57 lands, since that PR removes one of the two shapes.
Recorded rather than guessed at; the assertion is deliberately not re-pointed here.

ALSO IN THIS CHANGE. The infer ratchet's gone-arm fired on WorkManager.onFailureResult; a three-tree
control with pinned Infer v1.3.0 showed Pulse re-attributing an unchanged deref, with the identical
shape in the neighbouring overload reported at neither head, so the line is deleted rather than a
guard added. The same commit pins -encoding UTF-8 on the lane's hand-rolled javac, which had been
inheriting the developer locale and made bin/infer-test.sh exit 2 under LANG=C. The duplicate-code
thread is closed by extracting the shared fixture to ModelUtils.registerOneRecordAndTakeIt.
WorkManager's pm and sm fields carry TODO(refactor) markers plus a docs/refactoring.md entry for the
rename raised in review, not folded in here because both are @Getter(PUBLIC) and it would reach main,
unit and integration sources far outside this seam.

A CHAOS RED ON THE WAY THROUGH, DIAGNOSED AND RECORDED RATHER THAN RE-RUN.
ChaosRevokeUnderWorkDrainIT failed once with the AB-BA revoke-path monitor block - the poll thread
BLOCKED on the commitCommand AtomicBoolean held by its own pc-control thread, through
onPartitionsRevoked - which is master-state and not this change's: the diff touches no locking and no
AbstractParallelEoSStreamProcessor line, and the three earliest captures predate
#335's merge with the identical monitor, holder and method pair. Filed as
the fifth capture in docs/inflight/bug-857-family.md. The lag-stagnation observations in the same run
were non-gating, so the CLASS2 demotion held. Nothing was quarantined, loosened, or re-run to hide it.

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
astubbs added a commit that referenced this pull request Aug 27, 2026
…than the ledger counts, and a testable lead on the last unexplained line

Reading the merged commit bodies rather than the family's own summary, #119's
`## Fork status` is badly out of date. It says three defects landed and one remains.
At least six more have landed since, none of them in the family's accounting:

- **#346** orphaned a retry-queue entry when a rebalance landed between a
  staleness checkpoint and its acting read, after which `workIsWaitingToBeProcessed()`
  read TRUE FOREVER. Its own body calls that a confluentinc#857-family permanent
  stall. Red-then-green on both arms, mutation-tested.
- **#345** NPEd the broker-poll thread inside the rebalance listener via a
  `containsKey`-then-`get` race. Poller death under KEY ordering is paused
  consumption by another name.
- **#373** found a sign-reversed overcount its body names the
  "confluentinc#857 stall signature".
- **#336** rewrote the load gate whose drift kept intake paused.
- **#344** let the offset encoder mark still-incomplete offsets complete.
- **#349** fenced a cross-thread `dirty` flag, jcstress-measured.

The bucket has been drained steadily from several directions and nobody re-totalled.
That is the substantive reason #119 cannot be closed by reading this PR alone,
and why its fork-status section needs rewriting rather than appending to.

**A prediction is recorded for the one line still unexplained.** The
`ChaosChurnStormIT` `NO_PROGRESS` sightings are all `PERIODIC_CONSUMER_ASYNCHRONOUS`,
the mode where neither the AB-BA cycle nor the transactional wait can occur - which
is why they were set aside as a possible fourth defect. #344's defect is live
in that mode and only that mode, and its consequence - offsets marked complete while
incomplete - has the `NO_PROGRESS` shape. So: replay the three async seeds either
side of #344; if the mode match is the mechanism the pre arm reproduces and
the post arm does not.

Stated as a prediction rather than a finding, with its own counter-example beside it:
#373 was already tested against this arm on a mode-matching hypothesis and
fired anyway on that branch's own head. One plausible fix has failed here before.
astubbs added a commit that referenced this pull request Aug 27, 2026
…d gone out of date in eight ways

The ledger is where agents log a sighting and move on, and where the next one reads
before forming a hypothesis - so conclusions reached elsewhere are worth nothing
until they land here. A week of findings had accumulated in a PR note that gets
DELETED when that PR merges. Migrated.

What the ledger now says that it did not:

- Its own "three landed, one open" summary is stale. At least six more family
  defects have landed - #346, #345, #373, #336, #344, #349 - and none was
  counted. The bucket has been drained from several directions and nobody
  re-totalled.
- The original deadlock is VERIFIED rather than diagnosed: an A/B on the
  deterministic probe, one term changed, control failing every repetition and the
  fix failing none while logging the contended decline throughout.
- Replaying captured seeds does not reproduce that deadlock and should not be
  attempted again - the window opened zero times locally on either assignor arm, and
  two write-ups were retracted the same day for reading a green replay as evidence.
- The async line has its first replayable seed, found by random hunting rather than
  replay, and #344 is refuted as its explanation.
- A third of those failures went red with the NO_PROGRESS detector silent, which
  matters because the Class 2 demotion left the liveness claim resting on it.
- The symptom is a bucket of at least four distinguishable behaviours, separated by
  upstream's own maintainer in one sentence, plus a fifth reported on #29 and
  never chased - a pause with no rebalance in the logs at all.
- Upstream's own fix for this issue shipped, is carried here, and did not hold.
- confluentinc#875 is filed in this family on a third party's assumption and looks
  like an offset-completion defect instead.

Also records why a single beefier Docker host beats a distributed rig for the soak
harness beyond sequencing: central log shipping comes free, and any node can be
inspected AT RUNTIME while still wedged. Every sighting in this family that became a
mechanism did so because something captured the process while it was stuck; every
one that stayed a signature did not.
dhoard pushed a commit to dhoard/parallel-consumer that referenced this pull request Aug 30, 2026
…he sweep tool a mode that could have caught it (astubbs#258)

* docs(upstream-map): track the 28 issues closed by the 2023 admin sweep

Upstream ran two bulk clearouts before going quiet, and neither was a triage:
2023-06-15 `eddyv` closed 35 unmerged PRs with "Closing - Stale." (34 of them
ours), and 2023-07-07 `johnbyrnejb` closed 28 issues with "Closing Issue" -
every one marked COMPLETED rather than "not planned".

That state reason is why the cohort was invisible. GitHub renders `completed`
as resolved, so the issues read as done at a glance, and `upstream-sweep.sh`
searches `updated:>=last_swept`, so anything last touched in 2023 can never
appear in a sweep. None of the 28 were in this manifest; the mirroring that
produced the other 78 fork mirrors only ever sampled *open* upstream issues.

All 28 were re-read in full - bodies plus all 58 comments - and each verified
against fork source rather than trusted from its thread. That mattered: four
issue bodies point at PRs that "fix" them (astubbs#372->astubbs#390, astubbs#319->astubbs#270, astubbs#203->astubbs#345,
astubbs#191->astubbs#346) and every one of those PRs was itself swept unmerged.

Result: 2 already fixed (astubbs#41 offset-scan removal, astubbs#319 shutdown CME), 6 partly
addressed, 20 fully open. Grouped into work items rather than 28 near-duplicate
entries, since several want designing together - per-topic handlers with
separate consume/produce types, seek with subscription changes, retry expiry
with stall detection. astubbs#57 folded into the existing log-noise entry.

Swept PR head commits were checked and are all still reachable, so the drafts
are recoverable; entries cite branch and SHA, not just the PR number.

Upstream-Issue: confluentinc#154
Forwarded: no
Applied-Upstream: no

* docs(upstream-map): mirror the whole 2023 cohort, not the parts we rate

The point of mirroring is a clean, known cutoff - "every issue upstream closed
administratively is accounted for here" - not a curated pick of the good ones.
A set filtered by our own value judgement is not a cutoff: the next person
cannot tell "not mirrored because it was junk" from "not mirrored because it
was missed", and that ambiguity is worth far more than the cost of carrying a
few items nobody will ever action.

Drops the decline recommendations from astubbs#53, astubbs#199, astubbs#246 and astubbs#57 in favour of
neutral statements of the trade-off, and renames sweep-2023-decline-candidates
to sweep-2023-small-items (status wontfix -> none). The facts that informed
those recommendations are kept - they are useful to whoever picks the issue up
- but they are now framed as input to that person's decision rather than as our
verdict delivered in advance. Fork issues can always be closed later on their
merits, which leaves a visible record; pruning before mirroring does not.

Records the principle in the section header so a later pass does not re-prune.

Upstream-Issue: confluentinc#154
Forwarded: no
Applied-Upstream: no

* docs(upstream-map): link the created fork mirrors back to their entries

The 28 mirrors are live as astubbs#227-254 (label `upstream-admin-closed`),
with confluentinc#41 -> astubbs#233 and confluentinc#319 -> astubbs#252 created
and immediately closed as completed, carrying the code evidence that they are
genuinely fixed.

Records the fork numbers on each entry so the mapping is queryable rather than
re-derived, which is the reason this file exists. Adds `fork.fork_issues` (the
plural of the existing `fork_issue`) because several entries deliberately group
upstream items that want designing together, and documents it in the schema
block. Verified: all 28 mirrors are referenced, none missing, no strays.

Also snapshots each upstream title verbatim into its mirror body header, dated
2026-08-07 - the fork titles may drift as these are worked, and the original
wording is what makes an old thread findable.

Upstream-Issue: confluentinc#154
Forwarded: no
Applied-Upstream: no

* fix(tooling): give upstream-sweep a mode that can see closures it never saw

The default sweep is a window search - `updated:>=$since` - so it structurally
cannot see an item whose last activity predates the window, and `last_swept`
only moves forward, so the blind spot grows. That is why upstream's 2023
administrative closures went unnoticed for three years: 28 issues closed with
"Closing Issue" and 35 unmerged PRs closed as "Closing - Stale.", all marked
COMPLETED, none of it triage, none of it visible to us.

Adds `--audit`: no time window, asks "which closed upstream items are neither
tracked in the manifest nor mirrored in the fork?", and flags days where an
implausible number of things closed at once. Run against the real repo it
rediscovers both sweeps from scratch and reports zero unaccounted, which is
also an end-to-end check that the new fork_issues linkage is correct.

Bots are excluded from the PR analysis. Dependabot self-closes superseded
bumps in batches that look exactly like a sweep - 2022-08-16, 2022-10-20,
2023-11-03 and 2024-01-25 are all dependabot - and unfiltered they buried the
two real sweeps in noise. Filtering them surfaced two human PRs that had been
sitting inside those batches (confluentinc#508, confluentinc#650), now recorded
for review.

The report says outright that a bulk day is not proof of a sweep, because a
release triage looks identical from here, and that stateReason COMPLETED is not
evidence of a fix - that assumption is what made this cohort invisible.

Known remaining hole, recorded not fixed: a PR closed alone on a quiet day is
still invisible, since detection keys on bulk.

Upstream-Issue: confluentinc#154
Forwarded: no
Applied-Upstream: no

* fix(tooling): teach the audit about Discussions, a content type we never checked

Discussions were invisible to everything: not in the manifest, not mirrored,
not in any sweep mode. 74 of them upstream, and nothing we run would ever have
mentioned one.

They were NOT swept - no bulk closure, and the largest day (2024-04-02, six
threads) is all answered=true housekeeping. So the failure mode is different
from the 2023 cohort: not administrative closure, just questions nobody
answered, in a place no issue search reaches. Handling differs accordingly -
these want answering or converting, not mirroring wholesale.

The audit now lists zero-reply discussions, excluding release-announcement
threads by title: those legitimately have no replies, and counting them as
neglect would put 9 false positives at the top of the report.

Two finds justify the check on their own. Discussion 542 (zero replies) is a
field report of a transactional consumer stuck in rebalance because it cannot
acquire the produce lock, with the reporter suspecting the revoke-time flush -
the same lock lifecycle as bug-producing-lock-double-release, and they raised
the timeout without effect, which is evidence about the mechanism rather than
the duration. Discussion 883 (zero replies) is the same complaint as fork
mirror astubbs#187 but with a runnable reproducer, which astubbs#187 lacks.

Upstream-Issue: confluentinc#154
Forwarded: no
Applied-Upstream: no

* docs(inflight): record the open obligation to account for every upstream item

Two notes, both about what is NOT done.

Discussions are not a queue to be converted. There is no pipeline turning
threads into issues, and most should never become one. The rule is a judgement:
if reading a discussion makes us think there is an issue, we raise one - a
normal fork issue on its own merits, citing the discussion as where it came
from. It exists because we believe the problem is real, not because a thread
existed. That also keeps `upstream-mirror` meaning exactly "an upstream issue
we carry", which is what makes the 2023 cutoff verifiable.

The wider obligation is now written down: every upstream issue, PR and
discussion must be accounted for - carried, declined, or genuinely resolved
upstream - not sampled. The 2023 cohort was found only because it was a *bulk*
event; `--audit` keys on bulk closures and zero-reply threads, and both are
proxies that miss whole shapes of problem (a PR closed alone on a quiet day, a
discussion with one dismissive reply, an issue marked COMPLETED with no linked
PR). The audit narrows the field; only reading discharges the obligation.

Also records what has been ruled out, so it is not re-investigated: wiki
disabled, no advisories, all open-milestone issues already mirrored, the orphan
branches accounted for (v0.6.x-dev is the lambda-actor work already captured
via swept PRs; 0.5.3.x's regression fix IS on master as a908e16), and
"upstream pushed today" being a pushed_at artefact rather than new activity.
Left open: project boards need a read:project scope we do not have, and 169
forks are unexamined.

* fix(upstream-map): use a group the schema actually allows

Two new entries used `group: batching-ordering`, which is not in the GROUPS
allow-list in scripts/upstream-map.py, so `upstream-map.py validate` failed on
them. Caught in review on astubbs#258.

My mistake was validating the wrong way: I checked the file with an ad-hoc
yaml.safe_load plus a duplicate-id check, which passes happily on a group the
schema rejects, instead of running the project's own validator that AGENTS.md
tells contributors to run before committing manifest changes.

Reassigned both to `features` rather than widening GROUPS. The rest of this
cohort's feature entries already use `features`, so this keeps the cohort
internally consistent, and the ordering/batching distinction is not lost - it
lives where it belongs, on the issues themselves via the `area/batching-ordering`
label (astubbs#244, astubbs#236). Adding a vocabulary term to a shared schema as
a side effect of a mirroring PR is the larger, less reversible change.

Also drops the redundant 345 from sweep-2023-broker-disconnect-commit's
`related` list, where it already appears in `prs`.

Verified: `upstream-map.py validate` reports OK on 27 entries, and `refs` and
`table` both still render.

* docs(upstream): graduate the durable parts of the sweep record out of inflight

The three inflight notes stay - they hold undischarged work - but they were
also carrying permanent content, and inflight is transient by its own charter.

Moved to durable homes, each citing the manifest rather than restating it:

- docs/upstream.md gains the upstream-admin-closed cohort note (with the
  "do not trust 2023-era closure states" rule), the discussions non-mirroring
  policy decided 2026-08-07, documentation of --audit and its known blind
  spots, and the ruled-out upstream surfaces (wiki, advisories, milestones,
  orphan branches, pushed_at).
- docs/solutions/ gains the transferable lesson: a closure state is a
  rendering choice not a triage, "fixed by #N" must be checked against the
  merge bit, windowed watchers need a no-window audit, and bots must be
  filtered before hunting bulk events.
- upstream-pr-analysis.adoc is corrected: it claimed issues were never
  bulk-closed, which the 2023-07-07 sweep disproves, and the PR sweep is
  now confirmed rather than suspected.

The inflight notes now hold only open work, pointing at the new homes.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* docs(upstream): name the analysis doc's role (the plan) beside the manifest (the state)

docs/upstream.md's opening enumerated everything it owns except the
editorial analysis, and neither source-of-truth reference was a clickable
link. Now the two roles are named explicitly: the .adoc is the plan, the
manifest is the state tracker.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(upstream): make the audit's discussion query actually paginate, and correct the sweep cohort

Address PR review feedback (astubbs#258).

- upstream-sweep.sh: `gh --paginate` only substitutes a variable named
  `endCursor`; calling it `$cursor` meant the cursor was never fed back and gh
  re-requested page 1 forever (reproduced: 469 identical pages at first:2).
  It only looked healthy because 74 discussions fit in one page of 100. The
  failure was also swallowed by `2>/dev/null || true`, which would have printed
  a clean "(none)" for a broken query - the one answer this mode must never
  invent. Fail loudly instead.

- upstream-map.yaml: the sweep cohort listed 36 PRs against a documented count
  of 35. Upstream closed exactly 35 unmerged PRs on 2023-06-15; confluentinc#66
  (closed 2022-10-19) was carried in by mistake. Listing a ref here marks it
  accounted for, so it was hiding an unrelated PR from every future audit.
  Recorded PR 258 and moved the entry to `pr-open` per the lifecycle rule.

- next-upstream-coverage-completeness.md: dropped the cached counts - inflight
  notes must not record what a command can answer, and the "~100 partially
  mirrored" line already contradicted docs/upstream.md, which says all 78 open
  upstream issues are mirrored with backlinks. Kept only what the audit cannot
  say: what nobody has read yet.

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

* docs(agents): let the manifest cache frozen upstream-issue facts, and say why

The rule said "the manifest tracks upstream PRs only", so mirroring the 2023
sweep cohort into it read as a violation. The rule is what is out of date.

An archived upstream's closed issue numbers and closure events are frozen. Caching
them locally is a read-path optimisation, not a second tracker: grepping one file is
instant, while the same answer from the mirrors costs dozens of API round-trips and
burns rate limit shared across agents. The usual objection to duplication - the copy
silently diverges - needs a source that can still move, and this one cannot.

So the boundary is redrawn where it actually bites: the mirror owns an issue's *live
state* and remains the only place you update it; the manifest may cache what is frozen
(number, cohort, owning mirror). Cache what is frozen; never mirror what is moving.

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

* docs(upstream): put the manifest-caching rule in the doc that owns it

The previous commit wrote the rule into AGENTS.md, which is the one place it
does not belong. AGENTS.md's own preamble calls itself a router - "if it only
matters once you are already in a topic... it goes in that topic's doc" - and
docs/upstream.md line 7 already claims ownership explicitly: "AGENTS.md carries
only the pointer and the one-line rule that manifest upkeep is the agent's job."

The rule was in fact already stated twice before this branch (AGENTS.md:442 and
docs/upstream.md:23), so growing the AGENTS.md copy deepened a fragmentation that
was already there. Now stated once, where an agent editing the manifest will
actually be looking, with AGENTS.md left holding the pointer and the one binding
rule whose failure is silent (keep the fork side in sync).

Net effect on the router: one line shorter than master, despite covering more.

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

* docs(agents): make a pointer say who owns the rule, not just what is nearby

Diagnosed from a live miss. A reviewer cited AGENTS.md's "the manifest tracks
upstream PRs only", so that section was read and treated as authoritative - while
docs/upstream.md had been stating the same rule, and claiming ownership of it, the
whole time. The duplicate was then grown in the router rather than fixed at source.

Nothing in the reading path revealed the mistake. AGENTS.md stated a complete-looking
rule and followed it with a pointer listing four adjacent mechanics ("the manifest
schema, the mirrors, the commit trailers and the upstream sweep"), which reads as
*further detail*, not as *this is a summary and that doc wins*. The contract was
written down - docs/upstream.md:7 - but only on the side nobody enters from, since
AGENTS.md is what loads every session.

The anti-duplication rule already existed here ("Never state a fact twice"). What was
missing is the half that makes it discoverable: a cross-reference must name the owner
and say the owner wins, so a reader can tell a stub from the whole rule before editing
the copy. Applied to the rule itself and to the upstream pointer that failed.

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

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
@astubbs astubbs added this to the 0.6.0.0 milestone Sep 1, 2026
astubbs added a commit that referenced this pull request Sep 1, 2026
…he lane gate green

The lane was wired up in this PR and landed RED on one arm:
`ShardManagerLincheckTest`, an inverted harness asserting that Lincheck FINDS
a violation, found nothing. The handoff this branch carried recorded that as
"#336 REFUTED - do not re-run it". That verdict was wrong, and this
commit replaces it with the experiment that settles it.

Bisected rather than reasoned about. The harness has not changed since
#345 and Lincheck is pinned at 3.7 in both trees, so only product code
varies. Running the unchanged harness against each tree:

  #345 (0112c70)              FIRES
  confluentinc#905 hot-shard metric    FIRES
  #373 claim compare-and-set    FIRES
  #336 (3e668a4)              misses

#336 is the sole commit touching core's main sources between the last
hit and the first miss, so attribution is exact rather than merely bisected-to.
The counterexample it removed is the one the lane's note recorded months ago -
`revokeSweep(0)` in the prefix, then `addWork(0)` against `addWork(0)` - and
#336 removed it by admitting to the population before the put and
reading the outcome from the map instead of from the earlier read.

Three hand-written controls had said otherwise, and all three were wrong: one
kept the put atomic and never reintroduced a check-then-act at all, one
restored the map's check-then-act alone, one restored the counter's bare
increment alone. The defect was in neither half - it was deciding the
accounting from the pre-put read, which #336 removed wholesale. A
control assembled by hand tests the shape you believed the defect had, so its
negative says nothing about the commit. The durable form of that lesson is in
docs/solutions/best-practices/reverting-half-a-fix-is-not-a-control-2026-09-01.md.

So the arm gets the disposition the lane's inversion contract prescribes: it is
now `stressFindsNoWayToBreakTheShardMap`, asserting no violation, and
#336 is what it regression-tests. The bound is deliberately unchanged -
50 x 5,000 is the budget the counterexample was FOUND at, which makes this zero
worth more than one measured at a bound picked for cost. 0 in 250,000
invocations, and 0 in 2,500,000 at ten times it, on a 32-core box with Temurin
17.0.20+8 and Lincheck 3.7.

The whole lane is now green locally - 9 tests, 2m45s, all six harnesses
selected - so the leg lands GATING as the matrix entry already declared, and
the quarantine-or-advisory question the handoff left open does not arise.

The matrix entry's own gating argument is corrected too. It claimed the model
checker explores interleavings deterministically, which is true of model
checking and false of this lane: no model-checking arm over a product class
runs here at all, they are blocked on Lincheck rewriting a Lombok
`callSuper` hashCode into a recursing self-call. What licenses gating is that
the three assert-no-violation arms need no hit to pass. The residual flake risk
is named where it actually lives - the still-inverted arms,
`PartitionStateLincheckTest` and the toolchain probe, which do need a hit and
whose rate was measured 3.4x apart across two machines.

Also corrects the entry's ~2m30s estimate to the 7m42s measured on
ubuntu-latest, and retires the handoff note: its open question is answered, and
what outlives it has moved to the solutions write-up and to the lane's owning
note.
astubbs added a commit that referenced this pull request Sep 1, 2026
…he stale target/ that nearly reversed it

Review asked for the #336 attribution to be defended against #336's
own commit message, which says the Lincheck lane was green "still finding the
violation it is calibrated to find". Replicating the bisect to answer that turned
up a bigger problem with how it had been run.

The first bisect checked out each commit inside ONE worktree. Re-running the same
commits in a second worktree - one built at a different commit first - reported 0
hits out of 10 at a commit the first pass recorded as firing. Same commit, same
machine, same harness; only the inherited `target/` differed. Maven's incremental
compilation had left another commit's classes in place, so the harness ran against
a tree that never existed, and nothing in the output says so. It fails silently in
both directions, which is what makes it worth a section of its own rather than a
footnote.

Re-run with a FRESH worktree per commit, so no two trees can share class output:

  #345 (0112c70)              fires 5/5
  confluentinc#905 hot-shard metric    fires 5/5
  #373 (8000926)              fires 5/5
  #336 (3e668a4)              misses 5/5

The attribution holds, now on numbers that are reproducible rather than
single-shot. Each miss pays its full bound, so that row is 0 hits in 1,250,000
invocations.

On the commit message: run on #336's own tree the whole lane is RED, on
this arm alone, with the other five green. The message's own line - "adapted
cherry-pick of fa4d1cf" - is the likely mechanism, the lane it reports on
plausibly being the pre-adaptation one. Recorded in the javadoc rather than
explained away: if that line is ever shown to describe the merged tree, the flip
is wrong.

On the machine-dependence alternative the review raised: the miss is confirmed on
a second machine. Before the flip this arm also found nothing on ubuntu-latest,
four cores against 32, while the toolchain probe's stress arm fired on that same
runner. The lane's measured 3.4x cross-machine variance is a rate effect, and a
rate effect does not turn 15 of 15 hits into 0 across one commit on one box, nor
agree across two machines that far apart.
astubbs added a commit that referenced this pull request Sep 1, 2026
…und dark (#404)

Six Lincheck harnesses and bin/lincheck-test.sh landed with #347 and were
never wired into CI: no workflow referenced them, and every CI script passed
-Dexcluded.groups=...,lincheck, so the tag was excluded everywhere and included
nowhere. A test that never runs is not a passing test, and nothing went red to
say so for the lane's whole life.

Running it found one arm dark. ShardManagerLincheckTest's stress arm is inverted -
it asserts Lincheck FINDS a violation - and found nothing. Three hand-written
controls said #336 was not the cause, and all three were wrong: each
reverted one half of it onto today's tree, and the defect was in neither half
alone. It was deciding the accounting from the pre-put read, which #336
removed wholesale by admitting to the population first and reading the outcome
from the map.

Settled by bisect with a FRESH worktree per commit, which turned out to matter:
reusing one working copy reported 0 hits out of 10 at a commit that in fact fires
5 of 5, because Maven's incremental compilation left another commit's classes in
place. A shared target/ hands you a clean, wrong bisect and nothing in the output
says so. Re-run cleanly: fires 5/5 at #345, at confluentinc#905's
hot-shard metric and at #373's claim compare-and-set; misses 5/5 at
#336, the sole commit touching core's main sources in that interval.

So the arm is flipped to stressFindsNoWayToBreakTheShardMap, asserting no
violation, with #336 as what it regression-tests. The bound is unchanged
at 50 x 5,000 because that is the budget the counterexample was FOUND at, which
makes the zero worth more than one measured at a bound picked for cost: 0 in
250,000 invocations, and 0 in 2,500,000 at ten times it.

#336's own commit message claims the lane was green "still finding the
violation it is calibrated to find". Run on that tree it is RED, on this arm
alone. The likely mechanism is in the same message - it is an adapted cherry-pick
of fa4d1cf - and it is recorded in the javadoc rather than explained away.

The matrix entry's gating argument is corrected too. It claimed the model checker
explores interleavings deterministically, which is false of this lane: no
model-checking arm over a product class runs at all, they are blocked on Lincheck
rewriting a Lombok callSuper hashCode into a recursing self-call. What licenses
gating is that the assert-no-violation arms need no hit to pass. The residual risk
is named where it lives - PartitionStateLincheckTest and the toolchain probe still
need a hit, and both fired on ubuntu-latest on every CI run of this PR.

Method lesson in
docs/solutions/best-practices/reverting-half-a-fix-is-not-a-control-2026-09-01.md.
astubbs added a commit that referenced this pull request Sep 3, 2026
…dy claims to model

CI red on the Lincheck lane, and the failure was the harness's fixture rather than the shard map.

ShardManagerLincheckTest.stressFindsNoWayToBreakTheShardMap reported an invalid execution -
revokeSweep(0) beside failure(0), then addWork(0): NullPointerException. Stress mode carries no
stack trace, so it was reproduced locally (1 of 1) to get one:
PartitionStateManager.getPartitionState returns null, dereferenced by
ProcessingShard.isWorkContainerStale from addWorkContainer's resident check.

Why it only appears now. This harness never assigned its partition, so getPartitionState answered
null for every container in it - and that was invisible because the branch that dereferences it needs
an ARRIVAL to find a RESIDENT at its offset. Until the declining revoke sweep landed on this branch,
a sweep always removed the resident and, under KEY ordering, the empty shard with it, so every
addWork was an insertion into nothing. A sweep that DECLINES - failure(0) holds the retry queue's
write lock through retryQueue.add, so the concurrent tryRemove refuses - leaves the resident in
place, and the next addWork takes the branch for the first time in this harness's life.

Not a product defect, checked rather than assumed: PartitionStateManager never removes from
partitionStates - onPartitionsRemoved REPLACES the entry with RemovedPartitionState (`partitionStates.put(removedPartition, RemovedPartitionState.getSingleton())`) - and a container only
reaches a shard through a poll for an assigned partition, so the map answers non-null for anything
resident. The unguarded read is real and is a known parked policy question, which
docs/inflight/core-stale-arrival-guard-needs-a-null-safety-decision.md owns and which this does not
touch; that note gains a dated paragraph recording that a harness has now reached the call, from a
state the product deliberately creates.

The fix is the fixture: the constructor assigns TP before planting the resident, which is what its
own comment already claims to model ("the ordinary steady state of a running consumer"). Same idiom
as WorkManagerLincheckTest's constructor.

Teeth checked, not assumed. Restoring the #345 defect this harness regression-tests against -
the containsKey-then-get pair in ShardManager.removeWorkFromShardFor with an unconditional deref -
turns it RED again on the fixed fixture, reporting revokeSweep(0): NullPointerException against
revokeSweep(0) (the sweep racing itself, the route the harness javadoc records). ShardManager was
restored byte-identical afterwards, verified by an empty diff.

Cost: 8.3s to 10.2s at the committed bounds. 4 of 4 green after (3 targeted repeats plus the whole
lane); 1 of 1 red before. Whole lane green in 2m53s (bin/lincheck-test.sh, build included):
ShardManagerLincheckTest 1/0/0/0, WorkManagerLincheckTest 2/0/0/0, RetryQueueLincheckTest 1/0/0/0,
PartitionStateLincheckTest 1/0/0/0, LincheckSuperHashCodeProbeTest 2/0/0/0,
LincheckToolchainProbeTest 2/0/0/0.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018rEzrWYFr6oEzy6porczd3
astubbs added a commit that referenced this pull request Sep 7, 2026
…dy claims to model (#467)

test(core): the Lincheck shard harness assigns the partition it already claims to model

CI red on the Lincheck lane, and the failure was the harness's fixture rather than the shard map.

ShardManagerLincheckTest.stressFindsNoWayToBreakTheShardMap reported an invalid execution -
revokeSweep(0) beside failure(0), then addWork(0): NullPointerException. Stress mode carries no
stack trace, so it was reproduced locally (1 of 1) to get one:
PartitionStateManager.getPartitionState returns null, dereferenced by
ProcessingShard.isWorkContainerStale from addWorkContainer's resident check.

Why it only appears now. This harness never assigned its partition, so getPartitionState answered
null for every container in it - and that was invisible because the branch that dereferences it needs
an ARRIVAL to find a RESIDENT at its offset. Until the declining revoke sweep landed on this branch,
a sweep always removed the resident and, under KEY ordering, the empty shard with it, so every
addWork was an insertion into nothing. A sweep that DECLINES - failure(0) holds the retry queue's
write lock through retryQueue.add, so the concurrent tryRemove refuses - leaves the resident in
place, and the next addWork takes the branch for the first time in this harness's life.

Not a product defect, checked rather than assumed: PartitionStateManager never removes from
partitionStates - onPartitionsRemoved REPLACES the entry with RemovedPartitionState (`partitionStates.put(removedPartition, RemovedPartitionState.getSingleton())`) - and a container only
reaches a shard through a poll for an assigned partition, so the map answers non-null for anything
resident. The unguarded read is real and is a known parked policy question, which
docs/inflight/core-stale-arrival-guard-needs-a-null-safety-decision.md owns and which this does not
touch; that note gains a dated paragraph recording that a harness has now reached the call, from a
state the product deliberately creates.

The fix is the fixture: the constructor assigns TP before planting the resident, which is what its
own comment already claims to model ("the ordinary steady state of a running consumer"). Same idiom
as WorkManagerLincheckTest's constructor.

Teeth checked, not assumed. Restoring the #345 defect this harness regression-tests against -
the containsKey-then-get pair in ShardManager.removeWorkFromShardFor with an unconditional deref -
turns it RED again on the fixed fixture, reporting revokeSweep(0): NullPointerException against
revokeSweep(0) (the sweep racing itself, the route the harness javadoc records). ShardManager was
restored byte-identical afterwards, verified by an empty diff.

Green after on the whole Lincheck lane; red before. Reproduce: `bin/lincheck-test.sh`.

RE-VERIFIED ON MASTER, 2026-09-07 - AND ONE CLAIM ABOVE DOES NOT HOLD HERE.

Extracted from #431 as an independent change. Both claims re-measured on
this branch's base rather than carried over:

- THE NPE IS NOT REACHABLE ON MASTER. ShardManagerLincheckTest is GREEN with the fixture change
  reverted (1 test / 0 failures, whole lane 37s). The branch that dereferences the null needs an
  arrival to find a RESIDENT at its offset, and that needs the DECLINING revoke sweep, which is what
  #431 adds and which has not landed. So on master this is latent: the
  harness would go red on its own fixture the moment that PR merges, on the fixture rather than on
  the shard map it exists to test. Fixing it here is deliberate - it is cheap, separable, and a
  harness whose fixture contradicts its own comment ("the ordinary steady state of a running
  consumer", which has its partition assigned) is a false green waiting for a schedule.
- THE TEETH DO STILL HOLD ON MASTER. Restoring the #345 defect this harness regression-tests
  against - the containsKey-then-get pair in ShardManager.removeWorkFromShardFor with an
  unconditional deref - turns it RED on the fixed fixture, reporting
  "revokeSweep(0): NullPointerException ... Cannot invoke ProcessingShard.removeWorkAtOffset(long)
  because the return value of Map.get(Object) is null" against revokeSweep(0) - the sweep racing
  itself, the route the harness javadoc records. ShardManager restored, empty diff verified.

The fixture javadoc and the dated paragraph in
docs/inflight/core-stale-arrival-guard-needs-a-null-safety-decision.md are reworded accordingly: both
said the declining sweep HAD landed, which is true on that PR's branch and false here. The note keeps
the sighting - the datum it contributes is that the unguarded call is reachable from a state the
product deliberately creates, and that does not depend on the fix's outcome - and now says where it
was taken and that master was re-measured green.

refactor(core): one joinQuietly for the state tests, in the shared ThreadUtils

Extracted from #431, where a ce-simplify pass found the same
join-with-timeout-and-restore-the-interrupt wrapper hand-rolled in two tests under `state`. Only one
of those tests exists on master, so what lands here is the hoist and not the deduplication: the
wrapper moves to the shared test ThreadUtils, ShardPopulationRaceTest calls it, and its private copy
goes.

Hoisting a single-caller helper is deliberate and the javadoc says why rather than claiming a second
caller that is not here. `join` with a timeout plus an interrupt restore is what every thread-racing
test in `state` needs and what gets re-typed; the second private copy is how the drift starts, and
putting it in the shared utility on the way past is cheaper than deduplicating two copies later. The
null-thread no-op is kept for the same reason - it is what makes the helper callable from a `finally`
block before it knows whether the thread was ever started, which is the shape a cleanup path needs.

Behaviour unchanged: the call site's 500ms becomes Duration.ofMillis(500) and nothing else moves.

Reproduce: `./mvnw -Pci -pl parallel-consumer-core -am test -Dtest=ShardPopulationRaceTest`.

Co-authored-by: Claude Fable 5.1 (1M context) <noreply@anthropic.com>
astubbs added a commit that referenced this pull request Sep 9, 2026
…ever holds the offset (#492)

WHAT CHANGED FOR A USER: a rebalance can no longer remove a record that a later assignment had
already re-registered. `ShardManager.removeWorkFromShardFor` - the revoke and lost path - removed by
KEY with `removeWorkAtOffset(consumerRecord.offset())`, so whatever occupied the offset when the
removal landed is what left the shard. It now removes only the container the revoked record was
registered as, or a stale one, and never a live container from a later registration.

THE DEFECT CLASS, AND WHERE THIS SITE SITS IN IT. #468 closed the same class
at the poller's stale sweep: a removal keyed on the offset cannot say WHICH of two containers at that
offset it meant, and the fix was to make `WorkContainer` equality identity so that
`Map.remove(key, value)` is a true compare-and-remove. #483's defect-class
sweep reported this site alongside it - "the one remaining unconditional by-key shard removal" - and
deliberately left it, on the grounds that it belonged with #468's mechanism rather than with a
reachability proof. This is that. No fork or upstream issue tracks it; it was reported in a commit
body and on a `docs/inflight/` note, so this PR closes nothing.

THE CALLER HOLDS NO CONTAINER, WHICH IS WHY THE FIX IS SHAPED DIFFERENTLY. The stale sweep inspects a
container and then wants that one gone. This sweep is handed the `ConsumerRecord`s ONE generation was
still carrying as incomplete (`PartitionState.onPartitionsRemoved` ->
`removeAnyShardEntriesReferencedFrom`), so what it can name is the REGISTRATION, not an inspected
container. That works because `PartitionState.maybeRegisterNewPollBatchAsWork` puts the same record
instance into `incompleteOffsets` and into the `WorkContainer` it builds, in one loop body - so "the
container this generation registered for this record" is `occupant.getCr() == revokedRecord`, and a
later generation's re-delivery of the same offset is a different object because it came from a
different fetch. That identity has one named exception, stated at the site: `addNewIncompleteRecord`
puts unconditionally while `addWorkContainer` DROPS an arrival whose resident is not stale, so an
in-generation replay of an already-registered offset leaves the partition naming record B while the
shard holds the container over record A. The staleness condition below covers it.

TWO CONDITIONS, AND THE MIDDLE OPTION WAS WRONG. Registration identity alone declines for a container
from another registration that is nonetheless STALE, and declining there would leave a stale container
holding an offset of a revoked partition - the state this sweep exists to prevent. Staleness alone
declines for a live container built from the record the sweep was handed, which is what a revoke sweep
driven before the partition's state has been swapped sees, and is what
`ShardManagerLincheckTest.revokeSweep` models on every invocation: that harness's removal operation
would have become a silent no-op while staying green. Verified rather than assumed -
`incrementPartitionAssignmentEpoch` starts from `KAFKA_OFFSET_ABSENCE = -1`, so that harness's
`EPOCH = 0L` containers are live against the epoch its constructor assigns. So the guard declines for
exactly one thing - a LIVE container from another registration - which makes the change a no-op
everywhere except in the defect case, and each condition has its own ablation arm.

THE HARM, IF IT IS REACHED, IS THE LOST RECORD - #468's, not a misdirection. The live container
is gone from the shard while its own `PartitionState` carries the offset as incomplete, so nothing
selects it and nothing completes it, and the commit high-water mark cannot pass it until the partition
is re-polled. The v6 scope note this came from said the cost was "misdirection bounded to one
control-loop tick by #481's purge"; that is the DISPLACEMENT orphan's cost, not this one's.
This removal is a shard removal, and the purge collects retry-queue entries.

REACHABILITY: NOT TODAY, ON TWO INDEPENDENT ARGUMENTS, AND THE STRONGER ONE IS STRUCTURAL.

- Thread ordering, which has to name BOTH production routes. On the ordinary route the poll thread
  runs both rebalance callbacks, so a generation's revoke sweep completes before the assignment that
  could register a replacement begins. On the CLOSE route the sweep runs on the CONTROL thread
  (`maybeCloseConsumer` -> `onLeavePrepare` -> `onPartitionsRevoked`), which
  `PartitionStateManager.resetOffsetMapAndRemoveWork`'s javadoc calls live in every commit mode - and
  that is also `addWorkContainer`'s thread, so the two still cannot interleave. "Both callbacks are on
  the poll thread" is the half-statement, and it was written that way here first.
- `resetOffsetMapAndRemoveWork` installs `RemovedPartitionState` BEFORE it calls in, so
  `checkIfWorkIsStale` is true for EVERY occupant and the staleness condition carries all of them: on
  the shipped path this method is behaviourally identical to the by-key removal it replaces, and the
  decline branch is defence for a caller that sweeps before the swap. That says nothing about threads.

Nothing checks either argument. The conditional form costs one reference comparison and rests on
neither, which is exactly why #468 wrote `getWorkIfAvailable`'s last-resort sweep conditionally
against a race it had shown was unreachable there.

THE NPE GUARDS ON THIS PATH ARE UNTOUCHED, AND THE CLEARED SUSPICION NAMES THE RIGHT OBJECT. The
single-read `getShard` idiom #345 put in stays where it was; the new work is inside
`ProcessingShard`, below it. The staleness question resolves the partition state from the OCCUPANT,
not from `revokedRecord` - and in the only branch that asks, the occupant is by definition a different
registration - so the discriminator is two facts: the state is installed before the call (and a
partition with no state `continue`s without sweeping at all), and every `ShardKey` variant is
partition-scoped, so an occupant of this shard belongs to the revoked partition. WHAT WOULD REOPEN IT:
a caller from a path that has not installed a state, or a topic-scoped shard key - the latter being the
reopener `addWorkContainer`'s own cleared suspicion already lists, which reopens both at once.

EVIDENCE. `ShardRevokeSweepReplacementEvictionTest`, three arms, RED-then-GREEN through
`PartitionState.onPartitionsRemoved` so the argument list is built by production code - one level below
the state swap, which is what makes the decline branch reachable at all. Ablation matrix, predicted
before running, one arm red per ablation and no other:

- whole guard removed, back to `removeWorkAtOffset(offset)` -> the displacement arm
- staleness condition removed -> `aStaleContainerFromAnotherRegistrationIsStillSweptOut`
- registration-identity condition removed -> `aRevokeSweepStillRemovesALiveContainerBuiltFromTheRecordItWasHanded`
- decline retires the occupant instead of leaving it -> the displacement arm's accounting assertion

That fourth ablation is why the accounting assertion exists: making the decline call
`population.onRetired()` + `excludeFromSelection(occupant)` left every other assertion GREEN while
creating a permanent `RecordPopulation` deficit, which is this class's recurring defect and has no
clamp and nothing to reconcile it.

TWO INSTRUMENTATION FAILURES, RECORDED RATHER THAN TIDIED AWAY. The registration-identity ablation
reported NO failure on its first run: dropping the condition left an unused local, the module never
recompiled, and the grep for failures matched nothing - a silent false negative in the experiment
meant to prove the condition earns its place. Re-run with the build outcome asserted, it is red as
predicted. Separately, `@SuppressWarnings("ReferenceEquality")` was written on the identity comparison
and then measured: deleted, rebuilt under `-Pci`, `BUILD SUCCESS`. Neither `WorkContainer` nor Kafka's
`ConsumerRecord` overrides `equals`, so Error Prone never fired - it suppressed nothing and disagreed
with `isResident`'s bare `==` two methods away. Removed, with the reason written where it was.

SAME-DEFECT-CLASS SWEEP over `ShardManager`, `ProcessingShard` and `PartitionState`. Fixed: the one
above; no unconditional by-key removal of a container remains in main. Dismissed with discriminators:
`ProcessingShard.onSuccess` (re-verified rather than inherited - `WorkManager.handleFutureResult` is
the third staleness checkpoint and drops a stale result before `onSuccessResult`, so a returning stale
container cannot remove the fresh one that replaced it); `addWorkContainer`'s by-key INSERTION
(#483's leg 1, plus #336's admit-first, which reads the outcome from the map rather than
the earlier read); `removeStaleWorkContainersFromShard` and `getWorkIfAvailable`'s last-resort sweep
(already conditional, #468); `ShardManager.getShard` / `compute` / `computeIfPresent`
(single-read Optional idiom, #345, and atomic per-key, #336 - not check-then-act);
`RetryQueue.remove` / `removeAll` at every call site including `onSuccess`, `onFailure` and
`purgeDepartedRetryEntries` (same shape, but it is the queue's keying model rather than a removal that
forgot to name its target, so a fix is a change to that model - reported and left by #483, and
left here); `PartitionState.incompleteOffsets.remove` and the truncation prune (offsets over records,
control-thread-only - "this offset is complete" does not depend on which record object represents it).

`removeWorkAtOffset` now has no production caller. Kept as the modelling primitive four test classes
use for "a container departs its shard", with its javadoc rewritten: it used to open by naming the
`onPartitionsRemoved` caller this change moved away, and now says what it is and which of the two
conditional removals a main-code site should reach for instead.

RECORDS. `docs/solutions/logic-errors/a-by-key-removal-cannot-say-which-container-it-meant-2026-09-07.md`
- the class's owner - gains a dated section for the second site, because its own sweep's only hit was a
false positive and the real one was found a day later.
`docs/inflight/bug-shard-displacement-orphans-the-retry-queue-entry.md` gets a pointer, not a
narrative: its subject, state and `PROPOSED closed` marker are untouched, and what is recorded is only
that a reader arriving at #483's four-item list can see which one moved.

Reproduce: `bin/ci-unit-test.sh`; `bin/lincheck-test.sh`; `bin/check-all.sh`;
`./mvnw -pl parallel-consumer-core -am test -Dtest='ShardRevokeSweepReplacementEvictionTest,ShardStaleSweepReplacementEvictionTest,ShardManagerRevokeSweepNpeTest,ShardDisplacementOrphanReachabilityTest'`;
`bin/check-pr-analysis-surfaces.sh 492`.

Co-authored-by: Claude Opus (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

0.6.0.0 Targeted at the 0.6.0.0 release

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant