Skip to content

test(core): stop the core tests jar configuring other modules, and remove the sleeps that stood in for events - #265

Merged
astubbs merged 14 commits into
masterfrom
test/suite-config-isolation-and-event-based-waits
Aug 13, 2026
Merged

astubbs merged 14 commits into
masterfrom
test/suite-config-isolation-and-event-based-waits

Conversation

@astubbs

@astubbs astubbs commented Aug 8, 2026 •

Copy link
Copy Markdown
Owner

Depends on #264

Description

Two defects found while running Apache Kafka's own Streams test suite against a patched build
(#255), plus the sweep that followed from the second one. Both defects make
the test suite mean something other than what it says.

1. The core tests jar was configuring every downstream module's JUnit runner

src/test/resources/junit-platform.properties is packaged at the root of the core tests jar.
Eight modules depend on that jar - the four integrations plus every example - and JUnit reads the
first junit-platform.properties on the classpath. So all eight silently ran with
parallel.enabled and dynamic.factor=20 baked in at core's build time. Their own setting was
never consulted, and there was no way to opt out.

That inverts the root pom's intent: the ci profile sets parallel-tests=false deliberately,
because JUnit thread parallelism contends on static state and CI parallelises by forking JVMs
instead. A locally-built jar bakes true, so a downstream module could inherit enabled=true, factor=20 exactly where the project had decided it did not want it.

docs/solutions/test-flakiness/unit-tests-parallelise-by-forking-not-threading had already measured
this - fork x12 is 1:38 and reliable, thread x20 is ~2:32 and intermittent. So this was not merely
"modules inherited a setting": it forced eight modules into the configuration this repo had measured
as unreliable and deliberately switched off. It surfaced as 159 of 188 Kafka tests erroring on
shared state.

Moved to surefire/failsafe configurationParameters in core's pom. As build config it is per-module
by construction: each module evaluates its own ${parallel-tests}, nothing is packaged, and it
outranks a properties file if one is ever reintroduced. Core keeps its parallelism - measured 102
worker threads before and 103 after. The eight downstream modules revert to the JUnit default, which
is what they would always have had.

2. BlockedThreadAsserter asserted on a clock instead of on causality

assertUnblocksAfter scheduled the unblocker on a timer, then asserted the blocked function's
wall-clock elapsed time was at least that long. It failed in CI at 19.985s >= 20s - a 15ms
scheduler wobble that says nothing about the behaviour under test - and it deliberately slept 20s to
do it. The property it wants is an ordering fact, so it is now asserted as one: both events take a
tick from a shared monotonic sequence, and the return must come after the unblock.
ProducerManagerTest goes from 23.06s to 3.32s.

That rewrite was itself defective, and the fix is in this PR. A six-reviewer pass found two P1s;
four reviewers found the first independently, and one reproduced it. The entered-latch was counted
down before the function ran, so it meant "thread started", not "reached the blocking call" - the
main thread usually won the race to tick, and a function that never blocked passed the new ordering
assertion 177 times in 200. The old wall-clock version was flaky by 15ms; the replacement was
unsound by 88%. The second P1, found only by the adversarial lens: a blocked function that threw
was scored as a pass.

Both fixed - the function is now proven still parked before the unblocker ticks, and its throwable is
captured and asserted null. BlockedThreadAsserterTest is added as the negative control AGENTS.md
requires and that neither previous commit had. Building it refuted the obvious design: with only a
"returns immediately" case, removing the guard failed just 10 of 20 runs. The deterministic case is a
function returning on its own timer after the unblocker ticks, which the ordering check provably
cannot catch. Guard removed: red 20/20. Guard restored: green 20/20.

3. The sweep: sleeps that stood in for events

Defect 2 named a class, so the class was searched rather than the symptom. Every Thread.sleep under
src/test and src/test-integration across all modules was surveyed against one rule: a sleep that
waits and hopes a thing happened before asserting is a correctness sleep and goes; a sleep that is
the behaviour or the scenario stays.

Eight removed, across seven files. The clearest two: ShardManagerTest slept 10ms of wall clock
three times purely to advance a mock clock; CloseAndOpenOffsetTest slept 500ms for a commit with
its own comment saying "sleep is lazy but much much simpler" and a TODO for an event - the event
already existed, since dirty is set on success and cleared by the commit, so !isDirty() is
commit-happened.

Three correctness-adjacent sleeps deliberately kept, because there the elapsed time is the
instrument rather than a guess: a poll-rate assertion needs a window, "still paused after 1s" is a
negative property, and a 3s soak gives the invariant sampler many chances to catch a violation.
Everything else is fixture. Notably OffsetCommittingSanityTest's JUST_SLEEP arm is a deliberately
unverified dwell - awaiting there would collapse it into CHECK_CONSUMED and silently delete the
boundary case.

One behavioural finding: the SASL poll retry back-off is 5s, so the old sleep(5000) landed
close() mid-back-off by luck rather than design. Logs confirm close() breaks the back-off via
closeInProgressSignal in ~90ms.

No assertion was deleted, nothing disabled, no coverage lost - two tests gained assertions
(RetriesTest now verifies the retried half actually succeeds, which nothing did before).

Verification

  • Core: 328 tests, 0 failures, 10 skipped. Baseline match confirmed at each step (321/0/10 before the
    new negative-control class was added).
  • vertx 17/0/1. Each changed class run 5 consecutive times.
  • Copyright, TODO-index and SELF_HOSTED_RUNNER gates green.

Checklist

  • Docs updated - docs/SELF_HOSTED_RUNNER.md, docs/TODO_INDEX.md, and the inflight note
    reduced to the one still-open item (branch-parallel-measurement-contamination.md)
  • Tests added/updated - BlockedThreadAsserterTest added as a negative control; 7 test files
    changed; 2 gained assertions
  • Title & body reflect the final content of this PR
  • Self-hosted runner / security implications considered - docs/SELF_HOSTED_RUNNER.md is touched
    only to keep its gate green; no workflow or runner configuration changes

astubbs added 3 commits August 8, 2026 04:01
…ing on clocks

Two defects found while running Apache Kafka's own test suite against a
patched build (#255). Both make the suite mean something other than
what it says.

1. The core tests jar was configuring every downstream module's JUnit runner.

src/test/resources/junit-platform.properties is packaged at the ROOT of the
core tests jar. Eight modules depend on that jar - the four integrations
plus every example - and JUnit reads the first junit-platform.properties on
the classpath. So all eight silently ran with parallel.enabled and
dynamic.factor=20 baked in at CORE's build time; their own setting was
never consulted, and there was no way to opt out.

That inverts the root pom's intent: the ci profile sets
parallel-tests=false deliberately, because JUnit thread parallelism
contends on static state and CI parallelises by forking JVMs instead. A
locally-built jar bakes true, so a downstream module could inherit
enabled=true, factor=20 exactly where the project decided it did not want
it. It surfaced as 159 of 188 Kafka tests erroring on shared state.

Moved to surefire/failsafe configurationParameters in core's pom. As build
config it is per-module by construction: each module evaluates its own
${parallel-tests}, nothing is packaged, nothing leaks, and it outranks a
properties file if one is reintroduced. Core keeps its parallelism -
measured 102 worker threads before and 103 after. The eight downstream
modules revert to the JUnit default, which is what they would always have
had.

2. BlockedThreadAsserter asserted on a clock instead of on causality.

assertUnblocksAfter scheduled the unblocker on a timer, then asserted the
blocked function's wall-clock elapsed time was at least as long. It failed
at 19.985s >= 20s - a 15ms scheduler wobble that says nothing about the
behaviour under test - and it deliberately slept 20s to do it.

The property it wants is an ordering fact, so it is now asserted as one:
both events take a tick from a shared monotonic sequence, and the return
must come after the unblock. No clocks, no sleeps, no timer. It also
catches more than before - a function that never blocked takes the lower
tick and fails, where previously it could pass if the timer had not fired.
ProducerManagerTest goes from 23.06s to 3.32s.

Also removes a redundant Thread.sleep(1000) in WorkManagerTest: it advances
a mock clock, which is the only time source the retry path reads, then
slept a real second anyway. The same idiom appears twice earlier in the
file without one. Verified over 5 consecutive runs.

Full core suite green: 321 tests, 0 failures.
…are the test

Surveyed every Thread.sleep under src/test and src/test-integration across
all modules against one rule: a sleep that waits and hopes a thing happened
before asserting is a correctness sleep and goes; a sleep that IS the
behaviour or the scenario stays.

Eight removed, across seven files. The clearest two:

ShardManagerTest slept 10ms of WALL CLOCK three times purely to advance a
MOCK clock, then set it to Instant.now(). Replaced with clock.add(10,
MILLIS) - and the two remaining setInstant(now) calls had to go with them,
or the clock would jump backwards.

CloseAndOpenOffsetTest slept 500ms for a commit, its own comment saying
"sleep is lazy but much much simpler" with a TODO for an event. The event
already existed: dirty is set on success and cleared by the commit, so
!isDirty() IS commit-happened. TODO resolved.

Also: PCMetricsTest's 1s anti-race sleep became an await on the trailing
meters; MockConsumerEarlyCloseTest now counts auth failures actually
served; OffsetEncodingBackPressureTest's sleep sat directly in front of the
await that was already the real gate; VertxTest gained a latch inside the
user function; RetriesTest awaits the retry drain and now VERIFIES the
retried half succeeds, which nothing did before.

Three correctness-adjacent sleeps deliberately kept, because there the
elapsed time is the instrument rather than a guess: a poll-RATE assertion
needs a window; "still paused after 1s" is a negative property; and a 3s
soak gives the invariant sampler many chances to catch a violation.

Everything else is fixture: simulated processing delay, deliberately
blocked workers, drip-feeds, chaos cadences, deadlock windows. Notably
OffsetCommittingSanityTest's JUST_SLEEP arm is a deliberately unverified
dwell - awaiting there would collapse it into CHECK_CONSUMED and silently
delete the boundary case.

One behavioural finding: the SASL poll retry back-off is 5s, so the old
sleep(5000) landed close() mid-back-off by luck rather than design. The
await threshold is 2 served failures - enough to prove the poll loop
retries, while close() still lands mid-back-off. Logs confirm close()
breaks the back-off via closeInProgressSignal in ~90ms.

No assertion deleted, nothing disabled, no coverage lost - two tests gained
assertions. Core 321/0/10 matches baseline exactly; vertx 17/0/1; each
changed class run 5 consecutive times.
…us commits

The BlockedThreadAsserter rewrite made the assertion WEAKER in exactly the
dimension it was meant to strengthen. Four reviewers found it
independently; one reproduced it - a non-blocking function passed the new
ordering assertion 177 times in 200. The old wall-clock version was flaky
by 15ms; this was unsound by 88%.

Cause: blockedFunctionEntered.countDown() was the first statement in the
thread body, before the function ran, so the latch meant "thread started",
not "reached the blocking call". The main thread usually won the race to
tick, so a function that never blocked still took the higher tick.

Second P1, found only by the adversarial lens: a blocked function that
THREW was scored as a pass. The catch logged, then the return tick and
methodReturned were set regardless. The timing version failed that case.

Both fixed: the function is now proven still parked before the unblocker
ticks, and its throwable is captured and asserted null. The tick comparison
stays as a second line of defence, and the return wait is bounded at 20s to
match its callers rather than silently taking Awaitility's 10s default in a
file tuned for PIT.

Adds BlockedThreadAsserterTest - the negative control AGENTS.md requires and
that neither previous commit had. Building it refuted the obvious design:
with only "returns immediately", removing the guard failed just 10 of 20
runs. The deterministic case is a function that returns on its own timer
AFTER the unblocker ticks, which the ordering check provably cannot catch.
Guard removed: red 20/20. Guard restored: green 20/20.

Also from the review: the pom's duplicated parallelism config is now one
property; MockConsumerEarlyCloseTest counts only poll-path auth failures, so
">= 2" means what its comment claims; RetriesTest wraps its await in
try/finally with a daemon sampler so a timeout cannot leak the thread;
CloseAndOpenOffsetTest requires the last success to have registered, not
just a clean dirty flag; and the copyright, TODO-index and SELF_HOSTED_RUNNER
gates are green again.

The inflight note becomes branch-parallel-measurement-contamination.md,
carrying only the still-open item. docs/inflight/AGENTS.md forbids the
"delete this when it merges" marker the old one had, and the solved-work
narrative belongs in a commit message, which is where it now is.

Prior art I should have read before starting, and did not:
docs/solutions/test-flakiness/unit-tests-parallelise-by-forking-not-threading
had already measured this - fork x12 is 1:38 and reliable, thread x20 is
~2:32 and intermittent. So the leak was not merely "modules inherited a
setting", it was forcing eight modules into the configuration this repo had
measured as unreliable and deliberately switched off.

Core: 328 tests, 0 failures, 10 skipped.
@github-actions

github-actions Bot commented Aug 8, 2026

Copy link
Copy Markdown

Dependency Review

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

License Issues

parallel-consumer-core/pom.xml

PackageVersionLicenseIssue Type
org.apache.maven.plugins:maven-failsafe-pluginNullUnknown License
org.apache.maven.plugins:maven-surefire-pluginNullUnknown License
Excluded from license check: pkg:githubactions/actions/github-script

OpenSSF Scorecard

PackageVersionScoreDetails
maven/org.apache.maven.plugins:maven-failsafe-plugin UnknownUnknown
maven/org.apache.maven.plugins:maven-surefire-plugin UnknownUnknown

Scanned Files

  • parallel-consumer-core/pom.xml

@claude

claude Bot commented Aug 8, 2026 •

Copy link
Copy Markdown

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


Claude's Code Review of PR #265

Tasks

  • Gather context (PR description, changed files, diff)
  • Run /code-review skill against this PR
  • Post findings as inline PR comments

Summary

Ran the code-review skill over the diff (origin/master...HEAD). It posted 3 inline findings on the PR:

  1. BlockedThreadAsserter.java:190 — The ordering check compares tick values assigned by code position, not true causality. It only reliably catches a spurious "returned without blocking" case inside the 500ms still-blocked window — a regression where the function returns on its own timer later (e.g. ~1s, after the unblocker has already ticked) would still get a higher tick purely by code-position ordering and pass, even though it never actually blocked on the unblocker.

  2. MockConsumerEarlyCloseTest.java:122 — The new Awaitility.await().atMost(60, SECONDS) exactly matches the class-level @Timeout(60000L), leaving no headroom for close()/cleanup afterward. Under a slow CI runner this could turn a clear assertion failure into an opaque JUnit timeout.

  3. VertxTest.java:262 — innerFunctionStarted (latch count of 1) only confirms one of the two concurrently-primed records' worker callbacks has started before releasing latchTwo, slightly weakening the concurrency guarantee the original 1s sleep implicitly gave. Doesn't currently fail the test, but worth a second latch count if the intent is "both are inflight."

All three are minor/moderate robustness concerns rather than correctness bugs in the PR's stated fixes — the core defects described in the PR body (junit-platform.properties leaking into downstream modules, the two BlockedThreadAsserter P1s, and the sleep-removal sweep) all look correctly addressed based on the diff and the described verification (328 core tests, negative-control test added, guard-removed/guard-restored 20/20 checks).

No repo-level or user-level CLAUDE.md exists in this repo, so no project-specific convention checks applied.

@github-actions

github-actions Bot commented Aug 8, 2026 •

Copy link
Copy Markdown

✅ Duplicate Code Report

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

✅ PMD CPD

PR Base Change
Clones 29 28 🫤 +1
Duplicated lines 887 853 :face_with_raised_eyebrow: +34
Duplication 2.47% 2.38% 🫤 +0.09%
Rule Limit Status
Max duplication 5% ✅ Pass (2.47%)
Max increase vs base +0.1% ✅ Pass (+0.09%)
⚠️ 1 new clones introduced
  • 17 lines (75 tokens): parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/MockConsumerCommitTimeoutTest.java:94 <-> parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/MockConsumerEarlyCloseTest.java:103

✅ jscpd (language-agnostic)

PR Base Change
Clones 75 75 ➖ 0
Duplicated lines 1052 1060 👍 -8
Duplication 2.98% 3.04% 🙂 -0.06%
Rule Limit Status
Max duplication 5% ✅ Pass (2.98%)
Max increase vs base +0.1% ✅ Pass (-0.06%)
⚠️ 2 new clones introduced
  • 8 lines: parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/MockConsumerEarlyCloseTest.java:9 <-> parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/MockConsumerSaslAuthenticationTest.java:8
  • 13 lines: parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/CommitRejectionTestBase.java:12 <-> parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/MockConsumerEarlyCloseTest.java:15

Powered by astubbs/duplicate-code-cross-check

@github-actions

github-actions Bot commented Aug 8, 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/internal/utils/BlockedThreadAsserter.java parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/internal/utils/BlockedThreadAsserterTest.java 35.4
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/JStreamParallelStreamProcessor.java parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/internal/PCModule.java 30.1

🔺 Increased similarities

File A File B Base (%) PR (%) Change
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/CommitRejectionTestBase.java parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/MockConsumerCommitTimeoutTest.java 32.4 32.9 +0.5
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/MockConsumerSaslAuthenticationTest.java parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/MockConsumerTest.java 47.0 47.5 +0.5
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/CommitRejectionTestBase.java parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/MockConsumerTest.java 32.5 33.0 +0.5
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/MockConsumerCommitTimeoutTest.java parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/MockConsumerSaslAuthenticationTest.java 49.6 49.8 +0.3
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/JStreamParallelEoSStreamProcessor.java parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/ParallelStreamProcessor.java 37.5 37.7 +0.2
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/JStreamParallelStreamProcessor.java parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/ParallelStreamProcessor.java 37.2 37.4 +0.2
parallel-consumer-vertx/src/main/java/bz/stub/parallelconsumer/vertx/JStreamVertxParallelStreamProcessor.java parallel-consumer-vertx/src/main/java/bz/stub/parallelconsumer/vertx/VertxParallelStreamProcessor.java 39.8 40.0 +0.2
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/ParallelStreamProcessor.java parallel-consumer-vertx/src/main/java/bz/stub/parallelconsumer/vertx/JStreamVertxParallelStreamProcessor.java 33.1 33.2 +0.2
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/JStreamParallelStreamProcessor.java parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/PollContextInternal.java 31.8 31.9 +0.2
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/JStreamParallelStreamProcessor.java parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/ParallelEoSStreamProcessor.java 51.0 51.2 +0.1
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/ParallelEoSStreamProcessor.java parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/ParallelStreamProcessor.java 45.8 46.0 +0.1
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/ChaosChurnStormIT.java 49.0 49.2 +0.1
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/ParallelEoSStreamProcessor.java parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/PollContextInternal.java 34.0 34.1 +0.1
parallel-consumer-vertx/src/main/java/bz/stub/parallelconsumer/vertx/JStreamVertxParallelEoSStreamProcessor.java parallel-consumer-vertx/src/main/java/bz/stub/parallelconsumer/vertx/VertxParallelStreamProcessor.java 35.6 35.8 +0.1
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/JStreamParallelEoSStreamProcessor.java parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/JStreamParallelStreamProcessor.java 61.3 61.4 +0.1
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/JStreamParallelEoSStreamProcessor.java parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/PollContextInternal.java 32.8 32.9 +0.1
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/PollContext.java parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/RecordContextInternal.java 36.4 36.5 +0.1
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/JStreamParallelStreamProcessor.java parallel-consumer-vertx/src/main/java/bz/stub/parallelconsumer/vertx/JStreamVertxParallelStreamProcessor.java 30.4 30.5 +0.1
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/NoEncodingPossibleException.java parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/OffsetDecodingError.java 45.2 45.3 +0.1
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/MockConsumerCommitTimeoutTest.java parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/MockConsumerTest.java 56.7 56.8 +0.1

...and 23 more

Full similarity report
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 53.47 ⚠️
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/internal/InternalException.java 38.7
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/PCRetriableException.java 35.87
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/EncodingNotSupportedException.java 35.25
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/RunLengthV1EncodingNotSupported.java 34.05
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/BitSetEncodingNotSupportedException.java 33.75
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/RunLengthV2EncodingNotSupported.java 33.2
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/OffsetDecodingError.java 33.19
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 61.4 ⚠️
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/ParallelEoSStreamProcessor.java 55.06 ⚠️
parallel-consumer-vertx/src/main/java/bz/stub/parallelconsumer/vertx/JStreamVertxParallelEoSStreamProcessor.java 40.32
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/ParallelStreamProcessor.java 37.68
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/PollContextInternal.java 32.93
parallel-consumer-vertx/src/main/java/bz/stub/parallelconsumer/vertx/JStreamVertxParallelStreamProcessor.java 31.55
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 61.4 ⚠️
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/ParallelEoSStreamProcessor.java 51.18 ⚠️
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/ParallelStreamProcessor.java 37.37
parallel-consumer-vertx/src/main/java/bz/stub/parallelconsumer/vertx/JStreamVertxParallelEoSStreamProcessor.java 32.54
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/PollContextInternal.java 31.95
parallel-consumer-vertx/src/main/java/bz/stub/parallelconsumer/vertx/JStreamVertxParallelStreamProcessor.java 30.46
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/internal/PCModule.java 30.08
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 35.87
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/internal/InternalException.java 32.44
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 53.47 ⚠️
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/internal/InternalException.java 51.75 ⚠️
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/EncodingNotSupportedException.java 43.03
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/BitSetEncodingNotSupportedException.java 33.11
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/OffsetDecodingError.java 32.33
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/internal/InternalRuntimeException.java 30.55
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 31.4
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 55.06 ⚠️
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/JStreamParallelStreamProcessor.java 51.18 ⚠️
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/ParallelStreamProcessor.java 45.97
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/PollContextInternal.java 34.12
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/internal/AbstractParallelEoSStreamProcessor.java 32.93
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/internal/TestParallelEoSStreamProcessor.java 31.18
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 45.97
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/JStreamParallelEoSStreamProcessor.java 37.68
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/JStreamParallelStreamProcessor.java 37.37
parallel-consumer-vertx/src/main/java/bz/stub/parallelconsumer/vertx/JStreamVertxParallelStreamProcessor.java 33.24
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 36.54
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/PollContextInternal.java 32.03
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 34.12
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/RecordContextInternal.java 33.42
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/JStreamParallelEoSStreamProcessor.java 32.93
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/PollContext.java 32.03
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/JStreamParallelStreamProcessor.java 31.95
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 36.54
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/PollContextInternal.java 33.42
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/main/java/bz/stub/parallelconsumer/ParallelEoSStreamProcessor.java 32.93
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/internal/BrokerPollSystem.java 32.78
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 32.78
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.46
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 59.4 ⚠️
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/ParallelConsumerException.java 51.75 ⚠️
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/OffsetDecodingError.java 50.86 ⚠️
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/NoEncodingPossibleException.java 47.82
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/internal/InternalRuntimeException.java 39.61
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/ExceptionInUserFunctionException.java 38.7
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/BitSetEncodingNotSupportedException.java 35.51
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/RunLengthV1EncodingNotSupported.java 32.54
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/PCRetriableException.java 32.44
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/RunLengthV2EncodingNotSupported.java 31.72
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 39.61
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/EncodingNotSupportedException.java 31.09
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/ParallelConsumerException.java 30.55
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/test/java/bz/stub/parallelconsumer/internal/PCModuleTestEnv.java 32.15
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/JStreamParallelStreamProcessor.java 30.08
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 31.4
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/internal/ProducerManagerTest.java 30.2
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 34.46
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/internal/utils/CollectionUtils.java 32.3
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.76
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/internal/utils/Java8StreamUtils.java 34.46
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 50.14 ⚠️
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/RunLengthV1EncodingNotSupported.java 36.64
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/RunLengthV2EncodingNotSupported.java 35.72
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/internal/InternalException.java 35.51
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/ExceptionInUserFunctionException.java 33.75
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/ParallelConsumerException.java 33.11
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/OffsetDecodingError.java 31.84
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 59.4 ⚠️
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/BitSetEncodingNotSupportedException.java 50.14 ⚠️
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/OffsetDecodingError.java 48.13
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/RunLengthV1EncodingNotSupported.java 46.73
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/RunLengthV2EncodingNotSupported.java 45.56
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/NoEncodingPossibleException.java 45.48
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/ParallelConsumerException.java 43.03
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/ExceptionInUserFunctionException.java 35.25
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/internal/InternalRuntimeException.java 31.09
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.82
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/EncodingNotSupportedException.java 45.48
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/OffsetDecodingError.java 45.31
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/RunLengthV1EncodingNotSupported.java 36.64
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/RunLengthV2EncodingNotSupported.java 35.72
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.86 ⚠️
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/EncodingNotSupportedException.java 48.13
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/NoEncodingPossibleException.java 45.31
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/ExceptionInUserFunctionException.java 33.19
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/ParallelConsumerException.java 32.33
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/BitSetEncodingNotSupportedException.java 31.84
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/RunLengthV1EncodingNotSupported.java 30.79
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/RunLengthV2EncodingNotSupported.java 30.02
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 63.2 ⚠️
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/EncodingNotSupportedException.java 46.73
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/BitSetEncodingNotSupportedException.java 36.64
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/NoEncodingPossibleException.java 36.64
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/ExceptionInUserFunctionException.java 34.05
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/internal/InternalException.java 32.54
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/OffsetDecodingError.java 30.79
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 63.2 ⚠️
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/EncodingNotSupportedException.java 45.56
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/BitSetEncodingNotSupportedException.java 35.72
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/NoEncodingPossibleException.java 35.72
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/ExceptionInUserFunctionException.java 33.2
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/internal/InternalException.java 31.72
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/OffsetDecodingError.java 30.02
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.87
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 38.38
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/state/PartitionState.java 32.87
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 35.93
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 35.93
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 38.38
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/test/java/bz/stub/parallelconsumer/AmbientProbeExtensionTest.java 30.14
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 34.31
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.06 ⚠️
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/TransactionAndCommitModeTest.java 43.63
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/MultiInstanceRebalanceTest.java 35.48
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.43
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/TransactionAndCommitModeTest.java 38.88
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/MultiInstanceHighVolumeTest.java 35.48
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 36.13
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 36.13
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 53.82 ⚠️
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/MultiInstanceHighVolumeTest.java 43.63
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/MultiInstanceRebalanceTest.java 38.88
parallel-consumer-vertx/src/test-integration/java/bz/stub/parallelconsumer/vertx/integrationTests/VertxConcurrencyIT.java 31.44
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/TransactionTimeoutsTest.java

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

File Similarity (%)
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/internal/ProducerManagerTest.java 30.13
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.06 ⚠️
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/TransactionAndCommitModeTest.java 53.82 ⚠️
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/MultiInstanceRebalanceTest.java 39.43
parallel-consumer-vertx/src/test-integration/java/bz/stub/parallelconsumer/vertx/integrationTests/VertxConcurrencyIT.java 35.12
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/ChaosChurnStormIT.java 49.18
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/chaostests/ChaosRevokeUnderWorkIT.java 35.67
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/AbstractRevokeUnderWorkScenario.java 49.18
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/chaostests/ChaosScenarioBase.java 38.09
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 47.94
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 47.94
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/chaostests/AbstractRevokeUnderWorkScenario.java 35.67
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/ChaosChurnStormIT.java 38.09
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 33.15
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 30.14
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.5
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 49.61
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/QuarantineRegistryScriptTest.java 47.71
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/MockConsumerTest.java 32.98
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/MockConsumerCommitTimeoutTest.java 32.88
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.97 ⚠️
parallel-consumer-mutiny/src/test/java/bz/stub/parallelconsumer/mutiny/MutinyBatchTest.java 50.69 ⚠️
parallel-consumer-vertx/src/test/java/bz/stub/parallelconsumer/vertx/VertxBatchTest.java 44.78
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/BatchTestBase.java 30.5
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/MockConsumerEarlyCloseTest.java 61.06 ⚠️
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/MockConsumerTest.java 56.83 ⚠️
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/MockConsumerSaslAuthenticationTest.java 49.84
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/CommitRejectionTestBase.java 32.88
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/MockConsumerEarlyCloseTest.java

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

File Similarity (%)
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/MockConsumerCommitTimeoutTest.java 61.06 ⚠️
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/MockConsumerSaslAuthenticationTest.java 49.03
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/MockConsumerTest.java 48.5
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 49.84
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/MockConsumerEarlyCloseTest.java 49.03
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/MockConsumerTest.java 47.52
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/MockConsumerTest.java

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

File Similarity (%)
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/MockConsumerCommitTimeoutTest.java 56.83 ⚠️
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/MockConsumerEarlyCloseTest.java 48.5
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/MockConsumerSaslAuthenticationTest.java 47.52
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/CommitRejectionTestBase.java 32.98
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 32.85
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 32.85
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 49.61
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/QuarantineRegistryScriptTest.java 33.05
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 47.71
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/QuarantineLaneReportScriptTest.java 33.05
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 90.13 ⚠️
parallel-consumer-mutiny/src/test/java/bz/stub/parallelconsumer/mutiny/TestConventionsArchTest.java 89.45 ⚠️
parallel-consumer-reactor/src/test/java/bz/stub/parallelconsumer/reactor/TestConventionsArchTest.java 89.45 ⚠️
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 32.15
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/internal/ProducerManagerTest.java

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

File Similarity (%)
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/internal/ProducerManager.java 30.2
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/TransactionTimeoutsTest.java 30.13
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 31.18
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 35.43
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 35.43
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.76
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/internal/utils/Java8StreamUtils.java 32.3
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 33.15
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 34.31
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 38.9
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 38.9
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.51
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.51
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.8 ⚠️
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 78.93 ⚠️
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/CoreBatchTest.java 50.69 ⚠️
parallel-consumer-vertx/src/test/java/bz/stub/parallelconsumer/vertx/VertxBatchTest.java 48.91
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 71.09 ⚠️
parallel-consumer-mutiny/src/test/java/bz/stub/parallelconsumer/mutiny/MutinyTest.java

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

File Similarity (%)
parallel-consumer-reactor/src/test/java/bz/stub/parallelconsumer/reactor/ReactorTest.java 32.19
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.24
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-vertx/src/test/java/bz/stub/parallelconsumer/vertx/TestConventionsArchTest.java 90.92 ⚠️
parallel-consumer-reactor/src/test/java/bz/stub/parallelconsumer/reactor/TestConventionsArchTest.java 90.24 ⚠️
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/TestConventionsArchTest.java 89.45 ⚠️
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.8 ⚠️
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 78.93 ⚠️
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/CoreBatchTest.java 51.97 ⚠️
parallel-consumer-vertx/src/test/java/bz/stub/parallelconsumer/vertx/VertxBatchTest.java 50.14 ⚠️
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 71.09 ⚠️
parallel-consumer-reactor/src/test/java/bz/stub/parallelconsumer/reactor/ReactorTest.java

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

File Similarity (%)
parallel-consumer-mutiny/src/test/java/bz/stub/parallelconsumer/mutiny/MutinyTest.java 32.19
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.24
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-vertx/src/test/java/bz/stub/parallelconsumer/vertx/TestConventionsArchTest.java 90.92 ⚠️
parallel-consumer-mutiny/src/test/java/bz/stub/parallelconsumer/mutiny/TestConventionsArchTest.java 90.24 ⚠️
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/TestConventionsArchTest.java 89.45 ⚠️
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-vertx/src/main/java/bz/stub/parallelconsumer/vertx/VertxParallelEoSStreamProcessor.java 40.83
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/JStreamParallelEoSStreamProcessor.java 40.32
parallel-consumer-vertx/src/main/java/bz/stub/parallelconsumer/vertx/JStreamVertxParallelStreamProcessor.java 39.92
parallel-consumer-vertx/src/main/java/bz/stub/parallelconsumer/vertx/VertxParallelStreamProcessor.java 35.75
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/JStreamParallelStreamProcessor.java 32.54
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 39.98
parallel-consumer-vertx/src/main/java/bz/stub/parallelconsumer/vertx/JStreamVertxParallelEoSStreamProcessor.java 39.92
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/ParallelStreamProcessor.java 33.24
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/JStreamParallelEoSStreamProcessor.java 31.55
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/JStreamParallelStreamProcessor.java 30.46
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 42.88
parallel-consumer-vertx/src/main/java/bz/stub/parallelconsumer/vertx/JStreamVertxParallelEoSStreamProcessor.java 40.83
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/internal/ExternalEngine.java 39.46
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 42.88
parallel-consumer-vertx/src/main/java/bz/stub/parallelconsumer/vertx/JStreamVertxParallelStreamProcessor.java 39.98
parallel-consumer-vertx/src/main/java/bz/stub/parallelconsumer/vertx/JStreamVertxParallelEoSStreamProcessor.java 35.75
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.12
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/TransactionAndCommitModeTest.java 31.44
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-mutiny/src/test/java/bz/stub/parallelconsumer/mutiny/TestConventionsArchTest.java 90.92 ⚠️
parallel-consumer-reactor/src/test/java/bz/stub/parallelconsumer/reactor/TestConventionsArchTest.java 90.92 ⚠️
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/TestConventionsArchTest.java 90.13 ⚠️
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 50.14 ⚠️
parallel-consumer-mutiny/src/test/java/bz/stub/parallelconsumer/mutiny/MutinyBatchTest.java 48.91
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/CoreBatchTest.java 44.78

@github-actions

github-actions Bot commented Aug 8, 2026

Copy link
Copy Markdown

✅ SpotBugs Report

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

astubbs added a commit that referenced this pull request Aug 11, 2026
Both tests went red on this PR's own CI while it changed no Java at all, and
both have a written fix sitting in an open PR. That is precisely the case the
quarantine lane exists for: "tests that are red on master's gating CI when the
fix lives in another, open PR".

Leaving them red is the option the docs explicitly rule out - ambiguous checks
and error-prone merge decisions - and @disabled is the other, which loses the
signal entirely. Quarantine keeps them running in the non-gating lane while
taking them out of the gates.

WHY THEY QUALIFY

Rule 1, no quarantine without diagnosis - both are diagnosed, in
docs/inflight/test-untracked-ci-flakes.md:

  PCMetricsTest.metricsRegisterBinding compares a registry gauge against an
  expectation built from a test-side counter snapshot taken earlier in the
  method. Two independently-advancing values, read at different instants, with
  nothing holding processing still between them. Seen as expected 203.0 but was
  207.0 - four more records completed in the gap, so the metric was MORE current
  than the expectation testing it.

  OffsetEncodingBackPressureTest.backPressureShouldPreventTooManyMessagesBeing-
  QueuedForProcessing sleeps out the static retry delay instead of awaiting the
  retry event, then asserts on a count still in motion. Fails as ConditionTimeout,
  expected 139 but was 136 within 30 seconds, when the runner is loaded enough
  that the sleep expires first.

Rule 2, master-state not PR-state - both fail regardless of PR content. This PR
contains no Java and no pom.xml, and the pair fired on two consecutive runs of
one unchanged commit, each time a different one of them.

fixedBy is #265 for both, verified against its diff rather than its title:
it replaces the Thread.sleep(1000) above the metrics assertions with an
await().untilAsserted(...) on the trailing meters, and swaps
sleepQuietly(DEFAULT_STATIC_RETRY_DELAY) for
await().atMost(ofSeconds(30)).until(() -> attempts.get() >= 2).

flapping = true on both. They pass most runs - the unit lane was green on eight
consecutive PR runs across three branches the same day - so a pass proves nothing
and must not post the merge-blocking "your fix landed" thread that deterministic
quarantines get.

WHY THEY ARE VISIBLE NOW

#224 removed the surefire retry that was absorbing them. They were always
failing at this rate; the retry was buying the green. This is the ledger entry
from that PR getting its first real use.

The copyright header on OffsetEncodingBackPressureTest gains the modifications
line, required once an upstream-derived file is touched.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01R8He6kk23K3gN4qtojL9PE
astubbs added a commit that referenced this pull request Aug 11, 2026
Two enforced gates disagreed, and the registry could not satisfy both.

`bin/check-quarantine-owners.sh` and `bin/quarantine-lane-report.sh` both parsed
the owner marker with `grep -oE 'Owner: PR #[0-9]+'`, so the registry had to write
a BARE number. `bin/check-issue-refs.sh` rejects a bare `#NN` on an added line,
because the fork's numbers sit inside confluentinc's range and a bare one is a
coin flip about which repo is meant. Adding the first two entries to this registry
therefore failed the issue-ref gate by construction - not through carelessness,
but because the two formats were mutually exclusive.

The previous commit worked around that with the issue-ref gate's documented
`issue-refs: N/A` opt-out. That was the wrong instrument: the opt-out exists for
references that genuinely need no qualifier, not for a format conflict that can be
fixed. An N/A left in place would also have quietly become permanent, since every
future entry hits the same wall.

Both parsers now accept `Owner: PR #NN`, `Owner: PR astubbs#NN`, and
`Owner: PR astubbs/parallel-consumer#NN`, and the number is extracted from the
`#NN` tail rather than the whole match, so a digit inside a qualifier cannot win.
The bare form still parses, so existing entries keep working; the registry's
format spec now asks for the qualified one and says why.

Verified three ways rather than by inspection:

  qualified   `Owner: PR #265`  -> resolves, owner claim verified
  bare        `Owner: PR #265`         -> still resolves (back-compat intact)
  bogus       `Owner: PR astubbs#999999` -> ERROR, PR does not exist

The third is the one that matters. A parser that silently failed to match would
also report no error, and would look identical to a pass - so the control had to
show a wrong number being CAUGHT, not just a right number being accepted.

Both parsers are changed together and carry a comment saying so; they read the
same marker and drifting apart would mean the lane reporter attributing an entry
to a different PR than the audit checks.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01R8He6kk23K3gN4qtojL9PE
astubbs added a commit that referenced this pull request Aug 11, 2026
Both tests went red on this PR's own CI while it changed no Java at all, and
both have a written fix sitting in an open PR. That is precisely the case the
quarantine lane exists for: "tests that are red on master's gating CI when the
fix lives in another, open PR".

Leaving them red is the option the docs explicitly rule out - ambiguous checks
and error-prone merge decisions - and @disabled is the other, which loses the
signal entirely. Quarantine keeps them running in the non-gating lane while
taking them out of the gates.

WHY THEY QUALIFY

Rule 1, no quarantine without diagnosis - both are diagnosed, in
docs/inflight/test-untracked-ci-flakes.md:

  PCMetricsTest.metricsRegisterBinding compares a registry gauge against an
  expectation built from a test-side counter snapshot taken earlier in the
  method. Two independently-advancing values, read at different instants, with
  nothing holding processing still between them. Seen as expected 203.0 but was
  207.0 - four more records completed in the gap, so the metric was MORE current
  than the expectation testing it.

  OffsetEncodingBackPressureTest.backPressureShouldPreventTooManyMessagesBeing-
  QueuedForProcessing sleeps out the static retry delay instead of awaiting the
  retry event, then asserts on a count still in motion. Fails as ConditionTimeout,
  expected 139 but was 136 within 30 seconds, when the runner is loaded enough
  that the sleep expires first.

Rule 2, master-state not PR-state - both fail regardless of PR content. This PR
contains no Java and no pom.xml, and the pair fired on two consecutive runs of
one unchanged commit, each time a different one of them.

fixedBy is #265 for both, verified against its diff rather than its title:
it replaces the Thread.sleep(1000) above the metrics assertions with an
await().untilAsserted(...) on the trailing meters, and swaps
sleepQuietly(DEFAULT_STATIC_RETRY_DELAY) for
await().atMost(ofSeconds(30)).until(() -> attempts.get() >= 2).

flapping = true on both. They pass most runs - the unit lane was green on eight
consecutive PR runs across three branches the same day - so a pass proves nothing
and must not post the merge-blocking "your fix landed" thread that deterministic
quarantines get.

WHY THEY ARE VISIBLE NOW

#224 removed the surefire retry that was absorbing them. They were always
failing at this rate; the retry was buying the green. This is the ledger entry
from that PR getting its first real use.

The copyright header on OffsetEncodingBackPressureTest gains the modifications
line, required once an upstream-derived file is touched.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01R8He6kk23K3gN4qtojL9PE
astubbs added a commit that referenced this pull request Aug 11, 2026
Two enforced gates disagreed, and the registry could not satisfy both.

`bin/check-quarantine-owners.sh` and `bin/quarantine-lane-report.sh` both parsed
the owner marker with `grep -oE 'Owner: PR #[0-9]+'`, so the registry had to write
a BARE number. `bin/check-issue-refs.sh` rejects a bare `#NN` on an added line,
because the fork's numbers sit inside confluentinc's range and a bare one is a
coin flip about which repo is meant. Adding the first two entries to this registry
therefore failed the issue-ref gate by construction - not through carelessness,
but because the two formats were mutually exclusive.

The previous commit worked around that with the issue-ref gate's documented
`issue-refs: N/A` opt-out. That was the wrong instrument: the opt-out exists for
references that genuinely need no qualifier, not for a format conflict that can be
fixed. An N/A left in place would also have quietly become permanent, since every
future entry hits the same wall.

Both parsers now accept `Owner: PR #NN`, `Owner: PR astubbs#NN`, and
`Owner: PR astubbs/parallel-consumer#NN`, and the number is extracted from the
`#NN` tail rather than the whole match, so a digit inside a qualifier cannot win.
The bare form still parses, so existing entries keep working; the registry's
format spec now asks for the qualified one and says why.

Verified three ways rather than by inspection:

  qualified   `Owner: PR #265`  -> resolves, owner claim verified
  bare        `Owner: PR #265`         -> still resolves (back-compat intact)
  bogus       `Owner: PR astubbs#999999` -> ERROR, PR does not exist

The third is the one that matters. A parser that silently failed to match would
also report no error, and would look identical to a pass - so the control had to
show a wrong number being CAUGHT, not just a right number being accepted.

Both parsers are changed together and carry a comment saying so; they read the
same marker and drifting apart would mean the lane reporter attributing an entry
to a different PR than the audit checks.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01R8He6kk23K3gN4qtojL9PE
astubbs added a commit that referenced this pull request Aug 11, 2026
…was wrong

Three review findings, all correct, two of them mine from the previous commit.

THE QUARANTINE THAT SHOULD NOT HAVE HAPPENED

OffsetEncodingBackPressureTest.backPressureShouldPreventTooManyMessagesBeing-
QueuedForProcessing is un-quarantined, and its registry entry removed.

It was tagged with the diagnosis "sleeps out the static retry delay instead of
awaiting the retry event" and owned by #265, which replaces exactly that
sleepQuietly(DEFAULT_STATIC_RETRY_DELAY) with an await. The narrative fitted. The
line numbers do not.

The failure is at line 211 of the commit CI ran: the
waitAtMost(defaultTimeout).untilAsserted(...) block asserting committed offset
metadata, specifically
Truth8.assertThat(incompletes.getHighestSeenOffset()).hasValue(expectedHighestSeen)
- the "value of: optional.get()" in the failure text is that Optional. It runs
BEFORE the retry section #265 rewrites, and a change downstream of a
failing assertion cannot fix it.

So the real failure is a timeout waiting for the high-water mark to reach 139,
stuck at 136, and nothing currently explains why three records never arrive.
Rule 1 applies: no quarantine without diagnosis, undiagnosed red stays red and
blocks, on purpose. Taking it out of the gating lane on a diagnosis that does not
describe it is worse than leaving it red - it removes the pressure while
pretending the cause is known.

The error worth remembering: the fix PR was matched to the failure by
subject-matter resemblance - both concern this test, both concern waiting -
instead of by checking that the changed lines execute before the failing
assertion. Match a fixedBy to a stack line, not to a theme.

PCMetricsTest keeps its quarantine. Its diagnosis is a source-level read of two
values sampled at different instants, and #265 inserts its await BEFORE
the failing assertion, so it can actually gate it.

A CROSS-CHECK THAT HAD SILENTLY STOPPED CHECKING

check-quarantine-owners.sh compares the annotation's fixedBy against the
registry's Owner line, and parsed it as `fixedBy = "PR #NN"`. The annotations
added here write `fixedBy = "#265"`, so the grep matched nothing, the
declared value came back empty, and the advisory could never fire. Adding the
qualified form to one side quietly disabled the check that keeps the two sides
honest.

It now accepts the same three forms as the Owner marker. Proven by negative
control rather than inspection: setting the annotation to astubbs#999 against a
registry Owner of #265 now reports "annotation says fixedBy PR #999 but
the registry Owner line says PR #265 - align them". Before the fix it reported
nothing at all.

A WITHDRAWN INFERENCE

The ledger claimed the rerun failing at a DIFFERENT test was "the strongest
evidence" against a regression, reasoning that a regression fails the same way
twice. That does not hold: under concurrent execution one defect can perturb
timing enough to surface different tests and different failure modes, so two
dissimilar failures show only that the first did not reproduce. Withdrawn, with
the load-bearing evidence restated as the source-level read it always should have
been.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01R8He6kk23K3gN4qtojL9PE
astubbs added a commit that referenced this pull request Aug 11, 2026
…undiagnosed entry diagnosed

Two Codex review findings on #288, both correct.

THE fixedBy CROSS-CHECK WAS STILL SILENTLY DISABLED

The branch cherry-picked the Owner-marker parser fix from #286 but not
the fixedBy one - that fix travelled in the same commit as the un-quarantine
this PR deliberately skipped, and the handoff's claim that "the cross-check now
accepts three forms" described that branch, not this one. So the extraction
still matched only `fixedBy = "PR #NN"`, and PCMetricsTest's qualified
`fixedBy = "#265"` parsed as empty - the annotation-versus-registry
advisory could never fire, exactly the silent-disable #286 documented.

The parser hunk is taken from #286 (8a7e1a0) verbatim, and this time it
gets the regression test that commit lacked: a qualified fixedBy disagreeing
with a qualified Owner line must produce the mismatch advisory. Against the old
parser that test fails (empty declared, no advisory), so the silent-disable
class is now fenced, not just fixed.

THE ADVISORY REPORTED THE OPPOSITE OF THE ENTRY'S KEY STATE

check-quarantine-owners.sh printed "diagnosed-but-unowned, find it an owner"
for every unowned entry - including the backpressure one, whose defining
property is being UNDIAGNOSED. Telling a maintainer to find an owner for a
failure nobody understands points them at the wrong task. The no-owner branch
now distinguishes: an entry recording a rule-1 exception reports "UNDIAGNOSED
(recorded rule-1 exception); completing the diagnosis is the open task", and
quarantined-test.sh's audit banner no longer claims every entry must be
diagnosed. Both wordings are pinned by tests, including that the exception
advisory does NOT contain "diagnosed-but-unowned".

Verified: owner check green with the corrected advisories against the live
registry, and the 40 quarantine contract/script tests pass (two new).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F2MAyo5JDR5ZdWPGCxDCzY
astubbs added a commit that referenced this pull request Aug 11, 2026
…xplicit rule-1 exception (#288)

Both tests were hidden by the surefire retry until #224 removed it, and both then failed
outright on the gating unit lane, blocking every PR in the fork. They are quarantined here on
deliberately different terms, because their evidence is different.

PCMetricsTest.metricsRegisterBinding is diagnosed and owned. It builds its expectation from a
test-side counter snapshot taken earlier in the method, then asserts it against a registry gauge -
two independently-advancing values sampled at different instants with nothing holding processing
still between them. Seen as PARTITION_HIGHEST_COMPLETED_OFFSET expected 203.0 but was 207.0: four
more records completed in the gap, so the metric was MORE current than the expectation testing it.
Owner is #265, verified against that PR's diff rather than its title - its await() replaces a
Thread.sleep upstream of the failing assertion, so it genuinely gates it. On merge, that PR must
delete the annotation and the registry entry in the same commit.

OffsetEncodingBackPressureTest.backPressureShouldPreventTooManyMessagesBeingQueuedForProcessing is
UNDIAGNOSED, and is quarantined as an explicit rule-1 exception by owner decision. It fails as a
ConditionTimeout at the getHighestSeenOffset() assertion, where the committed high-water mark never
reaches expectedHighestSeen (139), with a different actual each run - 136 and 132 both observed.
An earlier attempt attributed it to the retry-delay sleep and was reverted: that code runs AFTER the
failing assertion, so the PR rewriting it cannot be the fix. The lesson is recorded with the entry -
match a fixedBy to a stack line, not to a theme. The entry carries no owner, so the audit reports it
as unowned rather than passing it silently, and the open hypothesis is written down with its
falsification path: the expectation may be unreachable rather than late, because the extra records it
counts on are the ones whose encoding crosses the threshold that stops intake.

Rule 1 said undiagnosed red stays red. Taking the exception was a judgement that at 4/45 - the most
frequent tracked flake - the blocking cost outweighed the pressure the redness was applying. It is
recorded as an exception everywhere it appears, so the diagnosis remains an open task rather than a
closed one.

Two audit-tooling defects surfaced in review and are fixed with regression tests. The fixedBy
cross-check parsed only `fixedBy = "PR #NN"`, so a qualified astubbs#NN reference matched nothing,
the declared value came back empty, and the annotation-versus-registry advisory could never fire - a
check that had silently stopped checking the moment the qualified form was introduced. And the
no-owner advisory reported "diagnosed-but-unowned, find it an owner" for every unowned entry,
including one whose defining property is being undiagnosed; it now distinguishes the two, so CI
points at completing the diagnosis rather than at finding an owner for a failure nobody understands.

The first version of that second fix was itself caught by the repo's own guard: `echo "$block" |
grep -qi ...` reports failure precisely when it MATCHES, because grep -q exits early, the writer takes
EPIPE, and pipefail promotes that to the pipeline's status. It only bites once the writer has more
than 64 KiB left to send, so a small registry passes and production breaks. Rewritten as a herestring;
the tree was swept for other instances of the class and there are none.

The registry rules are also brought into line with what the checks actually enforce. Rule 4 claimed
every entry needs an owning fix PR; the checks have always treated a missing owner as an advisory and
hard-failed only on owner claims that are WRONG - a closed-unmerged owner, or a merged owner with the
test still quarantined. An owning PR is the goal, not a precondition, and unowned entries stay visible
through the per-PR lane report and the release guard.

For a user: no production behaviour changes. The gating unit lane stops failing on these two tests
while they remain visible and executed on every PR, and a release cannot ship while either is still
quarantined.

Co-authored-by: Claude Fable 5 (1M context) <noreply@anthropic.com>
astubbs added a commit that referenced this pull request Aug 11, 2026
… the write-up where it belongs

Two things, neither about the review system this PR otherwise changes.

QUARANTINE ProducerManagerTest.producedRecordsCantBeInTransactionWithoutItsOffsetDirect.
Met while babysitting this PR - which is the point, flakes get quarantined as
they are met rather than waiting for the next sweep. It would not have been
found by a sweep anyway: the 2026-08-07 scan read surefire `Flakes:` markers,
which only exist when a retry re-ran a test and it then passed, and this one
failed its run outright.

Rule 1 is satisfied rather than excepted - the mechanism is known and the fix
is already written. The defect is in the shared
BlockedThreadAsserter#assertUnblocksAfter helper, not in this test: the
unblocker is scheduled BEFORE the elapsed clock starts, so the measured window
begins after the delay it is compared against and is short by however long
arming the scheduler takes. Under load that exceeds a millisecond and
`isAtLeast` fails a correct implementation. Seen as `expected to be at least
PT20S but was PT19.998S` - two milliseconds on a twenty-second bound, which is
the shape of a measurement error, not a behavioural one.

Rule 2 is settled without needing a rate: it failed on a PR whose diff
contained no Java at all, so nothing in the change could have caused it.

Owner #262, which stamps the arming instant and measures from there;
`flapping = true` because it passes most runs. Filed against the helper in the
tracker, since any test using it can show the same signature - and noting that
#265 deletes the same assertion instead, so whichever lands second has a
real decision to make rather than a mechanical merge.

Verified with both arms rather than assumed: under the gating exclusions the
method reports `Tests run: 0`, with `-Dexcluded.groups=` it runs and passes in
21.04s, and the three sibling tests in the class still run in the gating lane -
so the exclusion is method-granular and the lane still watches it. Registry and
owner checks pass.

FILE THE DUPLICATION WRITE-UP UNDER workflow-issues. It was in
documentation-gaps, contradicting its own frontmatter, which already said
`root_cause: inadequate_tooling_scope` and `resolution_type:
workflow_improvement`. Nothing was missing from the docs - the opposite, one
contract written nine times - and the causes are scanner scope and review
granularity. It sits next to
negative-results-need-an-instrument-that-could-have-said-yes.md, which it
already cross-references as the same shape.
astubbs added a commit that referenced this pull request Aug 11, 2026
…n out of it, and ask the gate a simpler question (#287)

#284 split the code review into a cheap always-on gate
and an on-demand reviewer. The gate worked. The reviewer did not: `track_progress`
does not support `workflow_dispatch`, so the action refused before reviewing
anything. With the auto-review already removed, that left no working route and a
required check nothing could turn green.

MAKING IT WORK

The obvious fix - synthesise a `pull_request` payload so the action sees a
supported event - is impossible, and was proved on a runner rather than argued.
It passes locally: the action's own parser yields the right PR in tag mode. But
the runner writes the `GITHUB_*` context over every step's environment AFTER the
step's own `env:` block, and `event_name` is on that allowlist. The payload file
is writable; the event name is not, and the name alone picks the mode. That
commit was dropped.

So the dispatch route runs in agent mode, and the three losses are paid out loud
rather than discovered later: no tracking comment (the summary comment is now
mandatory in the prompt), no inline-comment tool, and no CI MCP server (replaced
with `gh run list -c <sha>` under a scope that is actually documented).

The inline-comment loss turned out to be confined to that route. `claude.yml` was
already in tag mode, and the inline-comment server installs for any ENTITY event -
`issue_comment` is one, `workflow_dispatch` is not - so recovering it there was a
one-item addition to a list this change was already writing. The guidance
therefore inverts rather than degrades: ask by comment when you want findings
that mechanically block (real threads, which required_review_thread_resolution
enforces), dispatch when you want `-f focus` or the packaged procedure.

TAKING THE WRITE TOKEN OUT OF REACH

#284 shipped a privilege escalation. The reviewer job
held `actions: write`, checked out `refs/pull/<n>/head` with credentials persisted
by default, and by design executes this repo's `bin/` scripts from that checkout.
A same-repo PR could edit an allowed script, recover the token from `.git/config`,
and dispatch any workflow - `release.yml` has no actor gate. Now `actions: read`
with `persist-credentials: false`, and `actions: write` isolated in a
checkout-free `refresh-gate` job whose inputs cross as job outputs, so the
head-moved refusal still compares against the SHA the reviewer actually read.

The same gap existed on the comment route, traced live on
#288: a review posted at 08:29 satisfied every rule and
the required check sat red until a hand-run rerun at 08:37. That route now has
the same split.

Granting the curated allowlist there needed two carve-outs, both found in review:
the execution tools are withheld from fork heads and from untrusted commenters.
The first attempt at that guard was written as `${{ fork && '' || format(...) }}`,
which needs a truthy middle operand - so it returned the FULL allowlist while the
step above logged "WITHOUT execution tools". A guard that did not guard and said
it had.

ASKING THE GATE A SIMPLER QUESTION

The gate required a review NEWER than the head. It now accepts any finished
`claude[bot]` review on the PR. What that gives up is real - a review of the first
commit vouches for the twentieth - and it is affordable only because Codex
auto-reviews every push, so per-commit coverage comes from there. If that ever
stops being true, per-commit coverage stops coming from anywhere; that trigger is
recorded, with the strict implementation preserved at the tag
`archive/review-gate-strict-head-freshness`.

Deleted with it: the head/review timestamp comparison, preferring the server-side
timestamp over the contributor-controlled committer date, same-second tie
handling, the reviewed-SHA plumbing, the head-moved guard, and `checks: read`.
The two surviving rules - identity and completion - are mutation-tested, six
mutants all killed, including one that re-adds a freshness comparison, so
restoring strictness silently now breaks the suite.

One correction, because the first version of this change claimed otherwise:
leniency does NOT retire `actions: write`. The gate fires on `pull_request` only,
so the terminal flow - push, ask for review, merge - raises no event after the
review lands. The refresh jobs stay. That scope is the cost of the check being
produced by a `pull_request` workflow, not of strictness, and retiring it needs
the reviewer to raise a check run on the reviewed SHA. Tracked.

Leniency also opened a hole and closed it: the gate now asks only whether a
finished review exists, and the comment route answers `@claude` on fork PRs - so a
maintainer asking a QUESTION would have greened a fork PR. Fork heads are refused
before any comment is read.

ALSO

- The action exits 0 on a workflow-validation refusal, so the job reported
  success. It now fails when the action's own `conclusion` output is empty.
- The contract was stated in nine files, fourteen times, in nine different
  sentences. Collapsed to one canonical paragraph, with the rest reduced to
  pointers. Why no tool caught it is written up: `dups: clones` and
  `dups: similarity` scan `parallel-consumer-*/src` only, so docs, workflows and
  `bin/` are scanned by neither - and even aimed at them, token-based clone
  detection cannot see paraphrase. The scanners catch copy-paste; what bit here
  was restatement.
- `.github/workflows/README.md`, one line per workflow, leading with the fact
  that `claude-code-review.yml` is the one that does not review.
- A flapping `ProducerManagerTest.producedRecordsCantBeInTransactionWithoutItsOffsetDirect`
  quarantined, pointing at its fix in #262. Note that
  #265 takes an incompatible approach to the same line -
  it deletes the assertion rather than anchoring the measurement - so whichever
  lands second will conflict there.
- A cooperative-variant chaos sighting captured against the
  confluentinc#857 family (fork mirror
  #119) before its seed expired, recorded as consistent
  with that family rather than confirmed as it: the eager variant was already
  logged with a clean ProgressProbe kill, while this one shows only the
  shutdown-path timeout.

Verified end to end on this PR: the review was requested by comment, posted as
`claude[bot]`, and the gate went green - then stayed green across two further
pushes with no new review. Under the old rule each push would have reddened it.
This is the first PR in this series to merge without an admin bypass.

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
astubbs added a commit that referenced this pull request Aug 18, 2026
…hdrawn

Three additions to the family ledger, all found while working #209.

A fifth sighting, and the one that moves triage furthest: the same
ZOMBIE_MEMBER signature with #292 present and no double-start anywhere
in the log. The harness was ruled out by counting rather than by assertion - 0
concurrent double-runs across 41 run() invocations over 16 instances, 0 guard
engagements, so the race window was never even entered, and 0 teardown
indicators. That retires the fourth sighting from the family as answered, and
rewrites the family's triage rule: a ZOMBIE_MEMBER violation is no longer
evidence of the double-start, so grep the log for two "Running consumer
instance N" lines on different pool workers within ~2s - present, the guards
regressed; absent, it is the other cause and belongs in this file.

A sixth sighting with a full autopsy, and the retrieval trap that nearly hid
it: the console log for that job was truncated mid-run, so grepping it returned
zero for every probe signature - which reads exactly like a clean run. The
violations, the autopsy and the seed all came from the uploaded artifact. A
zero from the console is not a zero.

A seventh sighting, and the first bisected against a clean baseline rather than
argued about. PCMetricsTest.metricsRegisterBinding lost two records on a full
multi-module run - the family's signature, on a branch whose subject is work
being taken and not accounted for, so it was either the best evidence yet or
noise. A detached worktree at the pre-change commit settled it: the failure
reproduces without the branch, so it is not attributable to #209.

The dismissal that came with it is withdrawn. The entry originally said "load,
not the test" and moved on. That is the move AGENTS.md names explicitly - a
test failing under concurrent load may be exposing a real bug that only
manifests under stress - and it was self-serving, because the load was partly
self-inflicted by concurrent Maven runs. "Only fails under load" is what a
flaky test is, and CI runs the suite under load too. Since #265
un-quarantined that test the day before, this is a post-un-quarantine failure
and therefore evidence the un-quarantine was premature. The entry now says so,
and names what would settle it: a repeated full-suite run on a CI runner rather
than a developer box.

The method is the reusable part. Neither "it passed on retry" nor "it failed
once" is evidence alone; a worktree at the pre-change commit running the same
command is cheap, and it is what turns "probably a flake" into an answer.

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

Three additions to the family ledger, all found while working #209.

A fifth sighting, and the one that moves triage furthest: the same
ZOMBIE_MEMBER signature with #292 present and no double-start anywhere
in the log. The harness was ruled out by counting rather than by assertion - 0
concurrent double-runs across 41 run() invocations over 16 instances, 0 guard
engagements, so the race window was never even entered, and 0 teardown
indicators. That retires the fourth sighting from the family as answered, and
rewrites the family's triage rule: a ZOMBIE_MEMBER violation is no longer
evidence of the double-start, so grep the log for two "Running consumer
instance N" lines on different pool workers within ~2s - present, the guards
regressed; absent, it is the other cause and belongs in this file.

A sixth sighting with a full autopsy, and the retrieval trap that nearly hid
it: the console log for that job was truncated mid-run, so grepping it returned
zero for every probe signature - which reads exactly like a clean run. The
violations, the autopsy and the seed all came from the uploaded artifact. A
zero from the console is not a zero.

A seventh sighting, and the first bisected against a clean baseline rather than
argued about. PCMetricsTest.metricsRegisterBinding lost two records on a full
multi-module run - the family's signature, on a branch whose subject is work
being taken and not accounted for, so it was either the best evidence yet or
noise. A detached worktree at the pre-change commit settled it: the failure
reproduces without the branch, so it is not attributable to #209.

The dismissal that came with it is withdrawn. The entry originally said "load,
not the test" and moved on. That is the move AGENTS.md names explicitly - a
test failing under concurrent load may be exposing a real bug that only
manifests under stress - and it was self-serving, because the load was partly
self-inflicted by concurrent Maven runs. "Only fails under load" is what a
flaky test is, and CI runs the suite under load too. Since #265
un-quarantined that test the day before, this is a post-un-quarantine failure
and therefore evidence the un-quarantine was premature. The entry now says so,
and names what would settle it: a repeated full-suite run on a CI runner rather
than a developer box.

The method is the reusable part. Neither "it passed on retry" nor "it failed
once" is evidence alone; a worktree at the pre-change commit running the same
command is cheap, and it is what turns "probably a flake" into an answer.

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

Three additions to the family ledger, all found while working #209.

A fifth sighting, and the one that moves triage furthest: the same
ZOMBIE_MEMBER signature with #292 present and no double-start anywhere
in the log. The harness was ruled out by counting rather than by assertion - 0
concurrent double-runs across 41 run() invocations over 16 instances, 0 guard
engagements, so the race window was never even entered, and 0 teardown
indicators. That retires the fourth sighting from the family as answered, and
rewrites the family's triage rule: a ZOMBIE_MEMBER violation is no longer
evidence of the double-start, so grep the log for two "Running consumer
instance N" lines on different pool workers within ~2s - present, the guards
regressed; absent, it is the other cause and belongs in this file.

A sixth sighting with a full autopsy, and the retrieval trap that nearly hid
it: the console log for that job was truncated mid-run, so grepping it returned
zero for every probe signature - which reads exactly like a clean run. The
violations, the autopsy and the seed all came from the uploaded artifact. A
zero from the console is not a zero.

A seventh sighting, and the first bisected against a clean baseline rather than
argued about. PCMetricsTest.metricsRegisterBinding lost two records on a full
multi-module run - the family's signature, on a branch whose subject is work
being taken and not accounted for, so it was either the best evidence yet or
noise. A detached worktree at the pre-change commit settled it: the failure
reproduces without the branch, so it is not attributable to #209.

The dismissal that came with it is withdrawn. The entry originally said "load,
not the test" and moved on. That is the move AGENTS.md names explicitly - a
test failing under concurrent load may be exposing a real bug that only
manifests under stress - and it was self-serving, because the load was partly
self-inflicted by concurrent Maven runs. "Only fails under load" is what a
flaky test is, and CI runs the suite under load too. Since #265
un-quarantined that test the day before, this is a post-un-quarantine failure
and therefore evidence the un-quarantine was premature. The entry now says so,
and names what would settle it: a repeated full-suite run on a CI runner rather
than a developer box.

The method is the reusable part. Neither "it passed on retry" nor "it failed
once" is evidence alone; a worktree at the pre-change commit running the same
command is cheap, and it is what turns "probably a flake" into an answer.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013ahSzHD72EvTGTYkmpTsx6
astubbs added a commit that referenced this pull request Aug 19, 2026
#320 added a gate for cited paths that do not exist,
and deferred the 87 already in the tree. Deferring them is a chicken-and-egg:
the gate cannot run whole-tree - the mode that also catches a file being
deleted out from under its citations - until the count is zero. This clears
the ones that are documentation defects, and identifies the rest as gate
defects rather than documentation ones.

WHAT WAS ACTUALLY WRONG, ONCE READ ONE AT A TIME

  * 26 addresses stale from the io.confluent -> bz.stub rename. Every target
    still exists at the renamed path; repairing the address is what
    docs/citations.md requires ("a citation that no longer resolves makes the
    record LESS faithful"). Slash-form PATHS only - dot-form package prose in
    dated documents is untouched.
  * 2 genuine breakages: docs/ci.md's citation of the never-written
    bin/check-review-gate-contract.sh (the same edit as
    #319, so the two merge cleanly), and
    `example-metrics/CoreApp.java`, a shorthand that names no real path -
    now `examples/metrics/CoreApp.java`, which resolves as a real path tail.
  * ~20 paths named DELIBERATELY: a proposal for a script yet to be written, a
    generated file a plan decided against, artefacts a plan records as deleted,
    documents living on another branch. Each keeps its wording and gains
    `<!-- file-refs: N/A - <reason> -->`, which the gate reads as covering the
    paragraph above it.
  * 1 deleted file given the history pointer docs/citations.md prescribes:
    junit-platform.properties, removed by #265, now
    read via `git show 15f1ebe^:...` - verified to resolve.

AN INHERITED RULE THIS DELIBERATELY NARROWS

docs/plans/2026-08-11-001-refactor-package-rename-plan.md says dated documents
"must not be rewritten to say something they did not say... expect the answer
to be 'leave it' for everything under docs/plans/". That governs CLAIMS, and it
is obeyed: no finding, conclusion or measurement changed. It does not govern
ADDRESSES, which docs/citations.md - the owner of citation repair - requires be
kept working. The line drawn is slash-form path citations get repaired;
dot-form package names in prose do not.

The first sweep proved why that line matters. A blanket substitution turned
"Move `src/main/java/io/confluent/...` to `.../bz/stub/...`" into "Move bz/stub
to bz/stub", and rewrote a `git show <sha>^:<path>` pointer to a path that did
not exist at that commit - breaking the one thing it was for. Both were caught
by reading the diff rather than the count, and both are now preserved with a
stated reason.

WHAT REMAINS IS THE GATE'S FAULT, NOT THE DOCS'

31 of the original 87 still report, and every one is a false positive:

  * 30 are `docs/inflight.md`, cited across 8 documents that ALREADY carry
    `git show 0de96fc^:docs/inflight.md`. That is precisely the repair
    docs/citations.md prescribes, correctly applied - and the gate reports it
    as 30 defects, penalising the documented fix.
  * 1 is a `<sha>^:<path>` history pointer, correct because the path no longer
    exists.

Both are gate rules, queued for #320: a path preceded
by a git revision is a history pointer, and a path is repaired when its own
document carries a pointer naming it. They remove 31 findings without editing
a single document - which is the right split of the work.

Verified: check-issue-refs, check-docs-data, check-copyright-headers,
todo-index --check and the gate's 34 assertions all pass; the two history
pointers confirmed to resolve with `git show`.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
astubbs added a commit that referenced this pull request Aug 19, 2026
Eighty-seven paths in the tree resolved to nothing. Read one at a time they were
four different problems, and only two of them were defects:

  * 26 addresses stale from the io.confluent -> bz.stub rename. Every target
    still exists at the renamed path, so repairing the address is what
    docs/citations.md requires - "a citation that no longer resolves makes the
    record LESS faithful". Slash-form PATHS only; dot-form package prose in
    dated documents is untouched.
  * 2 genuinely broken: docs/ci.md's citation of the never-written
    bin/check-review-gate-contract.sh, and `example-metrics/CoreApp.java`, a
    shorthand naming no real path - now `examples/metrics/CoreApp.java`, which
    resolves as a real path tail.
  * ~20 named DELIBERATELY - a proposed script, a generated file a plan decided
    against, artefacts recorded as deleted, documents living on another branch.
    Each keeps its wording and gains a marker with a stated reason.
  * 1 deleted file given the history pointer docs/citations.md prescribes:
    junit-platform.properties, removed by #265, read
    via `git show 15f1ebe^:...` - verified to resolve.

AN INHERITED RULE THIS DELIBERATELY NARROWS.

docs/plans/2026-08-11-001-refactor-package-rename-plan.md says dated documents
"must not be rewritten to say something they did not say... expect the answer to
be 'leave it' for everything under docs/plans/". That governs CLAIMS, and it is
obeyed: no finding, conclusion or measurement changed. It does not govern
ADDRESSES, which docs/citations.md - the owner of citation repair - requires be
kept working. The line drawn is slash-form path citations get repaired,
dot-form package names in prose do not.

The first sweep proved why that line matters, and why this was done by reading
each diff rather than by counting. A blanket substitution turned "Move
`src/main/java/io/confluent/...` to `.../bz/stub/...`" into "Move bz/stub to
bz/stub", and rewrote a `git show <sha>^:<path>` pointer to a path that did not
exist at that commit - breaking the one thing it was for. Both are preserved
with a stated reason.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
astubbs added a commit that referenced this pull request Aug 19, 2026
Eighty-seven paths in the tree resolved to nothing. Read one at a time they were
four different problems, and only two of them were defects:

  * 26 addresses stale from the io.confluent -> bz.stub rename. Every target
    still exists at the renamed path, so repairing the address is what
    docs/citations.md requires - "a citation that no longer resolves makes the
    record LESS faithful". Slash-form PATHS only; dot-form package prose in
    dated documents is untouched.
  * 2 genuinely broken: docs/ci.md's citation of the never-written
    bin/check-review-gate-contract.sh, and `example-metrics/CoreApp.java`, a
    shorthand naming no real path - now `examples/metrics/CoreApp.java`, which
    resolves as a real path tail.
  * ~20 named DELIBERATELY - a proposed script, a generated file a plan decided
    against, artefacts recorded as deleted, documents living on another branch.
    Each keeps its wording and gains a marker with a stated reason.
  * 1 deleted file given the history pointer docs/citations.md prescribes:
    junit-platform.properties, removed by #265, read
    via `git show 15f1ebe^:...` - verified to resolve.

AN INHERITED RULE THIS DELIBERATELY NARROWS.

docs/plans/2026-08-11-001-refactor-package-rename-plan.md says dated documents
"must not be rewritten to say something they did not say... expect the answer to
be 'leave it' for everything under docs/plans/". That governs CLAIMS, and it is
obeyed: no finding, conclusion or measurement changed. It does not govern
ADDRESSES, which docs/citations.md - the owner of citation repair - requires be
kept working. The line drawn is slash-form path citations get repaired,
dot-form package names in prose do not.

The first sweep proved why that line matters, and why this was done by reading
each diff rather than by counting. A blanket substitution turned "Move
`src/main/java/io/confluent/...` to `.../bz/stub/...`" into "Move bz/stub to
bz/stub", and rewrote a `git show <sha>^:<path>` pointer to a path that did not
exist at that commit - breaking the one thing it was for. Both are preserved
with a stated reason.

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

Rule 1 was "no quarantine without diagnosis". It conflated two different unknowns - "we don't know
the mechanism" and "we don't know whether it's ours" - and only the second justifies blocking. A
test with a recorded sighting ledger IS a finding: it is known master-state flaky. It just has no
root cause yet.

The cost of the old wording was that an undiagnosed red stayed in the gating lane and blocked every
unrelated PR, which trains everyone to read red as normal. This repo already deleted surefire
retries for hiding flakes; a permanently-red gate destroys the same signal more thoroughly. The tell
that the default was miscalibrated: its escape hatch was an owner-granted exception, and the
exception had become the routine path - test-untracked-ci-flakes.md records the owner having to
grant one for a test failing 4 in 45 runs, which is a ledger by any reading.

Rule 1 now asks for EVIDENCE: a diagnosed mechanism, or a recorded sighting ledger (dates, runs,
signature, and what makes it master-state rather than PR-state). What stays banned is a hunch - "it's
red sometimes" is not evidence, and a single failure is a sighting, not a ledger. Nothing else moves:
the lane still runs the test, the registry still keeps it loud, rule 5 still blocks a release while
the list is non-empty. Quarantine defers; it does not forgive. It is explicitly not a licence to
label something "just a flaky test" - that is the label the drain-zombie carried right up until it
turned out to be a real product bug.

Updated in all six places that stated it, so they cannot drift: docs/quarantined-tests.md (owner, and
the fullest statement), docs/testing.md, AGENTS.md's table cell, the @Quarantined javadoc,
bin/check-quarantine-registry.sh's drift message, and QuarantinedAnnotationContractTest's assertion
message. The #265 entry in test-untracked-ci-flakes.md, which reasoned FROM the old rule, is
rewritten rather than find-replaced: it now qualifies on the rule itself instead of needing the
exception.

Also records the failure that prompted this, which turned out not to need quarantining at all:
docs/inflight/bug-pcmetrics-committed-offset-vs-completion-count.md.
PCMetricsTest.metricsRegisterBinding asserts PARTITION_LAST_COMMITTED_OFFSET equals a COMPLETION
counter, while the suite runs UNORDERED. Commits are contiguous and bounded by the lowest incomplete
offset; completions are not ordered. The observed 1214 vs 1207 is 214 completions against 207
contiguous - 7 records finished past a gap - and the gap is PERMANENT, because workers call
latch.await() before counter.incrementAndGet(), so a latched worker's offset never completes. No
timeout can close it. That is a wrong expectation, not a flake, and the note says so along with the
fix (compare against PARTITION_HIGHEST_SEQUENTIAL_SUCCEEDED_OFFSET) and a warning not to widen the
timeout instead.

It is also NOT a confluentinc#857 sighting, and the note says why: every sighting in that family is a
chaos/rebalance integration test with a commit mode and a seed, whereas this is a MockConsumer unit
test with no broker, rebalance, revoke path or mode. bug-857-family.md already records one
contamination of exactly this kind, so the ruling-out is written down rather than left implicit.

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

Rule 1 was "no quarantine without diagnosis". It conflated two different unknowns - "we don't know
the mechanism" and "we don't know whether it's ours" - and only the second justifies blocking. A
test with a recorded sighting ledger IS a finding: it is known master-state flaky. It just has no
root cause yet.

The cost of the old wording was that an undiagnosed red stayed in the gating lane and blocked every
unrelated PR, which trains everyone to read red as normal. This repo already deleted surefire
retries for hiding flakes; a permanently-red gate destroys the same signal more thoroughly. The tell
that the default was miscalibrated: its escape hatch was an owner-granted exception, and the
exception had become the routine path - test-untracked-ci-flakes.md records the owner having to
grant one for a test failing 4 in 45 runs, which is a ledger by any reading.

Rule 1 now asks for EVIDENCE: a diagnosed mechanism, or a recorded sighting ledger (dates, runs,
signature, and what makes it master-state rather than PR-state). What stays banned is a hunch - "it's
red sometimes" is not evidence, and a single failure is a sighting, not a ledger. Nothing else moves:
the lane still runs the test, the registry still keeps it loud, rule 5 still blocks a release while
the list is non-empty. Quarantine defers; it does not forgive. It is explicitly not a licence to
label something "just a flaky test" - that is the label the drain-zombie carried right up until it
turned out to be a real product bug.

Updated in all six places that stated it, so they cannot drift: docs/quarantined-tests.md (owner, and
the fullest statement), docs/testing.md, AGENTS.md's table cell, the @Quarantined javadoc,
bin/check-quarantine-registry.sh's drift message, and QuarantinedAnnotationContractTest's assertion
message. The #265 entry in test-untracked-ci-flakes.md, which reasoned FROM the old rule, is
rewritten rather than find-replaced: it now qualifies on the rule itself instead of needing the
exception.

Also records the failure that prompted this, which turned out not to need quarantining at all:
docs/inflight/bug-pcmetrics-committed-offset-vs-completion-count.md.
PCMetricsTest.metricsRegisterBinding asserts PARTITION_LAST_COMMITTED_OFFSET equals a COMPLETION
counter, while the suite runs UNORDERED. Commits are contiguous and bounded by the lowest incomplete
offset; completions are not ordered. The observed 1214 vs 1207 is 214 completions against 207
contiguous - 7 records finished past a gap - and the gap is PERMANENT, because workers call
latch.await() before counter.incrementAndGet(), so a latched worker's offset never completes. No
timeout can close it. That is a wrong expectation, not a flake, and the note says so along with the
fix (compare against PARTITION_HIGHEST_SEQUENTIAL_SUCCEEDED_OFFSET) and a warning not to widen the
timeout instead.

It is also NOT a confluentinc#857 sighting, and the note says why: every sighting in that family is a
chaos/rebalance integration test with a commit mode and a seed, whereas this is a MockConsumer unit
test with no broker, rebalance, revoke path or mode. bug-857-family.md already records one
contamination of exactly this kind, so the ruling-out is written down rather than left implicit.

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

Rule 1 was "no quarantine without diagnosis". It conflated two different unknowns - "we don't know
the mechanism" and "we don't know whether it's ours" - and only the second justifies blocking. A
test with a recorded sighting ledger IS a finding: it is known master-state flaky. It just has no
root cause yet.

The cost of the old wording was that an undiagnosed red stayed in the gating lane and blocked every
unrelated PR, which trains everyone to read red as normal. This repo already deleted surefire
retries for hiding flakes; a permanently-red gate destroys the same signal more thoroughly. The tell
that the default was miscalibrated: its escape hatch was an owner-granted exception, and the
exception had become the routine path - test-untracked-ci-flakes.md records the owner having to
grant one for a test failing 4 in 45 runs, which is a ledger by any reading.

Rule 1 now asks for EVIDENCE: a diagnosed mechanism, or a recorded sighting ledger (dates, runs,
signature, and what makes it master-state rather than PR-state). What stays banned is a hunch - "it's
red sometimes" is not evidence, and a single failure is a sighting, not a ledger. Nothing else moves:
the lane still runs the test, the registry still keeps it loud, rule 5 still blocks a release while
the list is non-empty. Quarantine defers; it does not forgive. It is explicitly not a licence to
label something "just a flaky test" - that is the label the drain-zombie carried right up until it
turned out to be a real product bug.

Updated in all six places that stated it, so they cannot drift: docs/quarantined-tests.md (owner, and
the fullest statement), docs/testing.md, AGENTS.md's table cell, the @Quarantined javadoc,
bin/check-quarantine-registry.sh's drift message, and QuarantinedAnnotationContractTest's assertion
message. The #265 entry in test-untracked-ci-flakes.md, which reasoned FROM the old rule, is
rewritten rather than find-replaced: it now qualifies on the rule itself instead of needing the
exception.

Also records the failure that prompted this, which turned out not to need quarantining at all:
docs/inflight/bug-pcmetrics-committed-offset-vs-completion-count.md.
PCMetricsTest.metricsRegisterBinding asserts PARTITION_LAST_COMMITTED_OFFSET equals a COMPLETION
counter, while the suite runs UNORDERED. Commits are contiguous and bounded by the lowest incomplete
offset; completions are not ordered. The observed 1214 vs 1207 is 214 completions against 207
contiguous - 7 records finished past a gap - and the gap is PERMANENT, because workers call
latch.await() before counter.incrementAndGet(), so a latched worker's offset never completes. No
timeout can close it. That is a wrong expectation, not a flake, and the note says so along with the
fix (compare against PARTITION_HIGHEST_SEQUENTIAL_SUCCEEDED_OFFSET) and a warning not to widen the
timeout instead.

It is also NOT a confluentinc#857 sighting, and the note says why: every sighting in that family is a
chaos/rebalance integration test with a commit mode and a seed, whereas this is a MockConsumer unit
test with no broker, rebalance, revoke path or mode. bug-857-family.md already records one
contamination of exactly this kind, so the ruling-out is written down rather than left implicit.

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

Rule 1 was "no quarantine without diagnosis". It conflated two different unknowns - "we don't know
the mechanism" and "we don't know whether it's ours" - and only the second justifies blocking. A
test with a recorded sighting ledger IS a finding: it is known master-state flaky. It just has no
root cause yet.

The cost of the old wording was that an undiagnosed red stayed in the gating lane and blocked every
unrelated PR, which trains everyone to read red as normal. This repo already deleted surefire
retries for hiding flakes; a permanently-red gate destroys the same signal more thoroughly. The tell
that the default was miscalibrated: its escape hatch was an owner-granted exception, and the
exception had become the routine path - test-untracked-ci-flakes.md records the owner having to
grant one for a test failing 4 in 45 runs, which is a ledger by any reading.

Rule 1 now asks for EVIDENCE: a diagnosed mechanism, or a recorded sighting ledger (dates, runs,
signature, and what makes it master-state rather than PR-state). What stays banned is a hunch - "it's
red sometimes" is not evidence, and a single failure is a sighting, not a ledger. Nothing else moves:
the lane still runs the test, the registry still keeps it loud, rule 5 still blocks a release while
the list is non-empty. Quarantine defers; it does not forgive. It is explicitly not a licence to
label something "just a flaky test" - that is the label the drain-zombie carried right up until it
turned out to be a real product bug.

Updated in all six places that stated it, so they cannot drift: docs/quarantined-tests.md (owner, and
the fullest statement), docs/testing.md, AGENTS.md's table cell, the @Quarantined javadoc,
bin/check-quarantine-registry.sh's drift message, and QuarantinedAnnotationContractTest's assertion
message. The #265 entry in test-untracked-ci-flakes.md, which reasoned FROM the old rule, is
rewritten rather than find-replaced: it now qualifies on the rule itself instead of needing the
exception.

Also records the failure that prompted this, which turned out not to need quarantining at all:
docs/inflight/bug-pcmetrics-committed-offset-vs-completion-count.md.
PCMetricsTest.metricsRegisterBinding asserts PARTITION_LAST_COMMITTED_OFFSET equals a COMPLETION
counter, while the suite runs UNORDERED. Commits are contiguous and bounded by the lowest incomplete
offset; completions are not ordered. The observed 1214 vs 1207 is 214 completions against 207
contiguous - 7 records finished past a gap - and the gap is PERMANENT, because workers call
latch.await() before counter.incrementAndGet(), so a latched worker's offset never completes. No
timeout can close it. That is a wrong expectation, not a flake, and the note says so along with the
fix (compare against PARTITION_HIGHEST_SEQUENTIAL_SUCCEEDED_OFFSET) and a warning not to widen the
timeout instead.

It is also NOT a confluentinc#857 sighting, and the note says why: every sighting in that family is a
chaos/rebalance integration test with a commit mode and a seed, whereas this is a MockConsumer unit
test with no broker, rebalance, revoke path or mode. bug-857-family.md already records one
contamination of exactly this kind, so the ruling-out is written down rather than left implicit.

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

Rule 1 was "no quarantine without diagnosis". It conflated two different unknowns - "we don't know
the mechanism" and "we don't know whether it's ours" - and only the second justifies blocking. A
test with a recorded sighting ledger IS a finding: it is known master-state flaky. It just has no
root cause yet.

The cost of the old wording was that an undiagnosed red stayed in the gating lane and blocked every
unrelated PR, which trains everyone to read red as normal. This repo already deleted surefire
retries for hiding flakes; a permanently-red gate destroys the same signal more thoroughly. The tell
that the default was miscalibrated: its escape hatch was an owner-granted exception, and the
exception had become the routine path - test-untracked-ci-flakes.md records the owner having to
grant one for a test failing 4 in 45 runs, which is a ledger by any reading.

Rule 1 now asks for EVIDENCE: a diagnosed mechanism, or a recorded sighting ledger (dates, runs,
signature, and what makes it master-state rather than PR-state). What stays banned is a hunch - "it's
red sometimes" is not evidence, and a single failure is a sighting, not a ledger. Nothing else moves:
the lane still runs the test, the registry still keeps it loud, rule 5 still blocks a release while
the list is non-empty. Quarantine defers; it does not forgive. It is explicitly not a licence to
label something "just a flaky test" - that is the label the drain-zombie carried right up until it
turned out to be a real product bug.

Updated in all six places that stated it, so they cannot drift: docs/quarantined-tests.md (owner, and
the fullest statement), docs/testing.md, AGENTS.md's table cell, the @Quarantined javadoc,
bin/check-quarantine-registry.sh's drift message, and QuarantinedAnnotationContractTest's assertion
message. The #265 entry in test-untracked-ci-flakes.md, which reasoned FROM the old rule, is
rewritten rather than find-replaced: it now qualifies on the rule itself instead of needing the
exception.

Also records the failure that prompted this, which turned out not to need quarantining at all:
docs/inflight/bug-pcmetrics-committed-offset-vs-completion-count.md.
PCMetricsTest.metricsRegisterBinding asserts PARTITION_LAST_COMMITTED_OFFSET equals a COMPLETION
counter, while the suite runs UNORDERED. Commits are contiguous and bounded by the lowest incomplete
offset; completions are not ordered. The observed 1214 vs 1207 is 214 completions against 207
contiguous - 7 records finished past a gap - and the gap is PERMANENT, because workers call
latch.await() before counter.incrementAndGet(), so a latched worker's offset never completes. No
timeout can close it. That is a wrong expectation, not a flake, and the note says so along with the
fix (compare against PARTITION_HIGHEST_SEQUENTIAL_SUCCEEDED_OFFSET) and a warning not to widen the
timeout instead.

It is also NOT a confluentinc#857 sighting, and the note says why: every sighting in that family is a
chaos/rebalance integration test with a commit mode and a seed, whereas this is a MockConsumer unit
test with no broker, rebalance, revoke path or mode. bug-857-family.md already records one
contamination of exactly this kind, so the ruling-out is written down rather than left implicit.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019infZnCpPvX8c6QWFC1uLC
astubbs added a commit that referenced this pull request Aug 20, 2026
#265 settled the question this branch had left open in the flake ledger - measure the
block correctly, or stop measuring it. It took the second answer, deleting BlockedThreadAsserter's
wall-clock assertion for a causal one plus BlockedThreadAsserterTest, and it reached master first.
So this takes master's helper wholesale and drops #262's armedAtNanos anchoring (517afd0).
That is the better outcome rather than a concession: anchoring shrank the error and kept the helper
sleeping out its own timeout, while removing the assertion ends the whole class of scheduler-jitter
failure. test-untracked-ci-flakes.md now credits #265 for the fix; #262 still carries
the re-enable, being the entry's owner.

docs/quarantined-tests.md is the union of two rule-3 lifts. Each side read as deleting the other's
entry - this branch had removed ProducerManagerTest.producedRecordsCantBeInTransactionWithoutItsOffsetDirect,
#265 had removed PCMetricsTest.metricsRegisterBinding - and both removals are correct, so
neither survives. PCMetricsTest.java takes master's version; this branch never authored its content,
which arrived via the rename commits into a region #265 rewrote.

The C10 test needed a real repair, not just a merge. #265 moved assertUnblocksAfter's blocked
function from the calling thread onto its own, and ReentrantReadWriteLock read holds are per-thread -
so producingIsBlockedForTheDurationOfTheCommitAndResumesOnRelease was releasing a lock the test
thread never held, and ensureProduceStarted threw "Need to call #beginProducing first". It now
acquires and releases inside the blocked function, which strengthens it: reaching released == true
proves finishProducing passed its own ensureProduceStarted check, so the lock was genuinely held by
the thread that took it - something the cross-thread version never established. Its third argument
also changed meaning underneath it, from "must block at least this long" to "return budget" at the
same arity, so ofSeconds(1) would have become a 1s budget against a 20s default sized for PIT's
instrumented JVM. Switched to the 2-arg overload.

Pushed with three failures unexplained, which is why the handoff note lands with it:
ParallelEoSStreamProcessorTest's executorThreadsInterruptedOnShutdownTimeout,
inFlightMessagesCommittedIfProcessedDuringShutdown and processInKeyOrder, all on CommitMode[3], all
around 10s. Neither of this branch's main-code changes fired - the produce-lock guard and the
cleanUpContext report are both absent from the run log - and each test passes in isolation while a
different set fails per run, which reads as contention. Not established: the decisive check of
whether [3] fails the same way on plain master was not run.

docs/inflight/handoff-262-master-merge.md carries that, the produce-callback decision reached but
not acted on, and the #265 PCMetricsTest exposure.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
astubbs added a commit that referenced this pull request Aug 24, 2026
PCMetricsTest carried one @Quarantined annotation and two registry entries, which
bin/check-quarantine-registry.sh fails on and which blocked this repo's own
pre-commit hook, not only CI.

This was NOT master-state, and an earlier note in this branch wrongly said it was.
origin/master has one entry against the same single annotation. The second arrived
with this stack via f4a16a6, the cherry-pick of the re-quarantine from
#116 (originally eb602ae) - a branch that did not carry master's entry, so
it appended rather than folded, and nothing on either side could see the collision
until the two met here.

They were describing the same failure from two directions. Master's entry is the
diagnosed mechanism: PARTITION_LAST_COMMITTED_OFFSET is asserted against a
completion counter under UNORDERED, workers call latch.await() before
counter.incrementAndGet(), so a latched worker's offset never completes and the gap
is permanent. The cherry-pick's entry is what that looks like from outside - the
metric behind and never converging, with a shortfall that varies run to run, which
is why no wait closes it.

Folded with nothing dropped, and the merge is asserted rather than assumed: every
sighting, both failure transcripts, the #265 release history and why that fix
addressed the opposite direction, the proposed comparand and why it is not a
one-line change, the OffsetEncodingBackPressureTest cross-reference still worth
ruling in or out as one phenomenon, and all four document links are present in the
merged text. The entry keeps master's position and framing so the diff against
master stays small.

A note in the merged entry records that it was two entries until today and why, so
a reader who remembers seeing two does not conclude one was silently lost.

Also corrects the #334 handoff, which filed this red under "standing debt,
pre-existing" - it was neither.

bin/check-quarantine-registry.sh now exits 0.
astubbs added a commit that referenced this pull request Aug 25, 2026
…sumed - and the ledger row that contradicted itself

Review pass over the two commits below. One real defect fixed, one proposed fix REFUTED by
measurement rather than applied, and the gap it was aimed at recorded where it can actually be closed.

Removes the `PCMetricsTest.metricsRegisterBinding` row this branch added to
docs/inflight/test-untracked-ci-flakes.md. Three independent reviewers flagged it and it is wrong
three ways: it claims `owner #265` while docs/quarantined-tests.md's entry for the same test
reads "No Owner yet"; the header rewritten in the same commit says #265 is "fixed and out of
this ledger", naming a different, closed item; and its "- see below" promises a section the file does
not contain. The test is already tracked by that registry entry and by
docs/inflight/bug-pcmetrics-committed-offset-vs-completion-count.md, so the row also duplicated a fact
this directory's rules say must live in exactly one place. It was absent at the diff base - nothing
outside this branch depended on it.

The loose lower bound on the settled frontier STAYS, and this is the substantive result. Two
reviewers proposed tightening `isGreaterThan(numberOfRecordsToPrimeWith - 1)` so that back pressure
engaging early would go red - one wanted a numeric floor at the measured block point (136), the other
wanted the committed payload asserted over the pressure threshold. Both were implemented and
mutation-tested against the guard they exist to protect, and BOTH SURVIVE. Mutating
`updateBlockFromEncodingResult` from `metaPayloadLength > getPressureThresholdValue()` to `... - 2`
leaves the test green, logging the identical `Payload size 32 higher than threshold 30.0` as the
control - because the mock consumer hands the whole extra batch over in one poll, so
`offsetHighestSucceeded` reaches 139 before the first encode that follows the batch. The settled
frontier is decided by the claim boundary, not by where the threshold sits, so no assertion on it can
see the threshold move. The stronger `... - 10` mutant IS killed, but by the pre-existing
`isAllowedMoreRecords()` assertion above the section, not by anything a tightened bound would add.

Adding an assertion that provably kills no mutant another assertion does not already kill is the
thing docs/testing.md's method exists to prevent, so neither proposal is in this commit. What is left
is the bound restated as the band it actually describes - `isBetween(numberOfRecordsToPrimeWith,
lastOffsetSent)` - which drops an awkward cast and says "into the extra batch and no further", at
identical strength.

The gap is real even though this test cannot close it, so it is recorded rather than lost:
docs/inflight/test-back-pressure-engage-point-is-unasserted.md carries the mutation result, why
neither this test nor OffsetEncodingBackPressureUnitTest can host the coverage, and the fact that the
deterministic single-threaded probe built for the diagnosis - the one instrument that controls the
claim boundary - is what would make a premature-engage regression red. The related blind spot rides
with it: nothing pins that getOffsetHighestSucceeded() and getOffsetHighestSeen() diverge while
blocked, so a regression collapsing the two accessors is invisible to the round-trip assertion.

Also corrects a claim in the preceding commit's own body: it says "this tree encodes 32 chars, not
the 31 the probe recorded", which reads as a contradiction and is not one. 31 chars is the payload at
frontier 136, where the probe steps one offset at a time; 32 is the payload at frontier 139, which is
what a real run reaches. Both are true and they measure different states.

Ruled out and not changed: the bare `await()` on quiescence uses Awaitility's 10s default while its
sibling uses the 30s defaultTimeout. Left alone - bare await() is this file's existing convention, the
records being drained only sleepQuietly(1), and a miss is a ConditionTimeout red rather than a silent
green. Two reviewers reached that independently.

Verified: OffsetEncodingBackPressureTest green 5/5; core unit suite 389 tests, 0 failures, 8 skipped;
check-quarantine-registry.sh, check-issue-refs.sh, check-copyright-headers.sh, check-file-refs.sh and
check-inflight-tags.sh all green.

Release-Note: none - test-only change.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
astubbs added a commit that referenced this pull request Aug 25, 2026
…per test, qualified refs, retired links

Three corpus repairs behind red gate lanes on this branch:

- docs/quarantined-tests.md carried two live entries for
  PCMetricsTest.metricsRegisterBinding - the original mechanism diagnosis and
  the #265 re-quarantine - which the registry check rightly reads as
  drift. The re-quarantine entry is the current one; it now carries a pointer
  to the first diagnosis (which still stands, in
  bug-pcmetrics-committed-offset-vs-completion-count.md) and the superseded
  block is gone. History keeps the original.

- docs/data/landing-page.yaml still linked docs/inflight/next-landing-page.md,
  retired by b0a5da3 when the owner dropped the workstream; both mentions
  are reworded inline, the same repair that commit applied to the six notes it
  caught.

- Six inflight notes carried bare #NN refs on lines this stack adds vs master:
  each now names its repo (confluentinc#346/#390/#315/confluentinc#606, #51 - each
  resolved in both repos first), a quoted upstream issue body takes the
  line-scoped exempt marker, and two ordinals that were never issue refs at
  all ("problem 1", "hypothesis 6") are written as ordinals.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019HwDcZdfv1Ne4u3g6ThrG9
astubbs added a commit that referenced this pull request Sep 1, 2026
Merges `feats/ks-streams-reconciled` - the reconciliation of #395,
#396, #398 and #391 on top
of the refreshed #394 - into this branch, so that
#271 can be retargeted onto that rung and its displayed diff collapse to the
residue. This is the plan's "retarget move",
`docs/plans/2026-08-31-001-process-god-branch-decomposition-plan.md`, and it is an ordinary merge: no
history was rewritten and nothing was force-pushed. The pre-merge tip is preserved as
`origin/backup/pre-stack-merge-271`.

The merge also brings `master` forward, because the stack is current with it and this branch was
not. That is most of the volume and all but a handful of the conflicts.

## Which side won, and the check that made it safe to say so

The rule was: the rungs' refined versions win wherever both sides have a file; the spike's residue is
kept. **The second half of that is only safe if the spike contributed nothing to the shared files,
and that was measured rather than assumed.** Both trees were exported with package paths normalised
(`io.confluent.parallelconsumer` and `bz.stub.parallelconsumer` folded to one token, and
`io.confluent.csid.utils` to its new home) and compared file by file against the branch's own merge
base. The answer is clean: outside `parallel-consumer-streams` and the streams example, **every
difference this branch carries is the package rename itself plus a copyright-header line** - the same
rename `master` performed independently, which is why taking the rungs' side loses nothing. The one
substantive exception is the streams example's stock-baseline fixtures, which are already on the
stack because #398 depends on them.

- **Files on both sides: the rungs' version, 93 of them.** They carry current master, the rename, and
  every fix the five rungs landed.
- **Files only on the spike: kept, 32 of them.** The plan and result documents, the branch handover,
  the ranked next-work notes, the eight `docs/solutions/` write-ups, and two streams tests the stack
  deliberately left behind - `HeadOfLineBlockingBenchmarkTest`, which
  #398 says it is leaving on the forest, and
  `ProcessorContextConfinementTest`. That residue is what this PR still exists to review.
- **Files master deleted: they stay deleted, 12 of them** - `.semaphore/`, `.travis-archived.yml`,
  `service.yml`, two `.idea` run configurations, the uppercase `docs/` names master lowercased, and
  the `InternalRuntimeException` pair master renamed to `PCInternalRuntimeException`.
- **Two shared ledgers merged as unions, not resolved to a side**:
  `docs/inflight/pr-strategy-doc-merge-triggers.md` and `docs/inflight/release-0.6.0.0.md` keep this
  branch's paragraphs alongside master's.

**The strongest check is the one that makes a mis-paired rename impossible to hide.** Rather than
counting recorded renames, the merged tree was differenced against `feats/ks-streams-reconciled`
directly: the only differences are the 32 additions and the two union-merged ledgers. Nothing else
survived on the wrong side, in the wrong module, or under an `io/confluent` path -
`git ls-files | grep io/confluent` is empty, and the prescribed `grep -rnE 'io[\./]*conflu'` sweep
returns only prose in dated documents.

**Both sides were already renamed, which is not what the plan predicted.** It expected the spike to be
pre-rename; `origin/feats/ks-on-pc-spike` had in fact moved five commits past the worktree's copy and
carries the rename. That is the good case AGENTS.md describes - the mis-pairing surfaces as
rename/rename conflicts on the right files instead of silently applying one module's edit to another -
and it did: three `TestConventionsArchTest.java` files were offered paired across modules, and the
right file was taken into each module rather than accepting git's pairing.

## One collision the merge produced, and the reason it is a good one

`HeadOfLineBlockingBenchmarkTest` carried a private `sleep(Duration)` helper. Since
#395 hoisted the identical helper onto `BrokerStreamsIntegrationTest` -
because two arms that simulate cost differently are not comparable - the two now collide, and the
compiler said so rather than either winning silently. The local copy is deleted and the shared one
inherited, which is what the hoist was for.

## The gates, and the one that is a scoping artefact

`bin/check-all.sh` was run in this worktree. Four gates failed on first pass and **three of the four
did not exist on this branch before the merge** - they arrived with master, and every finding was on
content that predates them.

- **`check-inflight-tags`** flagged sixteen notes with no `inflight-type`, all of them this branch's
  own and all older than the tag scheme. Tagged - a first pass a reviewer should correct where it
  reads wrong. `bug-core-tests-jar-junit-parallelism-leak.md` additionally carries a `closed` state,
  because #265 removed the file it is about.
- **`check-file-refs`** flagged citations broken by the rename - the exact class
  [`docs/citations.md`](docs/citations.md) says must be repaired rather than left. Forty-seven paths
  were re-pointed to their successors, **each verified to exist before the edit was written**; the
  claims around them are untouched, which is the line that document draws. What genuinely has no repo
  path - Apache Kafka's own sources inside the published jar, a placeholder in a shell recipe, a class
  that was only ever proposed - carries a line-scoped `file-refs: N/A` with its reason. Two targets
  that moved out of the tree point at the history holding them instead.
- **`check-issue-refs`** flagged two bare `#NNN` in the handover; qualified.
- **`check-branch-self-reference`** is the artefact, and the gate's own header names this exact
  situation: mid-merge the merge base is still the old one, so master's sentences read as this
  branch's. Twenty-five of the twenty-eight files it flagged are on `feats/ks-streams-reconciled` too
  and twenty-four are byte-identical to it, so marking them would be attesting to somebody else's
  notes - which that header explicitly says not to do. Committing the merge is the documented fix.

## Verified

JDK 17, macOS. The whole reactor compiles, main and test. The reconciled branch it merges was verified
in its own right before this: seam-off oracle unchanged, module unit suite green, and all 35
broker-backed integration arms green against a real broker.
astubbs added a commit that referenced this pull request Sep 1, 2026
…ound

Merging #257 brought master's newer repo-hygiene gates onto this branch, and they immediately
found real debt in this branch's own notes - not in master's. `bin/check-all.sh` goes from 4 failing
gates to 0.

**check-inflight-tags** - nine notes here predate the tag scheme and carried no `inflight-type`, so
the session index could not sort them and they were invisible at session start. Tagged by CONSEQUENCE
per docs/inflight/AGENTS.md, not by filename prefix: the swallowed produce failures are `data-loss`
(a batch marked succeeded for records never produced), the commit-interval override is `config-lie`,
the poisoned transaction is `stall`, the unclosed Kafka clients are `crash`, and the two "tell someone"
notes are `stranded-work`. Register hardening is `task` + `test-debt` rather than `misdirection`: the
false-green at the top of its ranking is the strongest item, but `misdirection` is a bug impact and
the note is a list of decisions.

**check-branch-self-reference** - 24 sentences described #262 or its branch in the present
tense, which the merge falsifies. Rewritten in post-merge terms and attested, not marked-and-left:
the transactional-stack section now states what each PR IS rather than whether its check is red, the
flakes ledger records the #265 collision and the rule-3 lift as history, and two "on this
branch" phrases that named nothing are gone. `branch-transactional-battle-test.md` takes
`post-merge: exempt-file` because being #262's issue map is the file's whole subject.

One claim was wrong rather than merely stale, and is corrected: `pr-strategy-doc-merge-triggers.md`
would have read as though the exactly-once headline had to move. It does not. Two claims were refuted
against a master without #257 and both read PROVED with it merged in, which is what STRATEGY.md
already says.

**check-file-refs** - 22 path citations in the dated battle-test plan still said `io/confluent/`,
broken by this branch's own rename commits. Repaired to `bz/stub/`, which docs/citations.md requires:
the address of the thing the record pointed at may be fixed, its claims may not. Three of them name
files the plan proposes to create for the deferred Phase B, so those paragraphs carry
`file-refs: N/A` instead - a proposal is not a citation.

**Deleted `handoff-262-master-merge.md`.** It was written for an agent picking this branch up cold,
and this merge answers three of its four open items: master's #351 fixed the back-pressure
flake, its de1620d un-quarantined PCMetricsTest, and it absorbed the produce-callback fix the one
unresolved review thread was about. #261 merged, so the fourth is half gone. Its one piece of
evidence that was not recorded elsewhere - the three `(CommitMode)[3]` failures seen locally on
2026-08-13 - is folded into the flakes ledger beside master's own independent `[3]` sighting, where
someone looking for that failure will actually find it. The two corroborate: master saw `[3]` fail on
a branch carrying no main Java, and this branch's own main-code changes are ruled out by grep. The
assertion messages from the local run were not kept, so it is NOT established that the two are the
same failure, and the note says so. The control that would settle it - the same suite on plain
`origin/master` - is still unrun.
astubbs added a commit that referenced this pull request Sep 2, 2026
#29 landed - the confluentinc#857 revoke-path deadlock, which this branch's records name
repeatedly as the thing Phase B waits on. Two conflicts, both docs, both resolved as a union rather
than a pick.

**docs/quarantined-tests.md - union, and both halves matter.** Master's side gained
`MultiInstanceRebalanceTest.largeNumberOfInstances`, quarantined with #29: a rebalance stall
measured but not explained, unowned because no diagnosis exists. That entry is master-state and stays.
This branch's rule-3 lift of `ProducerManagerTest.producedRecordsCantBeInTransactionWithoutItsOffsetDirect`
still applies, so that one comes out - #265 deleted the wall-clock assertion it flaked on, and
#262 owns the re-enable. Taking either side wholesale would have lost one of the two. Registry
check confirms 1 entry, method-granularity.

**docs/inflight/pr-blockers-and-collisions.md - took master's.** Its rewrite of the
`master-confluent` retarget bullet says the same fact better and is already post-merge attested.

**The merge also falsified claims elsewhere, which is the part a conflict list does not show.** Both
live registers this branch owns asserted #29 was unmerged and that Phase B was blocked behind
it. Corrected in `branch-transactional-battle-test.md` and `pr-blockers-and-collisions.md`: Phase B's
blocker is discharged and the work is startable.

Both corrections carry the caveat the commit body supplies, so the next reader does not over-claim
what the deferral bought: **the fix closes the AB-BA cycle only in `PERIODIC_CONSUMER_SYNC`**, because
the other commit modes never block on the commit path and the second edge does not exist there. The
transactional mode this suite covers was therefore never exposed to that edge - so waiting for
#29 protected Phase B's SLO baseline from a defect that would not have appeared in it anyway.
Worth knowing before anyone treats the deferral as having been load-bearing.

Deliberately NOT swept: `docs/inflight/test-857-parallel-integration-proof.md` carries
`inflight-state: deferred - cannot start until #29 lands`, which is now satisfied. It is
master's note for someone else's work, so unblocking it is theirs to do rather than something to
widen this diff with. Dated records under `docs/plans/` that say #29 is "still open" are left
alone on purpose - docs/citations.md permits repairing an address, never rewriting a claim, and those
claims were true when written.

Verified: full-reactor `test-compile` clean, `bin/check-all.sh` 15 passed / 0 failed, quarantine
registry consistent.
astubbs added a commit that referenced this pull request Sep 2, 2026
#262's transactional-guarantee register and its two produce-lock guards.
Three core main files - PollContextInternal, ProducerManager,
AbstractParallelEoSStreamProcessor - and none of them is on this branch's path:
this branch changes offset DECODING, and the produce lock is a commit-path
concern with no offset metadata anywhere near it.

THE CONFLICT, AND WHY NEITHER SIDE COULD JUST BE TAKEN

test-untracked-ci-flakes.md, both sides having edited the same table. Each side
was stale in a different row, so taking either wholesale would have lost
something real:

  - ProducerManagerTest: MASTER's row wins outright and this branch's is
    deleted. Ours still said "quarantined, owner #262"; master's records
    that #265 fixed it by deleting the wall-clock assertion and that
    #262, as owner, LIFTED the quarantine and deleted the registry entry.
    The quarantine lane report on this PR was still printing the old state,
    which is exactly the kind of stale-but-plausible signal this merge corrects.
  - processInKeyOrder: OURS wins. Master still carries the two-sighting version;
    this branch merged master's two with its own four an hour earlier, so the
    six-sighting row across two branches is the superset.
  - MdcContextPropagationTest: new from master, kept. Its own note owns the
    diagnosis.
  - JStream, the PIT lane and ManagedPCInstanceLifecycleTest are this branch's
    and master has never seen them.

Composed rather than resolved by side, which is the only way a shared ledger
survives two writers.

Verified: unit lane BUILD SUCCESS across all eleven modules, 696 tests over the
four library modules, 0 failures. bin/check-all.sh 15/15.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01228AtRiHyTzeH7SjcXzgNj
astubbs added a commit that referenced this pull request Sep 2, 2026
One conflict, in docs/inflight/test-untracked-ci-flakes.md: master rewrote
the ProducerManagerTest row (#265 fixed it, #262 lifted the
quarantine) on the line above the simpleBatchTest row this branch rewrote
for its fifth sighting. Both edits kept; the stray blank line master
removed stays removed. Resolved by editing the markers, and the removals
in the file were read against both parents - each is the other side's
own change.

master's edit to .github/workflows/maven.yml (a comment block on the
Lincheck lane) auto-merged in a region this branch does not touch.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UH2q829FDKQcqQseE8Cp7q
astubbs added a commit that referenced this pull request Sep 7, 2026
bin/check-branch-self-reference.sh asks the merging branch to attest to any note
that names it, at the one moment fixing it is cheap. This note named
`optimize/unit-gate` and asked whether its measurements were taken against an "off"
parallelism arm that was not actually off.

Answered rather than deferred, because the answer is checkable and the note is
about to outlive the branch it names: the arm WAS affected. The leak was closed by
#265, which deletes core's junit-platform.properties from
the tests jar, and every wall-clock figure this branch reported predates it. Those
figures now describe a gate that no longer exists.

What survives is the change itself. runOrder=balanced is a sort, and the
fork-ordering statistics are regenerated against the merged tree, so the mechanism
and the shipped data are unaffected - only the reported seconds need re-taking. The
sibling branch named in the note, ci/reenable-parallel-tests, is still unchecked and
stays open here.

The branch reference is replaced with the PR number, since the branch stops existing
when this lands and a branch name is not a link.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015Xx8GAnzc8F7ksrvpYj8hC
astubbs added a commit that referenced this pull request Sep 7, 2026
Review finding on #105. The write-up's upkeep caveat only covered
one direction - a newly added class is unranked and sorts last - and the reviewer pointed out
that the failure mode actually in front of us is the opposite one, which is worse because it
leaves nothing to see.

Adding a class at least puts something unranked on disk. A class that gets much FASTER, or
disappears, changes nothing observable: surefire's runOrder=balanced keeps sorting, by recorded
costs that describe a suite which no longer exists, and the fork packing decays toward the
unordered scan it replaced. No build goes red, because class ordering is not something an
assertion can be wrong about.

The live instance is core's file, ranked around RunLengthEncoderTest at roughly three times the
next-slowest entry. #106 collapses exactly that class, so landing it without regenerating
the statistics would quietly hand most of this change back. That obligation is recorded in
docs/inflight/pr-blockers-and-collisions.md - the register a session actually inherits - rather
than only in a PR body that stops existing at merge, and it names the remedy: a full
bin/ci-unit-test.sh run on core, committing the rewritten files.

Also states plainly that this change and #106 OVERLAP rather than sum. Packing removes
the idle fork at the end of the run; #106 removes the work that made that fork long. Once
the work is gone the tail is a fraction of its size, so packing keeps helping by proportionally
less against whatever class is next in line. Neither makes the other pointless - a class
scheduled last strands a fork for its own length, whatever that length is - but adding their
gains together would double-count, and a reader of either PR alone would be inclined to.

No wall-clock figure is added, restated or defended here: the PR's headline seconds remain
withdrawn pending re-measurement against a control arm that #265 uncontaminated.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015Xx8GAnzc8F7ksrvpYj8hC
astubbs added a commit that referenced this pull request Sep 7, 2026
…w read them per line

Corrects a claim ee9a3b2 carried in from the automated review on
#105. That review compared the wrong unit and the error survived into
both files that commit touched, so it is fixed here in the same terms it was made.

THE MISTAKE, BECAUSE IT IS THE REUSABLE PART. Each line of a .surefire-pc-unit-times file is one
test METHOD, and a heavy class is spread over many of them. surefire's runOrder=balanced sorts
CLASSES - pom.xml's own comment beside the setting says so, and forking cannot split a class, so
the class is the scheduling unit either way. Ranking the raw lines therefore compares one method
of one class against a whole other class, and it badly overstates how far the top class stands
above the next. The review read core's file that way, put RunLengthEncoderTest at roughly three
times the next entry, and named a METHOD as the class that would define the tail after
#106.

Aggregated per class, the top two are close rather than a factor apart, and the third is well
behind:

  awk -F, '{t[$3]+=$2} END {for (c in t) printf "%9.0f  %s\n", t[c], c}' \
      parallel-consumer-core/.surefire-pc-unit-times | sort -rn | head -5

Both files now state the shape and give that command rather than baking in a ratio, which would
be wrong at the next stats refresh anyway.

WHAT IT CHANGES ABOUT THE ARGUMENT, IN BOTH DIRECTIONS. The staleness risk is real and stays -
an ordering built around a class that has since collapsed decays silently, with no red build -
but it is materially smaller than the review stated. It also cuts the other way, in this
change's favour: because forking cannot split a class, #106 moves the floor down to the
second-heaviest class and no further, and that class is substantial. So the residual tail is
most of the present one and packing keeps most of its value rather than being largely
obsoleted. The "overlap, not sum" paragraph stays correct and stays put; only the implication
that the residual tail is small is removed.

No figure is asserted for #106's own collapse. The review took "62.3s -> 0.2s" from that
branch's commit message, but that measurement predates #265's contaminated-arm fix and
disagrees with both the committed statistics and a run on the merged tree, so the class is
described as collapsing by an order of magnitude and the re-measurement now in flight can supply
the number.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015Xx8GAnzc8F7ksrvpYj8hC
astubbs added a commit that referenced this pull request Sep 7, 2026
…oders are active (#106)

perf(offsets): stop walking every offset when only distance-based encoders are active

OffsetSimultaneousEncoder.invoke() visited every offset between the committed base
offset and the highest succeeded offset. When that range spans a large gap - up to
~2.1 billion - it is a multi-second scan on the commit path, and it is exactly the
case where no BitSetEncoder can be constructed, leaving only RunLength. It now
visits only the offsets where the completion state changes. This resolves the
encoder's own long-standing TODO about large ranges being slow.

WHY IT IS SAFE. RunLengthEncoder accumulates the open run by the DELTA to the
previously seen offset, not by counting calls. For a maximal run [a,b], visiting a
opens the run and visiting b adds b-a, giving the identical length to visiting every
offset; extra visits inside the run telescope harmlessly. So invoke() needs only each
run's first and last offset, and because a state change can only occur at an
incomplete offset or immediately beside one, the visit set is {0, length-1} plus each
in-range incomplete and its two neighbours. It is sized by the NUMBER OF INCOMPLETES,
never by the range width.

The full scan is retained whenever any active encoder requires every offset (BitSet,
ByteBuffer), expressed as OffsetEncoder.requiresEveryOffset() and defaulting to the
safe answer, so a future encoder opts into sparse deliberately rather than inheriting
it by accident.

REVIEW FOUND TWO DEFECTS IN THE FIRST VERSION, AND BOTH ARE FIXED. Cross-model review
(Codex, confirmed independently by a Claude pass) found two bugs in the hand-written
in-range filter. Both break the same premise, which is what makes them correctness
bugs rather than edge cases: the boundary proof holds only if the visit set contains
EVERY in-range incomplete - miss one and the run boundary beside it is never visited,
the run is absorbed into its neighbour, and the encoding silently diverges with no
exception raised.

  - The exclusive end offset is highestSucceededOffset + 1, which wraps to
    Long.MIN_VALUE at Long.MAX_VALUE, dropping every incomplete and encoding them as
    complete. The bound is now the inclusive last offset, which reconstructs
    highestSucceededOffset and cannot wrap.
  - The early exit assumed ascending iteration, but the incompletes set is
    caller-supplied on a public constructor whose field javadoc promises no order
    requirement. It is removed rather than repaired: it could never fire in
    production, because encodeOffsetsCompressed samples the high-water mark once and
    derives both the set and this range top from it.

Both are latent rather than reachable by a running deployment - the first needs a
partition at ~9.2 quintillion offsets, and the only production supplier of the set
collects into a natural-order TreeSet. Note SortedSet#subSet, which the hand-written
loop replaced, WOULD have honoured the set's comparator; avoiding subSet for its own
good reason must not import an ordering assumption it never had. The loop carries
that reasoning so it is not undone.

VERIFICATION. A differential test runs both strategies over 130 generated scenarios at
a fixed seed and asserts the encodings are byte-for-byte identical, that the key sets
match, and that the sparse path was genuinely taken. Two further regression tests
cover the shapes above, and both were proven by sabotage rather than assumed: with the
old loop restored each fails with its predicted symptom - an empty encoding map, and a
byte mismatch against the full scan - while all 130 pre-existing scenarios still pass,
which is the direct evidence that the differential test could never have caught either.

No existing test is weakened, skipped or excluded. RunLengthEncoderTest changes are
javadoc only; its assertions are untouched.

PERFORMANCE. RunLengthEncoderTest collapses by an order of magnitude, from tens of
seconds to a fraction of one. Deliberately no gate-level figure: the numbers this work
originally quoted were taken before #265 fixed a leak that
made dependent modules run thread-parallel regardless of their own setting, so they
describe a CI gate that no longer exists. The class-level win is a change in
algorithmic complexity and stands without a benchmark. Reproduce with
./mvnw -Pci -pl parallel-consumer-core -am test.

FOLLOW-UP OWED AFTER THIS MERGES. This collapses the runtime of the class that
#105's checked-in .surefire-pc-unit-times ordering is built
around, so those statistics must be regenerated with a full bin/ci-unit-test.sh or
that PR's test packing decays silently, with no red build to say so.

IT ALSO CARRIES ONE DOCUMENTATION LEARNING, deliberately rather than as its own PR.
Bringing this branch across the package rename produced rename/rename conflicts on
the near-identical per-module arch tests, and resolving them with `git checkout
--theirs` staged files still containing conflict markers. The write-up added under
docs/solutions/workflow-issues/ records the mechanism: --theirs fails loudly there
(stages 2 and 3 sit at different paths, so the path you name has no stage 3), and the
silent step is the `git add` after it, which stages whatever the merge left in the
worktree and leaves `git ls-files -u` clean. A batched invocation aborts on the first
bad path, so ordinary conflicts sharing that command line are left unresolved too.
The rule that generalises - resolve by explicit ref and check the command's status,
not the look of the tree - was already in use in this repo but had never been written
down. Its first draft got the mechanism backwards and is corrected in the second
commit, which is why both are here.

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
astubbs added a commit that referenced this pull request Sep 7, 2026
…only became measurable after #106 (#105)

test(ci): fork-tail packing measured and rejected - and why the gate only became measurable after #106

This branch set out to cut wall time off the required Unit Tests gate by packing the
surefire fork tail: run the slowest test classes first so no fork idles at the end.
The mechanism was built, the plumbing that makes it work on CI was found, and it was
then measured properly and REJECTED. What lands is documentation - a null result and
the findings around it. No Java, no pom.xml change, no checked-in data.

WHY IT LOOKED RIGHT. Surefire's forks pull classes from one shared queue and the run
ends when the last fork finishes, so scheduling the longest job first is textbook
longest-processing-time packing. Surefire 3.5.5's runOrderStatisticsFileChecksum made
it usable on CI for the first time by pinning the statistics filename, so the recorded
runtimes could be committed and survive a cold checkout.

WHY IT COULD NOT BE JUDGED UNTIL NOW, which is the part worth keeping. The packing was
built around one un-splittable class that dominated both the gate's wall time and its
variance. Measured with that class intact, the ordering was being judged in exactly the
arrangement this repo's integration-lane write-up says buys nothing for ANY arrangement
- the dominant class still setting the floor. #106 collapsed
that class; only then could the ordering be regenerated on the merged tree and the two
compared. Shrink the dominant class first, re-derive, then measure.

THE RESULT. Two arms sharing that base, statistics regenerated on the very tree under
test, interleaved, three repetitions each, in a container capped to the runner's core
count: the packing arm was slower in every paired repetition, by a few seconds at the
median. A small consistent loss rather than no measurable effect. The write-up states
the shape and the reproduce recipe rather than the numbers, which go stale on the next
run.

THE FINDING THAT OUTLIVES IT. #106 did not only make the gate
faster, it made the gate MEASURABLE. Repeat runs of identical code used to differ by up
to a minute and a half; across these runs the spread was seconds. The variance everyone
had been fighting was that one class landing in different fork slots. That is why a
difference of a few seconds resolves now where ninety could not before, and it changes
what any future measurement on this gate is worth.

ALSO HERE. Maven -T module parallelism loses on a 2-core gate, measured, and starves
wait-heavy tests into awaitility timeouts - pick one parallelism axis per core budget.
A benchmark harness must not mutate its own input, since surefire rewrites the ordering
statistics in place and a run then inherits the previous run's fork placement. A codecov
sighting where a PR containing no Java, compared against a base that is a proven git
ancestor of its head, was still reported as carrying more files and more lines than that
base - recorded with its evidence and explicit about which half of the existing note it
does not test. And an AGENTS.md worktree rule: name the tree on every commit, because a
bare git commit resolves against the session root, which is some other worktree.

The write-up keeps its own pre-measurement prediction, marked WRONG and left visible:
it argued packing would keep most of its value once the dominant class shrank. The
per-class arithmetic behind that was right and the conclusion still did not follow. A
mechanism that is real is not the same as a mechanism that pays, and only a measurement
tells the two apart.

The wall-clock figures this work originally quoted are withdrawn rather than corrected:
they predate #265 closing a leak that made dependent modules
run thread-parallel regardless of their own setting, so they describe a gate that no
longer exists.

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
astubbs added a commit that referenced this pull request Sep 9, 2026
…a week ago (#490)

Working docs/inflight/test-untracked-ci-flakes.md, undiagnosed row first.
Four rows retired, one new instance found and fixed, four left open with the
reason stated in each.

THE UNDIAGNOSED ROW WAS NOT UNDIAGNOSED, IT WAS STALE

processInKeyOrder failing its own `[sanity check input data]` has a mechanism,
a fix, and a measurement - all of them on master since 2026-09-02. The wait in
front of that assertion counted CONTROL loop cycles, while `polled` is filled
by the POLL thread from a doAnswer on consumerSpy.poll; nothing orders the two,
so the loop can turn before the poll thread has been scheduled and the list is
empty. All-or-nothing, because MockConsumer hands over the whole batch at once.
#29 replaced the cycle count with a wait on the data (`551f40011`,
merged as `a6941020f`), measured matched-pair at 5 failures in 31 versus 0 in 31.

The provenance check is what settles the row rather than another measurement:
EVERY recorded sighting predates that commit reaching master, including the one
whose control arm reddened "unmodified master" - that arm was at `b2e6c190d`,
five days before the fix landed. There is no sighting on a tree carrying it.

A second, branch-side ledger of this same failure exists on refs that never
merged (`test-processinkeyorder-sanity-check-races-the-first-poll.md`, findable
with `node bin/inflight.mjs prior-art`), which is why the working tree looked
like it had less evidence than the corpus held.

A NEW INSTANCE OF THE SAME CLASS, CAUGHT BY THE CONTROL ARM

`551f40011` named the other assert-after-N-cycles waits and left them as
master-side hardening tracked in this register. Running the control arm for the
above - master with only that await removed - reddened one of them:
inFlightMessagesCommittedIfProcessedDuringShutdown, whose
`awaitForSomeLoopCycles(2)` stands in for "the record is in flight". Under load
close() can find nothing to complete and the commit assertion reads []. It now
waits on the user function actually being entered, which is a STRONGER
precondition, not a looser deadline: a [] after it means close() genuinely
failed to complete in-flight work, which is a product signal.

AMBIENTPROBEEXTENSIONTEST - DIAGNOSED IN THE REGISTER, NOW FIXED AND PROVEN

LogCapture attaches to a process-global logger, and three headroom methods each
assert the exact set of lines they saw while running concurrently, so each
captures its siblings'. Control: master, class alone, red 4 of 4. Treatment:
same commit plus three @ResourceLock annotations, green 6 of 6. Sabotage-checked
per docs/testing-at-write-time.md - deleting reportDeadlineHeadroom's PASSED
call from AmbientProbeExtension.testSuccessful reds exactly
headroomIsReportedOnAPassingTestToo, so the lock isolates without blunting.

A lock rather than @execution(SAME_THREAD) on the class: the two other classes
with this shape capture in most of their methods, this one in three of many.
The class already used that idiom for ENVIRONMENT_DUMP_LOCK.

Never red on CI because the ci profile sets parallel-tests=false, so only local
runs were exposed - which is worse, since local runs are what a developer reads.

DEFECT-CLASS SWEEP - two classes, candidates named

Two test methods capturing the same logger concurrently: every LogCapture.of
call site grouped by (test class, captured logger). Only this class was exposed.
Dismissed with reasons: ConsumerOffsetCommitterAsyncFailureLoggingTest and
LoadFactorCeilingReportingTest (both @execution(SAME_THREAD));
RevokeOnTheControlThreadTest, UserFunctionFailureLoggingTest,
RemovedPartitionStateTest and this class's own ProgressProbe capture (one
capturing method each). Cross-class collision is excluded by
mode.classes.default being JUnit's same_thread.

An assertion gated on a cycle count from another thread: both assertThat(polled)
sites are awaited; queuedMessagesNotProcessed... was fixed by #101;
executorThreadsInterruptedOnShutdownTimeout waits on the latch the user function
holds, not on a cycle count, and is left alone.

TWO ROWS RETIRED THAT THEIR OWNERS SHOULD HAVE RETIRED

The JStream row said outright that its mechanism was #116's and that
whoever merged it owned the retirement; #116 merged on 2026-09-03 and
JStreamLiveResultStreamTest is in the tree. The ProducerManagerTest row was
describing finished work - #265 and #262 both merged.

WHAT STAYS OPEN, AND WHY

The PIT lane, rapidToggleShouldNotCreateDuplicateInstances, ReactorPCTest and
CommitResponseTimeoutSymptomTest keep their rows and their stated reasons.
Nothing is quarantined: docs/quarantined-tests.md is empty and none of these has
the rate or the diagnosis rule 1 wants.

Two new local sightings from this pass's own runs are recorded as their own row
before the logs expire - queuedMessagesNotProcessedOrCommittedIfSubmittedDuring-
Shutdown and closeAfterSingleMessageShouldBeEventBasedFast, one sighting each,
which is a sighting and not a rate.

THE SABOTAGE TOOK FOUR ATTEMPTS, AND THE FIRST THREE WERE FALSE NEGATIVES

The shutdown fix in the previous commit needed the mandatory break-it-first check
from docs/testing-at-write-time.md, and the first THREE main-code mutations left
inFlightMessagesCommittedIfProcessedDuringShutdown green. Taken at face value that
reads as "this test asserts nothing about committing". It does not - the mutations
had not reached the commit:

  1. closeDrainFirst() -> DONT_DRAIN. Never ran: the test calls close(), which IS
     closeDontDrainFirst() already, and DONT_DRAIN finishes in-flight work anyway.
  2. The close-sequence call to commitOffsetsThatAreReady() removed. Green.
  3. commitOffsetsThatAreReady() neutered outright. Green - and this one printed a
     marker proving it ran, so the offset this test asserts is not committed by
     that method at all.
  4. AbstractOffsetCommitter#retrieveOffsetsAndCommit's call to commitOffsets
     removed. RED on all three parameters, on the assertion under test.

The marker is the whole point. Without it, three green sabotages would have made a
strong and wrong case that the test was dark, and I would have recorded a defect
that does not exist. The honest reading of a green sabotage is "I have not yet
shown the test still guards its property", never "the property is unguarded".

Recorded in the solution doc rather than in a commit nobody greps, with the
attempts that failed kept rather than dropped - a reader who tries mutation 2 or 3
on this test will otherwise reach the same wrong conclusion. The register's entry
now points at that section before anyone touches the test.

Also adds the matched-pair number for the shutdown fix itself: red twice in
fourteen class runs under heavy load on the unfixed arm, none in fourteen on the
fixed one, the fix being the only difference between the two trees. Small n, said
so - the fix rests on the mechanism and on mutation 4, not on that count.

THE NEW SIGHTINGS ROW WAS OUTSIDE THE TABLE IT WAS ADDED TO

A blank line sat between the last existing row and the row added above for the
two shutdown-path sightings, so GitHub rendered it as a separate one-row table
with the sighting text as its header: present in the file, absent from the
register a reader sees. Nothing checks markdown table continuity, and the added
row looks correct in a diff, which is how it survived a review. That row's reason
for recording rather than diagnosing also said "the seeds die with the logs",
borrowed from the chaos suite; these are MockConsumer unit tests with no seed,
and what expires is the local run's own output.

VERIFIED AFTER THE MERGE, WITH THE FAILING CONDITION ACTUALLY PRESENT

Both fixed tests were looped on the merged tree - AmbientProbeExtensionTest class
alone and ParallelEoSStreamProcessorTest#inFlightMessagesCommittedIfProcessed-
DuringShutdown - twelve alternating rounds before the master merge and ten after,
green every time on both. Run WITHOUT -Pci on purpose: the `ci` profile sets
parallel-tests=false, so under it JUnit thread parallelism is off and the
AmbientProbe defect cannot occur - a green there would have proven nothing. The
surefire reports were read rather than the exit codes trusted, confirming each
round reached 28 methods and 3 parameters instead of no-opping.

The class-scope SpotBugs finding attributed to this PR's diff was checked rather
than assumed inherited: its annotation spans lines 67 to 1729, the whole class,
and its cause is a `org.mockito.internal` static import written in 2021. The same
finding fires on JStreamParallelEoSStreamProcessorTest, which this branch does not
touch. Left alone.

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

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant