Skip to content

ci: fix four SIGPIPE-inverted checks, guard the class, and restore action-version automation - #211

Merged
astubbs merged 5 commits into
masterfrom
ci/grant-review-gate-selftest
Aug 6, 2026
Merged

ci: fix four SIGPIPE-inverted checks, guard the class, and restore action-version automation#211
astubbs merged 5 commits into
masterfrom
ci/grant-review-gate-selftest

Conversation

@astubbs

@astubbs astubbs commented Aug 6, 2026

Copy link
Copy Markdown
Owner

Description

Started as two lines granting the reviewer one script. Each step exposed the next, so it ended up as a small CI-hygiene pass: fix a class of bug, add the guard that catches it, and turn back on the automation that should have been watching.

1. The reviewer could not run the thing it was reviewing

bin/test-check-review-posted.sh was missing from --allowedTools while its sibling bin/test-check-copyright-headers.sh was granted. So when #210 changed the review gate, the reviewer verified the fix by reading and said so - on the one PR where executing it mattered. The workflow already runs that script itself.

Granted, both spellings (they are prefix matches, not globs). Not widened to bin/*: the list is enumerated as an injection-safety margin, and a directory glob gives that away as effectively as Bash(*).

2. Four scripts inverted their own answer

writer | grep -q under set -o pipefail reports failure exactly when it matches: grep exits on the first hit, the writer takes EPIPE, pipefail promotes 141. It needs >64 KiB still to write, so it passes every small fixture and surfaces on real data.

Site State
check-review-posted.sh:94 live - reported "no review posted" on four PRs whose reviews had posted (#198, #199, #204, #210)
check-quarantine-owners.sh:98, :110 latent, 351 bytes away - see below
quarantine-lane-report.sh:201 latent - its `

The quarantine one is the find worth reading twice. It pipes a whole source file into grep -q inside an if. Pipe buffer 65,536 bytes; AbstractParallelEoSStreamProcessor.java is 65,185. Two open PRs (#203, #205) are adding lines to that file. When it crosses, the failure reads "the quarantine is not yet on its base" - a missing annotation, nowhere near a pipe.

All four become herestrings.

3. Guards, because docs do not stop recurrence

bin/check-shell-sigpipe.sh - fails any bin/*.sh piping into grep -q under pipefail. Matches every flag spelling (-q, -qE, -Eq, grep -v -q, --quiet), skips exactly two files - itself and its self-test - because both carry the anti-pattern as data.

shellcheck does not detect this. Verified against the known-bad line: clean. Hence a bespoke grep rather than adopting a linter.

bin/check-action-versions.sh - fails if any action is used at two versions. It found drift immediately: claude.yml and claude-code-review.yml were still on checkout@v4, which runs on deprecated Node 20. All 24 uses now @v6.

Both have self-tests (11 cases for the SIGPIPE guard), and every regression case was verified red against the pre-fix code before being kept.

4. Dependabot had been off since 2022

.github/dependabot.yml had the github-actions ecosystem commented out by a470ab0b with "Repo doesn't use github actions anymore" - true then, and false for years. Nothing had bumped an action since, which is why the drift went unnoticed.

Re-enabled weekly, and deliberately not grouped, unlike the maven ecosystem. Grouping buys less noise; actions bump a few times a year, so there is little to buy off. It costs isolation, and an action has repo-wide reach - a bad checkout breaks every workflow, and in a grouped PR of five you cannot tell which, nor merge the safe four. Dependabot still bumps every use of one action together, so versions stay consistent either way.

No PR limit: that cap stops a swarm of Java dep PRs; actions are a trickle, and a limit would silently withhold an update.

astubbs/* ignored, with the reason inline - each is pinned to a SHA ahead of that fork's newest tag, so Dependabot would advance unreleased branch work. A workaround to remove once #212 lands.

5. Where these live

repo-hygiene.yml (renamed from shell-hygiene.yml when the first non-shell check arrived within the hour), one job per concern:

  • shell: sigpipe - now a required context in the master ruleset
  • workflows: action versions - new, advisory

The job name shell: sigpipe is untouched by the rename: the ruleset keys on the job, not the workflow.

bin/AGENTS.md (new) records what earns a reviewer grant, what must never get one, and both guards' rules - because the honest answer to "which convention failed here?" was that none existed.

Known-red check

claude-review fails here and cannot be fixed from inside this PR. Editing claude-code-review.yml makes the action skip its own review, so none posts, and the gate correctly reports that. Needs an admin merge or a bypass.

Follow-ups filed

  • CI: our three forked actions are pinned to unreleased commits, not releases #212 - the three forked actions pinned to unreleased commits (next-patch-release)
  • The interactive reviewer path (claude.yml) has no --allowedTools at all, so @claude review this - the workaround the gate's own error recommends - produces a reviewer that structurally cannot execute anything. All four review passes here were static for that reason. Worth its own change.

Checklist

  • Tests - two new self-tests (11 + existing), all regression cases verified red against pre-fix code; check-copyright-headers.sh clean (232 files, 0 violations)
  • Docs updated - bin/AGENTS.md new, AGENTS.md CI list, inline rationale in both workflows and dependabot.yml
  • Changelog - N/A, not a per-PR chore (AGENTS.mdChangelog); CI tooling earns no entry under the entry test
  • No product code touched - nothing under src/

@github-actions

github-actions Bot commented Aug 6, 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
  • ⚠️ 1 package(s) with unknown licenses.
See the Details below.

License Issues

.github/workflows/repo-hygiene.yml

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

OpenSSF Scorecard

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

Scanned Files

  • .github/workflows/repo-hygiene.yml

@github-actions

github-actions Bot commented Aug 6, 2026

Copy link
Copy Markdown

✅ Duplicate Code Report

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

✅ PMD CPD

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

No new clones introduced by this PR.

✅ jscpd (language-agnostic)

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

No new clones introduced by this PR.

Powered by astubbs/duplicate-code-cross-check

@github-actions

github-actions Bot commented Aug 6, 2026

Copy link
Copy Markdown

📌 Duplicate code detection tool report

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

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

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

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

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

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

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

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

File Similarity (%)
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/ParallelConsumerException.java 54.33 ⚠️
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/internal/InternalException.java 40.34
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/PCRetriableException.java 36.96
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/EncodingNotSupportedException.java 36.96
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/RunLengthV1EncodingNotSupported.java 35.33
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/RunLengthV2EncodingNotSupported.java 35.33
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/BitSetEncodingNotSupportedException.java 35.25
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/OffsetDecodingError.java 34.1
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/NoEncodingPossibleException.java 30.02
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/JStreamParallelEoSStreamProcessor.java

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

File Similarity (%)
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/JStreamParallelStreamProcessor.java 60.98 ⚠️
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/ParallelEoSStreamProcessor.java 54.75 ⚠️
parallel-consumer-vertx/src/main/java/io/confluent/parallelconsumer/vertx/JStreamVertxParallelEoSStreamProcessor.java 40.4
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/ParallelStreamProcessor.java 37.02
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/PollContextInternal.java 32.7
parallel-consumer-vertx/src/main/java/io/confluent/parallelconsumer/vertx/JStreamVertxParallelStreamProcessor.java 31.47
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/JStreamParallelStreamProcessor.java

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

File Similarity (%)
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/JStreamParallelEoSStreamProcessor.java 60.98 ⚠️
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/ParallelEoSStreamProcessor.java 50.67 ⚠️
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/ParallelStreamProcessor.java 36.78
parallel-consumer-vertx/src/main/java/io/confluent/parallelconsumer/vertx/JStreamVertxParallelEoSStreamProcessor.java 32.45
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/PollContextInternal.java 31.66
parallel-consumer-vertx/src/main/java/io/confluent/parallelconsumer/vertx/JStreamVertxParallelStreamProcessor.java 30.22
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/PCRetriableException.java

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

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

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

File Similarity (%)
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/ExceptionInUserFunctionException.java 54.33 ⚠️
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/internal/InternalException.java 53.25 ⚠️
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/EncodingNotSupportedException.java 44.95
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/BitSetEncodingNotSupportedException.java 35.02
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/OffsetDecodingError.java 33.71
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/RunLengthV1EncodingNotSupported.java 31.09
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/RunLengthV2EncodingNotSupported.java 31.09
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/internal/InternalRuntimeException.java 30.79
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/NoEncodingPossibleException.java 30.11
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/ParallelConsumerOptions.java

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

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

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

File Similarity (%)
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/JStreamParallelEoSStreamProcessor.java 54.75 ⚠️
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/JStreamParallelStreamProcessor.java 50.67 ⚠️
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/ParallelStreamProcessor.java 45.54
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/PollContextInternal.java 33.91
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/internal/AbstractParallelEoSStreamProcessor.java 33.05
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/internal/TestParallelEoSStreamProcessor.java 31.14
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/ParallelStreamProcessor.java

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

File Similarity (%)
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/ParallelEoSStreamProcessor.java 45.54
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/JStreamParallelEoSStreamProcessor.java 37.02
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/JStreamParallelStreamProcessor.java 36.78
parallel-consumer-vertx/src/main/java/io/confluent/parallelconsumer/vertx/JStreamVertxParallelStreamProcessor.java 32.61
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/PollContext.java

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

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

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

File Similarity (%)
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/ParallelEoSStreamProcessor.java 33.91
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/RecordContextInternal.java 33.11
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/JStreamParallelEoSStreamProcessor.java 32.7
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/PollContext.java 32.4
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/JStreamParallelStreamProcessor.java 31.66
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/RecordContextInternal.java

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

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

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

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

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

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

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

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

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

File Similarity (%)
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/EncodingNotSupportedException.java 60.56 ⚠️
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/ParallelConsumerException.java 53.25 ⚠️
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/OffsetDecodingError.java 50.97 ⚠️
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/NoEncodingPossibleException.java 48.86
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/ExceptionInUserFunctionException.java 40.34
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/internal/InternalRuntimeException.java 39.49
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/BitSetEncodingNotSupportedException.java 37.25
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/RunLengthV1EncodingNotSupported.java 33.97
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/RunLengthV2EncodingNotSupported.java 33.97
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/PCRetriableException.java 33.09
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/internal/InternalRuntimeException.java

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

File Similarity (%)
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/internal/InternalException.java 39.49
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/EncodingNotSupportedException.java 31.44
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/ParallelConsumerException.java 30.79
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/internal/PCModule.java

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

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

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

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

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

File Similarity (%)
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/EncodingNotSupportedException.java 51.73 ⚠️
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/RunLengthV1EncodingNotSupported.java 37.65
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/RunLengthV2EncodingNotSupported.java 37.65
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/internal/InternalException.java 37.25
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/ExceptionInUserFunctionException.java 35.25
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/ParallelConsumerException.java 35.02
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/OffsetDecodingError.java 32.89
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/EncodingNotSupportedException.java

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

File Similarity (%)
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/internal/InternalException.java 60.56 ⚠️
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/BitSetEncodingNotSupportedException.java 51.73 ⚠️
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/OffsetDecodingError.java 48.44
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/RunLengthV1EncodingNotSupported.java 47.33
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/RunLengthV2EncodingNotSupported.java 47.33
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/NoEncodingPossibleException.java 46.8
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/ParallelConsumerException.java 44.95
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/ExceptionInUserFunctionException.java 36.96
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/internal/InternalRuntimeException.java 31.44
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/NoEncodingPossibleException.java

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

File Similarity (%)
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/internal/InternalException.java 48.86
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/EncodingNotSupportedException.java 46.8
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/OffsetDecodingError.java 45.42
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/RunLengthV1EncodingNotSupported.java 38.34
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/RunLengthV2EncodingNotSupported.java 38.34
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/ParallelConsumerException.java 30.11
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/ExceptionInUserFunctionException.java 30.02
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/OffsetDecodingError.java

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

File Similarity (%)
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/internal/InternalException.java 50.97 ⚠️
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/EncodingNotSupportedException.java 48.44
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/NoEncodingPossibleException.java 45.42
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/ExceptionInUserFunctionException.java 34.1
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/ParallelConsumerException.java 33.71
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/BitSetEncodingNotSupportedException.java 32.89
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/RunLengthV1EncodingNotSupported.java 31.74
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/RunLengthV2EncodingNotSupported.java 31.74
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/RunLengthV1EncodingNotSupported.java

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

File Similarity (%)
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/RunLengthV2EncodingNotSupported.java 63.61 ⚠️
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/EncodingNotSupportedException.java 47.33
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/NoEncodingPossibleException.java 38.34
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/BitSetEncodingNotSupportedException.java 37.65
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/ExceptionInUserFunctionException.java 35.33
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/internal/InternalException.java 33.97
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/OffsetDecodingError.java 31.74
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/ParallelConsumerException.java 31.09
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/RunLengthV2EncodingNotSupported.java

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

File Similarity (%)
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/RunLengthV1EncodingNotSupported.java 63.61 ⚠️
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/EncodingNotSupportedException.java 47.33
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/NoEncodingPossibleException.java 38.34
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/BitSetEncodingNotSupportedException.java 37.65
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/ExceptionInUserFunctionException.java 35.33
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/internal/InternalException.java 33.97
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/OffsetDecodingError.java 31.74
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/ParallelConsumerException.java 31.09
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/state/PartitionState.java

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

File Similarity (%)
parallel-consumer-core/src/test-integration/java/io/confluent/parallelconsumer/integrationTests/VeryLargeMessageVolumeTest.java 60.68 ⚠️
parallel-consumer-core/src/test-integration/java/io/confluent/parallelconsumer/integrationTests/MultiInstanceHighVolumeTest.java 46.95
parallel-consumer-core/src/test-integration/java/io/confluent/parallelconsumer/integrationTests/MultiInstanceRebalanceTest.java 41.12
parallel-consumer-core/src/test-integration/java/io/confluent/parallelconsumer/integrationTests/VeryLargeMessageVolumeTest.java

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

File Similarity (%)
parallel-consumer-core/src/test-integration/java/io/confluent/parallelconsumer/integrationTests/TransactionAndCommitModeTest.java 60.68 ⚠️
parallel-consumer-core/src/test-integration/java/io/confluent/parallelconsumer/integrationTests/MultiInstanceHighVolumeTest.java 55.48 ⚠️
parallel-consumer-core/src/test-integration/java/io/confluent/parallelconsumer/integrationTests/MultiInstanceRebalanceTest.java 44.17
parallel-consumer-vertx/src/test-integration/java/io/confluent/parallelconsumer/vertx/integrationTests/VertxConcurrencyIT.java 39.2
parallel-consumer-core/src/test-integration/java/io/confluent/parallelconsumer/integrationTests/chaostests/AbstractRevokeUnderWorkScenario.java

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

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

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

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

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

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

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

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

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

File Similarity (%)
parallel-consumer-core/src/test-integration/java/io/confluent/parallelconsumer/integrationTests/chaostests/ChaosChurnStormIT.java 38.01
parallel-consumer-core/src/test-integration/java/io/confluent/parallelconsumer/integrationTests/state/LatestResetTailNudgeIT.java

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

File Similarity (%)
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/MockConsumerEarlyCloseTest.java 70.4 ⚠️
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/MockConsumerTest.java 56.95 ⚠️
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/MockConsumerSaslAuthenticationTest.java 49.51
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/CommitRejectionTestBase.java 32.48
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/MockConsumerEarlyCloseTest.java

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

File Similarity (%)
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/MockConsumerCommitTimeoutTest.java 70.4 ⚠️
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/MockConsumerTest.java 55.43 ⚠️
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/MockConsumerSaslAuthenticationTest.java 52.91 ⚠️
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/MockConsumerSaslAuthenticationTest.java

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

File Similarity (%)
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/MockConsumerEarlyCloseTest.java 52.91 ⚠️
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/MockConsumerCommitTimeoutTest.java 49.51
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/MockConsumerTest.java 46.91
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/MockConsumerTest.java

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

File Similarity (%)
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/MockConsumerCommitTimeoutTest.java 56.95 ⚠️
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/MockConsumerEarlyCloseTest.java 55.43 ⚠️
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/MockConsumerSaslAuthenticationTest.java 46.91
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/CommitRejectionTestBase.java 32.5
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/ParallelEoSSStreamProcessorRebalancedTest.java

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

@github-actions

github-actions Bot commented Aug 6, 2026

Copy link
Copy Markdown

✅ SpotBugs Report

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

@astubbs

astubbs commented Aug 6, 2026

Copy link
Copy Markdown
Owner Author

@claude review this

@claude

claude Bot commented Aug 6, 2026

Copy link
Copy Markdown

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


Review

  • Gather context (diff, changed files, repo conventions)
  • Verify claims in PR body (both grants present, prefix-match reasoning, workflow guard behavior)
  • Review bin/AGENTS.md content for accuracy/clarity
  • Attempt to run the self-test scripts — see note below
  • Post review feedback

Note on verification method: this review is running under @claude review this, which fires .github/workflows/claude.yml — a workflow with no --allowedTools at all. The grants this PR adds live in claude-code-review.yml's automated-review job, which doesn't apply here, so every Bash call in this session required approval and none could run. I verified everything by reading the code instead of executing it. That's a real, if narrow, gap: the interactive reviewer path can't independently confirm "these tests pass" either — it can only read that they should. Out of scope for this PR though, since it only touches the automated review job.

The diff does what it says.

  • Bash(bin/test-check-review-posted.sh:*) and Bash(./bin/test-check-review-posted.sh:*) are both added to claude-code-review.yml's --allowedTools, right next to the copyright self-test grants they mirror. No stray commas, no malformed entries — checked by eye against the existing list format.
  • Not widened to bin/* — confirmed, still an enumerated list.
  • Addition counts match the PR metadata: 55 new lines in bin/AGENTS.md + 3 added/2 removed in the workflow comment/list = 58/-2.
  • bin/test-check-review-posted.sh and bin/check-review-posted.sh both exist on this branch and are executable, so the new grant isn't inert.

bin/AGENTS.md claims check out against the actual code:

  • The workflow-validation-guard behavior (skips itself, exits 0, when claude-code-review.yml differs from default branch) matches the rationale comment already in check-review-posted.sh (lines 17–21, 44–47) and the "Assert a review was actually posted" step's own comment in the workflow (lines 143–149).
  • The "manually requested review doesn't turn the original red check green" claim is correct per check-review-posted.sh's run-id matching — it only accepts a comment citing that specific run id.
  • The printf | grep -q / SIGPIPE-under-pipefail guidance is grounded in real repo convention, not invented: bin/check-copyright-headers.sh already uses herestrings for this exact reason (its own comment says "seen in CI: an upstream file flagged as fork-original"), and bin/test-check-copyright-headers.sh has a structural self-test (lines 172–182) that greps the scanner for | grep -q / | awk patterns and fails if found.

One non-blocking observation, not a defect in this diff: bin/check-review-posted.sh line 94 currently does exactly printf '%s\n' "$comment_bodies" | grep -qE "actions/runs/${run_id}([^0-9]|$)" under set -euo pipefail (line 56) — the precise anti-pattern the new bin/AGENTS.md warns against, with no herestring and no structural guard like the copyright scanner has. Real PR comment threads (this one included — the duplicate-code-report comment alone is tens of KB) can plausibly exceed the 64 KiB pipe buffer where this bites. This PR doesn't touch that file, and the PR body/AGENTS.md text signals #210 is where this actually gets fixed ("adds the same guard to bin/test-check-review-posted.sh, which shipped without one and hit the bug on four PRs"), so this is context for that companion PR, not a blocker here.

Minor nit: the workflow comment reflow splits "so the reviewer can" / "independently re-run what a PR" across two lines in a slightly awkward spot — purely cosmetic, no action needed.

Everything else — merge-order note, the expectation that claude-review goes red on this PR itself (workflow-editing guard working as designed), the checklist — matches what's actually in the diff. No blocking issues.

@astubbs

astubbs commented Aug 6, 2026

Copy link
Copy Markdown
Owner Author

#211 now fixes the violations of its own rule

Fair challenge: this PR added a rule to bin/AGENTS.md while the repo broke it in four places. A rule shipped with known violations is not a rule. All four are fixed here, plus a CI guard so it cannot recur.

Could a static scanner have caught it?

No. shellcheck runs clean on the known-bad line - verified directly against bin/check-review-posted.sh:94 before writing anything. It has no check for SIGPIPE-under-pipefail. That is presumably why this repo hand-rolled a grep-based guard for the copyright scanner rather than adopting a linter, and it is why the new check is bespoke.

shellcheck is not in CI either - it appears only in three scripts' comments.

The four violations

Site Status Why it matters
check-review-posted.sh:94 live reported "no review posted" on four PRs whose reviews had posted - #198, #199, #204, #210
check-quarantine-owners.sh:98, :110 latent, and close see below
quarantine-lane-report.sh:201 latent the `

The quarantine one is the find worth knowing about. It pipes an entire source file into grep -q inside an if, so the pipeline's status is the answer:

if ! git show "FETCH_HEAD:$relpath" 2>/dev/null | grep -qE "$QUARANTINE_ANNOTATION_ERE"; then

The pipe buffer is 65,536 bytes. AbstractParallelEoSStreamProcessor.java is 65,185 bytes.

351 bytes of headroom - on a file that #203 and #205 are both adding lines to. The first quarantined test to live in a file that crosses 64 KiB would fail this check, and the message would read "the quarantine is not yet on its base" - a missing annotation, not a pipe error. Someone would have gone looking in entirely the wrong place.

The fix, and the guard

All four become herestrings - no pipeline, nothing for pipefail to promote.

bin/check-shell-sigpipe.sh (new) enforces it across every script in bin/, wired into copyright.yml beside the existing self-test (seconds, no JDK) and granted to the reviewer.

Verified both directions, not just that it passes: clean on this tree, and exit 1 when the old line is reinstated. It skips itself, because its own failure message necessarily contains the anti-pattern as the "wrong" half of a worked example - noted in the code so the exclusion is not mistaken for an oversight.

Scope is grep -q only. head and awk can misbehave the same way but are common, usually consume everything, and are often written with || true; flagging them would be noise, so that guidance stays in bin/AGENTS.md as prose.

Overlap with #210

check-review-posted.sh:94 is fixed in both PRs - #210 also adds the functional regression test for it. Conflict expected and cheap to resolve. It belongs here because this is the PR that states the rule.

astubbs added a commit that referenced this pull request Aug 6, 2026
#211 added a rule to bin/AGENTS.md - never pipe into `grep -q` under pipefail -
while the repo broke it in four places. A rule shipped with known violations is
not a rule.

`writer | grep -q PATTERN` under `set -o pipefail` reports failure exactly when
it MATCHES: grep exits on the first hit, the writer takes EPIPE (141), pipefail
promotes that to the pipeline's status. It only fires once the writer still has
more than one pipe buffer (64 KiB) to write, so it passes every small fixture
and surfaces when real data grows.

- check-review-posted.sh:94 - live. Reported "no review posted" on four PRs
  whose reviews had posted (#198, #199, #204, #210).
- check-quarantine-owners.sh:98,110 - latent, and close. `git show` pipes a whole
  source file into `grep -q` inside an `if`. The largest file in the repo is
  65,185 bytes against a 65,536-byte buffer: 351 bytes of headroom, on a file two
  open PRs are adding lines to. It would fail as "annotation missing", not as a
  pipe error.
- quarantine-lane-report.sh:201 - the `||` makes a SIGPIPE take the wrong branch
  and silently retarget, rather than shielding it.

All four become herestrings, which have no pipeline to fail.

Adds bin/check-shell-sigpipe.sh, run in CI beside the copyright self-test
(seconds, no JDK) and granted to the reviewer. Verified both directions: clean on
this tree, exit 1 when the old line is reinstated. It skips itself, since its
failure message necessarily contains the anti-pattern as the "wrong" half of a
worked example.

shellcheck does NOT detect this - run against the known-bad line, it passed
clean. Hence a bespoke grep rather than adopting a linter.

Note check-review-posted.sh:94 is also fixed in #210, which adds the functional
regression test for it. Conflict expected and cheap; this PR fixes it because it
is this PR that states the rule.

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

astubbs commented Aug 6, 2026

Copy link
Copy Markdown
Owner Author

@claude review this

@claude

claude Bot commented Aug 6, 2026

Copy link
Copy Markdown

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


Review

  • Gather context (diff, changed files, repo conventions)
  • Verify the two allowedTools grants in claude-code-review.yml
  • Verify bin/AGENTS.md claims
  • Review bin/check-shell-sigpipe.sh (new guard script)
  • Verify the four SIGPIPE fixes (check-review-posted.sh, check-quarantine-owners.sh x2, quarantine-lane-report.sh)
  • Run the self-tests / new guard script if possible — see note
  • Post review feedback

Note on verification method: same gap as the first review pass on this PR — @claude review this runs .github/workflows/claude.yml, which carries no --allowedTools. Every Bash call in this session (including bash bin/check-shell-sigpipe.sh itself) required approval and none could run interactively, so this is a static read, not an executed one. I cross-checked the guard's logic and its effect on the four fix sites by hand instead (details below).

The diff does what the PR body says.

  • Bash(bin/check-shell-sigpipe.sh:*) / Bash(./bin/check-shell-sigpipe.sh:*) are both added to claude-code-review.yml's --allowedTools, and the comment above the list now names the script.
  • copyright.yml gets a new "No SIGPIPE-prone pipes in bin/" step, positioned right after the copyright self-test step, before "Check copyright headers" — matches "wired in beside the existing self-test."
  • All four sites (check-review-posted.sh:94, check-quarantine-owners.sh:98 & :110, quarantine-lane-report.sh:201) are rewritten as herestrings, and all four files do have set -euo pipefail (confirmed by reading each), so these were live risk, not defensive-only cleanup.

Verified the 64 KiB headroom claim directly, since it's the kind of specific number that's usually rounded in a PR body: wc -c on AbstractParallelEoSStreamProcessor.java on this tree returns exactly 65185 bytes against a 65536-byte pipe buffer — the "351 bytes of headroom" claim is exact, not approximate.

Checked the guard script (bin/check-shell-sigpipe.sh) can't false-negative on the fixes it's supposed to police. Grepped bin/*.sh for the raw pattern \|\s*grep -[a-zA-Z]*q independently of the script's own logic: the only remaining hits are the four fix sites' own explanatory comments (e.g. check-review-posted.sh:94, check-quarantine-owners.sh:98) plus the guard's own worked example — all of which start with # after the line-number prefix, so the script's grep -vE '^[0-9]+:[[:space:]]*#' comment filter correctly excludes them. No live violations remain.

One genuine but very minor limitation, not currently live: the violation regex grep -[a-zA-Z]*q matches combined-flag forms (grep -qE, grep -Eq) but not split flags (grep -v -q pattern), since the space breaks the character class. I checked — no script in bin/ currently writes it that way, so this doesn't miss anything today, but it's a blind spot the next author of a check-*.sh won't know about since bin/AGENTS.md's "Scope" note only calls out the intentional head/awk exclusion, not this regex-shape one. Not blocking.

Also non-blocking: check-shell-sigpipe.sh has no bin/test-check-shell-sigpipe.sh self-test, so its self-exclusion line ([ "$f" = "bin/check-shell-sigpipe.sh" ], hardcoded by path) has no regression coverage if the file is ever renamed — it would fail loudly (flag itself) rather than silently, so low severity, and it's consistent with check-quarantine-owners.sh/check-quarantine-registry.sh, which also ship without self-tests. Just flagging it since self-tests are literally this PR's subject.

Cosmetic, carried over from the first review pass, still unaddressed: claude-code-review.yml lines 108-109 still split "so the reviewer can" / "independently re-run what a PR" across an odd line break in the comment reflow. Purely cosmetic.

Everything else matches the PR body: both grants present in both spellings, the enumerated-list rationale intact (not widened to bin/*), bin/AGENTS.md's claims about the workflow-validation guard and the "both spellings, prefix not glob" reasoning check out against the actual code, and the "four violations, all fixed" claim is exhaustive per the independent grep above.

No blocking issues.

@astubbs astubbs left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

@astubbs

astubbs commented Aug 6, 2026

Copy link
Copy Markdown
Owner Author

Both non-blocking findings addressed, plus one they led me to

1. Split-flag blind spot - fixed, and it was worth fixing

Correct: grep -[a-zA-Z]*q is defeated by a space, so grep -v -q and grep --quiet passed straight through.

You were right that nothing in bin/ writes them that way today, so this fixed no live bug. The reason it still mattered is the one you gave: a shape-sensitive guard makes a green check a false reassurance, and the next author of a check-*.sh had no way to learn the limitation - the scope note only documented the deliberate head/awk exclusion.

Now matches -q, -qE, -Eq, split flags and --quiet/--silent, while still not matching a bare word like query, since a leading - is required on the q-bearing token. Both directions are pinned by tests.

2. No self-test - added, 11 cases

bin/test-check-shell-sigpipe.sh, run in CI before the guard it protects, mirroring how the copyright and review-gate self-tests are wired.

The two new-capability cases were verified to fail against the old regex before being kept:

FAIL: pipe into grep -v -q (SPLIT flags)   (expected exit '1', got '0')
FAIL: pipe into grep --quiet (long form)   (expected exit '1', got '0')

A regression test that has never been red proves nothing.

On the self-exclusion specifically - you flagged it as hardcoded by path with no coverage. Rather than test the hardcode, I removed it: the exclusion now matches on basename, so a rename or a move cannot silently switch it off. Case 10 pins that by copying the guard into a fixture directory and confirming it is still skipped.

That change also surfaced a second file needing the same treatment: the self-test itself, whose fixtures are literally the shapes being detected. It now skips exactly two files - itself and test-<itself> - and the code says why. Those are the only two that can legitimately carry the anti-pattern as data; anything else excluded would be a violation in hiding. Case 11 pins it.

3. One I found while doing the above

The exclusion was written [ A ] || [ B ] && continue. Under set -e that list returns non-zero when both tests are false - the classic bash foot-gun. It happened to work, but leaving it in the very file that lectures about shell foot-guns would have been poor. Rewritten as an explicit if.

Also

The comment reflow flagged in both passes is fixed.

bin/AGENTS.md now records the flag spellings covered and the two-file exclusion, so the limitation you identified is documented rather than tribal.

Verification: guard clean on the tree, all 11 self-test cases green, and test-check-review-posted.sh, test-check-copyright-headers.sh and check-copyright-headers.sh (232 files, 0 violations) all still pass.

Standing caveat on this PR's reviews

Both passes were static - @claude review this runs .github/workflows/claude.yml, which carries no --allowedTools at all, so nothing can be executed there. The grants this PR adds are to the automated job, which skips itself here precisely because this PR edits its workflow. So the PR that adds the grant is the one where it cannot be exercised; it takes effect for the next PR that touches these scripts. The interactive path's missing allowlist is a separate gap, worth its own change.

astubbs added a commit that referenced this pull request Aug 6, 2026
Both findings from the second review pass on #211, plus one I found while
addressing them.

The violation regex was `grep -[a-zA-Z]*q`, which a space defeats: `grep -v -q`
and `grep --quiet` both slipped through. Nothing in bin/ writes them that way
today, so this fixed no live bug - but the next author of a check-*.sh would have
had no way to know the guard was shape-sensitive, which makes a green check a
false reassurance. Now matches -q, -qE, -Eq, split flags and the long forms,
while still not matching a bare word like `query` (a leading `-` is required on
the q-bearing token).

Adds bin/test-check-shell-sigpipe.sh - 11 cases, run in CI before the guard it
protects, mirroring how the copyright and review-gate self-tests are wired. The
split-flag and long-form cases were both verified to FAIL against the old regex
before being kept; a regression test that has never been red proves nothing.

The guard's self-exclusion was a hardcoded path, so renaming the file would have
silently switched it off. It now matches on basename, and covers its own
self-test too - whose fixtures are, necessarily, the shapes being detected. Those
are the only two files that may contain the anti-pattern as data; excluding
anything else would be hiding a real violation. Case 11 pins both.

Also rewrites that exclusion from `[ A ] || [ B ] && continue` to an explicit
`if`. Under `set -e` that list returns non-zero when both tests are false - the
exact class of bash foot-gun this script exists to discourage, and it would have
been an unpleasant thing to leave in the file that lectures about them.

Fixes the comment reflow flagged in both review passes.

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

astubbs commented Aug 6, 2026

Copy link
Copy Markdown
Owner Author

@claude review this

@claude

claude Bot commented Aug 6, 2026

Copy link
Copy Markdown

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


Review

  • Gather context (diff since last review pass, changed files)
  • Verify the split-flag regex fix in bin/check-shell-sigpipe.sh
  • Verify the new bin/test-check-shell-sigpipe.sh (11 cases) is meaningful
  • Verify the basename-based self-exclusion (guard + its own test)
  • Verify the set -e foot-gun fix in the exclusion logic
  • Verify bin/AGENTS.md updates document the new scope
  • Post review feedback

Note on verification method, same as both prior passes on this PR: @claude review this runs .github/workflows/claude.yml, which carries no --allowedTools. Every Bash call in this session required approval that isn't available headless, including running bin/test-check-shell-sigpipe.sh and bin/check-shell-sigpipe.sh themselves. I verified the new guard and its self-test by reading the code and by independently re-deriving the guard's regex logic with the Grep tool against bin/*.sh rather than executing the script - detailed below.

The three follow-ups from the second review are addressed, and I confirmed each holds up:

  1. Split-flag blind spot. The regex is now \|[[:space:]]*grep([[:space:]]+-[a-zA-Z-]+)*[[:space:]]+(-[a-zA-Z]*q|--quiet|--silent). I traced it by hand against the five shapes the self-test exercises (-qE, -Eq, split -v -q, --quiet, and the negative case grep query) and it matches exactly where it should: the trailing alternation requires a - immediately before the q-bearing token or --quiet/--silent, so query (no leading -) cannot match, while -v -q matches because the repeated group ([[:space:]]+-[a-zA-Z-]+)* absorbs -v before the final group matches -q. Independently grepping bin/*.sh with this exact pattern (not going through the script) turns up matches only inside comments and inside the two self-referential files - no live violations. That matches the "clean on this tree" claim.

  2. Self-test (bin/test-check-shell-sigpipe.sh, 11 cases). Read line-by-line: cases 2-5 cover the four q-spellings, case 9 is the negative control (grep query), case 6/7 cover comment-only and no-pipefail exemptions, case 8 is the herestring fix itself, and cases 10-11 copy the real guard/self-test into a fixture dir under a different path and confirm the basename match still excludes them - which is the right way to pin "matched on basename, not hardcoded path." Wired into copyright.yml as "Self-test the SIGPIPE guard," immediately before "No SIGPIPE-prone pipes in bin/" - self-test runs before the thing it protects, consistent with how test-check-copyright-headers.sh is sequenced.

  3. set -e foot-gun in the exclusion. Confirmed rewritten as a plain if [ "$base" = "$self_name" ] || [ "$base" = "test-$self_name" ]; then continue; fi (bin/check-shell-sigpipe.sh:56-58) - the [ A ] || [ B ] && continue form it replaced does return non-zero under set -e when both tests are false (bash evaluates the &&/|| list's exit status as that of the last command run, and [ B ] failing when [ A ] already failed leaves a nonzero list status), so this was a legitimate fix, not a stylistic one.

The four SIGPIPE fix sites are all correctly converted, and none reintroduce a pipe:

  • check-review-posted.sh:94, check-quarantine-owners.sh:101,113, quarantine-lane-report.sh:201 all now feed grep -q via <<< herestrings (the git show ones go through <<<"$(git show ...)", which is a command substitution, not a pipeline - no SIGPIPE surface either way). Confirmed all four files still have set -euo pipefail active, so this wasn't dead code being "fixed."
  • quarantine-lane-report.sh:201's companion head -1 also lost its pipe (target=$(head -1 <<<"$changed")), matching the PR body's claim that this site was the more subtle one - a SIGPIPE there would silently retarget via the ||, not just misreport.

bin/AGENTS.md now documents the flag spellings covered and the two-file exclusion (lines 54-56), so the blind spot the last review flagged is written down rather than left tribal, as claimed.

One claim in the round-up comment doesn't fully hold, cosmetic only: the reflow at claude-code-review.yml:107-110 is described as fixed, but it's still a 3-line wrap of one sentence with an awkward break - now ...) so the reviewer / can independently re-run what a PR / claims rather than inferring it..., splitting "a PR" from "claims." Functionally identical to what both earlier passes flagged, just shifted by the two script names inserted earlier in the same comment. Not blocking - purely comment formatting - but worth a one-line rewrap since it's been raised three times now.

No blocking issues. Everything else - the guard's scope decisions (why head/awk stay prose-only, why the self-test needs two exclusions not one), the CI wiring, and the --allowedTools grants for the two new scripts (both spellings, alongside bin/test-check-review-posted.sh which was the subject of the PR's first commit) - matches what's actually in the diff.
(branch: ci/grant-review-gate-selftest)

@astubbs

astubbs commented Aug 6, 2026

Copy link
Copy Markdown
Owner Author

The SIGPIPE checks now have their own workflow

They were bolted onto copyright.yml because they are sub-second and need no JDK. That left a workflow called Copyright Headers half of whose steps were about shell, and a job called Copyright header check doing two unrelated things.

.github/workflows/shell-hygiene.yml (new), one job per concern:

name: Shell Hygiene
jobs:
  sigpipe:
    name: "shell: sigpipe"
    steps:
      - name: Self-test the SIGPIPE guard     # 11 cases - proves the guard CAN fail
        run: bash bin/test-check-shell-sigpipe.sh
      - name: No SIGPIPE-prone pipes in bin/  # the guard itself
        run: bash bin/check-shell-sigpipe.sh

Self-test first, matching how copyright.yml sequences its scanner's self-test ahead of the scan. A guard nobody has proven can fail is a guard nobody should trust.

Why not rename copyright.yml to something broader

Considered and rejected. These checks are not about copyright and never were, so they belong in their own workflow rather than in a renamed version of that one. Moving them out makes copyright.yml accurate again by subtraction.

It also leaves the Copyright header check context untouched - which matters, because the master ruleset requires it by that exact name. Renaming the job would have made the gate wait for a context that no longer exists, so a rename could only have shipped together with a ruleset edit.

One thing needing a decision

shell: sigpipe is a new context and is advisory until it is added to the master ruleset - visible and red on failure, but not blocking a merge. The name follows the convention already there (quarantine: audit, dups: clones, deps: vulnerabilities), so it slots in cleanly whenever you want it gating.

Future shell checks land as sibling jobs, each its own required-status-check candidate rather than hidden inside another's green tick. The cost is one runner spin-up for a sub-second check.

Also

The reviewer-workflow comment flagged in all three passes is properly rewrapped. The previous attempt moved the break rather than fixing it, splitting "a PR" from "claims" - fair catch, it had earned being done properly by the third mention.

@astubbs

astubbs commented Aug 6, 2026

Copy link
Copy Markdown
Owner Author

@claude review this

@claude

claude Bot commented Aug 6, 2026

Copy link
Copy Markdown

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


Review

  • Gather context (diff since last review pass, changed files)
  • Verify the new .github/workflows/shell-hygiene.yml extraction
  • Confirm copyright.yml no longer carries the SIGPIPE steps
  • Confirm required-status-check naming/context claims
  • Verify the reflow fix to claude-code-review.yml comment
  • Post review feedback

Note on verification method, same gap as all three prior passes on this PR: @claude review this runs .github/workflows/claude.yml, which carries no --allowedTools. Every Bash execution in this session required approval that isn't available headless — including running bin/test-check-shell-sigpipe.sh itself — so this is a static read of the new commit, not an executed one. Read-only inspection (git log, grep, file reads) worked fine and is what the findings below are based on.

The extraction does what the commit message says.

  • copyright.yml loses exactly the two SIGPIPE steps (Self-test the SIGPIPE guard, No SIGPIPE-prone pipes in bin/) and nothing else — job name "Copyright header check" is untouched, so the master-ruleset required-check reference the PR body relies on stays valid. Confirmed by diff, not just by reading the final state.
  • New shell-hygiene.yml is well-formed: name, on (push scoped to master + pull_request + workflow_dispatch, matching copyright.yml's stated rationale for avoiding a double-run on PR branches), concurrency group keyed the same way as copyright.yml's (shell-hygiene-${{ github.head_ref || github.ref }} vs copyright-${{ ... }}), permissions: contents: read, one job (sigpipe) named "shell: sigpipe".
  • Step order is self-test-then-guard, matching copyright.yml's sequencing of test-check-copyright-headers.sh ahead of check-copyright-headers.sh — matches the "a guard nobody has proven can fail is a guard nobody should trust" claim in both the commit message and the comment header.
  • bin/check-shell-sigpipe.sh and bin/test-check-shell-sigpipe.sh both exist on this branch, are executable, and their line counts (90 / 106) match the <changed_files> summary — the new workflow's run: lines aren't pointing at anything stale.
  • Both Bash(bin/check-shell-sigpipe.sh:*) / Bash(./bin/check-shell-sigpipe.sh:*) and Bash(bin/test-check-shell-sigpipe.sh:*) / Bash(./bin/test-check-shell-sigpipe.sh:*) are present in claude-code-review.yml's --allowedTools — both scripts, both spellings, consistent with the "grant BOTH spellings" rule this PR's own bin/AGENTS.md states.
  • The reflow: claude-code-review.yml's comment now reads "...so the reviewer can independently re-run what a PR claims..." as one continuous clause instead of breaking mid-phrase — the thing flagged in all three prior passes is actually fixed this time, not just shifted.
  • bin/AGENTS.md's claim that check-shell-sigpipe.sh "runs in CI" still holds; it doesn't name which workflow, so it didn't go stale when the check moved files.

One small, genuine inconsistency, not blocking: shell-hygiene.yml:37 uses actions/checkout@v4, while every other actively-maintained workflow in this repo — including copyright.yml, which this file's own header comment says it deliberately mirrors ("matching copyright.yml and maven.yml") — uses actions/checkout@v6. Checked across all workflow files: @v4 otherwise appears only in the two Anthropic-action files (claude.yml, claude-code-review.yml), which is a different action template, not a repo convention to match. Since this file explicitly models itself on copyright.yml's structure, picking up its checkout version too would've been free; as-is it's a one-file drift that a future bulk checkout bump would need to remember to include. Fix this → https://claude.ai/code?q= bump .github/workflows/shell-hygiene.yml:37 from actions/checkout@v4 to actions/checkout@v6 on branch ci/grant-review-gate-selftest, matching the version already used by copyright.yml and every other current workflow in the repo.

Not independently verifiable from the repo: the claim that shell: sigpipe is "a NEW context and is advisory until someone adds it to the master ruleset." Branch-protection rulesets aren't stored as a file in this repo, so this is a GitHub-side setting I can't check from a checkout — noted, not disputed.

No blocking issues. The split, the job naming convention, the self-test-before-guard sequencing, and the grants all match what the commit message and PR body describe.
(branch: ci/grant-review-gate-selftest)

@astubbs

astubbs commented Aug 6, 2026

Copy link
Copy Markdown
Owner Author

Both points addressed

actions/checkout@v4 — fair catch, fixed

Verified independently rather than taking it: 21 of the repo's 24 actions/checkout uses are @v6. The only other @v4s are claude.yml and claude-code-review.yml, which come from the Anthropic action template — so, as you said, not a convention to match. shell-hygiene.yml was the sole piece of drift, in a file whose own header says it mirrors copyright.yml. Bumped to @v6.

The reasoning for fixing rather than shrugging is the one you gave: it would have been the newest file needing to be remembered separately in a future bulk bump.

The ruleset claim — you were right that you couldn't check it, and it has since changed

You flagged "advisory until someone adds it to the master ruleset" as unverifiable from a checkout. Correct, and worth recording: shell: sigpipe was added to ruleset 15055005 today, so it is now a required context, not advisory. The PR body has been corrected.

Verified after the change that all four rule types (deletion, non_fast_forward, pull_request, required_status_checks) and the original 15 contexts survived — ruleset updates are read-modify-write, so a bad payload silently drops whatever it omits.

Two consequences now live, both recorded in the PR body:

On the verification gap you noted for the fourth time

Every pass on this PR has been static because @claude review this runs claude.yml, which has no --allowedTools at all. The grants this PR adds are to the automated job, which skips itself here precisely because this PR edits its workflow — so the PR that adds the grant is the one that cannot exercise it. It takes effect for the next PR touching these scripts.

The interactive path's missing allowlist is a separate gap and worth its own change: the workaround the gate's own error message recommends (@claude review this) currently produces a reviewer that structurally cannot run anything.

@astubbs astubbs changed the title ci(review): let the reviewer run the review gate's own self-test ci: fix four SIGPIPE-inverted checks, guard the class, and restore action-version automation Aug 6, 2026

@astubbs astubbs left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

astubbs and others added 5 commits August 6, 2026 14:58
bin/test-check-review-posted.sh was missing from --allowedTools while its
sibling bin/test-check-copyright-headers.sh was granted. So when #210 changed
the review gate, the reviewer could not run the gate's self-test and verified
the fix by reading instead - and said so - on the one PR where executing it
mattered most. The workflow already runs that same script itself, at its
"Self-test the review gate" step.

Both spellings granted for each script: these are prefix matches, not globs, so
Bash(bin/foo.sh:*) does not cover ./bin/foo.sh.

Deliberately NOT widened to bin/*. The comment above the list explains why it is
enumerated rather than Bash(*) - the job has no fork guard beyond
sender.type != Bot and reads attacker-influencable text - and a directory glob
gives that margin away just as effectively.

Adds bin/AGENTS.md, because nothing failed to keep the allowlist in sync: no
rule existed. `allowedTools` appears in zero docs, scripts or checks, so a new
verification script stays invisible to the reviewer until someone remembers by
hand. An automated "every script must be granted" check would be wrong - the
list is a security boundary and most scripts belong off it - so the rule is
written down instead: what earns a grant, what must never get one, that both
spellings are needed, and that editing this workflow costs you the review on
that PR.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RtNUsxokE9g2pSEjBHZqNA
`writer | grep -q` under `set -o pipefail` reports failure exactly when it
MATCHES: grep exits on the first hit, the writer takes EPIPE (141), pipefail
promotes that to the pipeline's status. It only fires once the writer still has
more than one pipe buffer (64 KiB) to write, so it passes every small fixture
and surfaces when real data grows.

- check-review-posted.sh:94 - live. Reported "no review posted" on four PRs
  whose reviews had posted (#198, #199, #204, #210).
- check-quarantine-owners.sh:98,110 - latent, and close. `git show` pipes a whole
  source file into `grep -q` inside an `if`. The largest file in the repo is
  65,185 bytes against a 65,536-byte buffer: 351 bytes of headroom, on a file two
  open PRs are adding lines to. It would fail as "annotation missing", not as a
  pipe error, sending the reader nowhere near the cause.
- quarantine-lane-report.sh:201 - the `||` makes a SIGPIPE take the wrong branch
  and silently retarget, rather than shielding it.

All four become herestrings, which have no pipeline to fail.

Kept separate from the guard that enforces this, so the fixes can be reviewed -
and reverted - on their own.

shellcheck does NOT detect this: run against the known-bad line, it passed clean.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RtNUsxokE9g2pSEjBHZqNA
Docs do not stop recurrence, and shellcheck does not detect this pattern -
verified against the known-bad line, which it passed clean. So the rule the
previous commit fixed four instances of gets a check.

bin/check-shell-sigpipe.sh fails any bin/*.sh piping into `grep -q` under
pipefail. It matches every flag spelling - -q, -qE, -Eq, split flags
(`grep -v -q`) and --quiet/--silent - while still not matching a bare word like
`query`, since a leading `-` is required on the q-bearing token.

It skips exactly two files: itself and its self-test. Both must carry the
anti-pattern as DATA - the guard shows the "wrong" half of a worked example in
its failure message, and the self-test's fixtures are literally the shapes being
detected. Anything else skipped would be a violation in hiding. Matched on
basename, not a hardcoded path, so a rename cannot silently switch it off.

bin/test-check-shell-sigpipe.sh, 11 cases, runs in CI BEFORE the guard it
protects - the same sequencing copyright.yml uses. Every case that asserts a
detection was verified to FAIL against a weaker regex before being kept; a
regression test that has never been red proves nothing.

The exclusion is written as an `if`, not `[ A ] || [ B ] && continue`: under
`set -e` that list returns non-zero when both tests are false, which is exactly
the class of bash foot-gun this file exists to discourage.

New repo-hygiene.yml rather than bolting these onto copyright.yml, which would
have left a job called "Copyright header check" doing two unrelated things.
These checks are not about copyright and never were. One job per concern, named
`<area>: <check>` to match the context convention already in the master ruleset
(quarantine: audit, dups: clones, deps: vulnerabilities), so each is its own
required-status-check candidate instead of hiding in a shared green tick.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RtNUsxokE9g2pSEjBHZqNA
Dependabot bumps versions that are already there. It has nothing to say about a
NEW workflow authored at an old version - which is exactly how this PR's own
repo-hygiene.yml shipped at actions/checkout@v4 while 21 other uses were on @v6.
A human caught it in review, and not for the first time.

bin/check-action-versions.sh fails if any action is used at two versions. The
rule is deliberately NOT "checkout must be v6", which rots on the next bump.
"Pick one and use it everywhere" survives upgrades, precisely because Dependabot
raises every use of an action in a single PR, so a consistent repo stays
consistent through them.

SHA pins are exempt and are not drift: the astubbs/* forks are pinned to a commit
on a BRANCH on purpose, so each use site tracks a different ref by design. See
#212 for why that itself wants fixing.

The check immediately found drift beyond the file that prompted it: claude.yml
and claude-code-review.yml were still on actions/checkout@v4. An earlier review
reasoned those away as "a different action template, not a convention to match" -
but checkout is checkout, and v4 runs on deprecated Node 20, which is what the
Node 20 warnings in job logs are. Exempting them instead would have hollowed out
the rule on the day it was written. All 24 uses are now @v6.

Writing the check surfaced a bug in itself: it scanned a stray .bak file left by
the very experiment testing it. Now scoped to *.yml/*.yaml.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RtNUsxokE9g2pSEjBHZqNA
The github-actions ecosystem has been OFF since a470ab0 (2022), commented out
with "Repo doesn't use github actions anymore". True then; the entire CI estate
is now Actions across 24 workflow files. Nothing had bumped an action version in
four years, which is why drift went unnoticed until a human spotted a new file
at checkout@v4 while 21 other uses were on @v6.

Weekly, not daily like maven: actions bump a few times a year, and daily polling
would re-present the same PR.

Deliberately NOT grouped, unlike maven. Grouping buys less noise, and there is
little noise here to buy off. What it costs is isolation, and an action has
repo-wide reach: a bad checkout or setup-java breaks every workflow at once, and
in a grouped PR of five bumps you cannot tell which one broke CI, nor merge the
safe four. This does not fragment versions - Dependabot bumps every use of one
action in a single PR regardless, so bin/check-action-versions.sh stays green.

No open-pull-requests-limit: that cap exists to stop a swarm of Java dependency
PRs. Actions are a trickle, and a limit here would silently withhold an update
rather than reduce work.

astubbs/* ignored, with the reason inline: each is pinned to a SHA AHEAD of that
fork's newest tag - unreleased work on a branch - so Dependabot would advance it
to newer branch commits, a hand-managed decision. Recorded as a workaround to
remove once #212 lands and they reference immutable tags.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RtNUsxokE9g2pSEjBHZqNA
@astubbs
astubbs force-pushed the ci/grant-review-gate-selftest branch from 84ced9f to 708b75f Compare August 6, 2026 02:59
@astubbs
astubbs merged commit dac1f40 into master Aug 6, 2026
24 of 27 checks passed
@astubbs
astubbs deleted the ci/grant-review-gate-selftest branch August 6, 2026 03:08
astubbs added a commit that referenced this pull request Aug 6, 2026
Picks up the two new required contexts (shell: sigpipe, workflows: action
versions) so this PR can report them, and resolves the overlap with #211.

check-review-posted.sh:94 - both branches fixed the same SIGPIPE line. The code
was identical; only the explanatory comment differed. Took master's wording.

test-check-review-posted.sh - this branch's structural guard (no `| grep -q` in
the checker) is now redundant: bin/check-shell-sigpipe.sh landed on master with
#211 and enforces that across every bin/*.sh, in every flag spelling, with its
own self-test. Removed the local copy rather than keep two rules for one thing.

Case 13 is KEPT. It is behavioural where the repo-wide guard is static: it drives
the checker with a match followed by >64 KiB of comments and asserts exit 0, so
it would catch a regression that reintroduced the failure by some route other
than a literal `| grep -q` - which is the only shape the static guard sees.

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

PR Checklist failed with "12 reference(s) below #1000 do not say which repo they
mean". The gate arrived in 735b1d3 (#114), which merged 17 minutes AFTER
#211 - so this branch was written before the rule existed.

The fork's numbers sit inside upstream's range, so a bare number is a coin flip:
#114 found 48 numbers that exist in BOTH repos meaning different things.
All twelve here are fork PRs, now written astubbs#NN.

Pointed, given this PR is about a reference convention.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RtNUsxokE9g2pSEjBHZqNA
astubbs added a commit that referenced this pull request Aug 6, 2026
Brings in #198 and #211, and picks up the two new required
checks (`shell: sigpipe`, `workflows: action versions`) from
.github/workflows/repo-hygiene.yml, which this branch predated - GitHub was
blocking on statuses that could never arrive.

One conflict, in src/docs/development/upstream-map.yaml, resolved in master's
favour: the whole `UPSTREAM ISSUES` block was deleted there, including the
issue-162-861-906-build-friction entry this branch had been updating.

That is not a collision to split the difference on - it is a policy change that
makes this branch's edit obsolete. #211 mirrored all 78 open upstream
issues into this fork and shrank the manifest to track upstream PRs ONLY,
because issues now live in the mirror. AGENTS.md now says so directly: "If the
work maps to an upstream *issue*, the fork mirror is where status goes". This
work maps to confluentinc#861, whose mirror is #180, so re-adding the
entry would reintroduce exactly the duplication #211 removed. The
upstream side of confluentinc#861 is still tracked on master, under the
upstream-pr-901-licence-check entry.

Follow-up commits handle what the merge cannot: #211 also made bare
issue numbers below #1000 a CI failure on added lines, and this branch's added
lines are full of them.

AGENTS.md merged cleanly - both this branch's "Building and running the tests"
section and #211's repo-hygiene CI entry survive.

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

#211 made a bare `#NN` below 1000 a CI failure on added lines, because the
fork's numbers sit entirely inside confluentinc's range - a bare `#200` resolves
here to a ManagedTruth issue while an author may well have meant
confluentinc#200, shared-nothing architecture. This branch predated that rule and
its added lines were full of bare numbers: running
.github/scripts/issue-ref-gate.js over the diff flagged seven, across AGENTS.md,
bin/build.sh, pom.xml and the parked note. All seven now name their repo, fork
first, hyperlinked where the format allows; the gate reports zero.

Two of them gained something in the rewrite. #132 / confluentinc#162 is
titled "mvn compile fails if test-jar of parallel-consumer-core was not
previously installed" - which is precisely the fresh-clone failure this PR spent
its last round correcting, filed from the other end. The docs now say so, in
AGENTS.md and in the parked note, because a reader hitting the vertx dependency
error should find both the explanation and the issue that has been describing it
since 2021.

In the enforcer's POM comment the reference is spelled out with a URL rather than
left as prose: that comment sits beside a <message> body whose indentation is
load-bearing, and a bare number there is the least clickable place in the repo.
The message body itself is untouched - re-verified that the rule still fires and
still prints one [ERROR] per line, left-aligned as intended.

Separately, AGENTS.md listed .github/workflows/shell-hygiene.yml, which does not
exist: commit 1b040cb folded it into repo-hygiene.yml and left the old bullet
behind, so the CI list documented two workflows for one file. Removed the stale
bullet and folded into the surviving one the two details only it carried - that
the SIGPIPE inversion needs >64 KiB after the match to bite, and that shellcheck
does not catch it. Those explain why the check is a bespoke script instead of a
linter rule, which is the part worth keeping. Found while checking this branch's
text still read correctly next to #211's new entry.

Verified: `./mvnw validate` BUILD SUCCESS; `-pl parallel-consumer-core` still
fails the enforcer with the intended message; bin/check-shell-sigpipe.sh and
bin/check-action-versions.sh both pass.

Upstream-Issue: confluentinc#861
Forwarded: not-needed
Applied-Upstream: no

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RtNUsxokE9g2pSEjBHZqNA
astubbs added a commit that referenced this pull request Aug 6, 2026
Brings in the repo-hygiene workflow whose two new required checks
(shell: sigpipe, workflows: action versions) this branch predated, so the
PR was blocked waiting on contexts it could never produce.

Conflict: src/docs/development/upstream-map.yaml. #211 slimmed the
schema (dropped `forwarded`, `todo`, `backlink`, the long-tail DEFERRED
block and scripts/upstream-backlink.sh) and mirrored every open
confluentinc issue into this fork. Resolved by taking master's file whole
and re-adding the issue-402-max-load-factor-log-noise entry in the new
shape: `forwarded`/`todo` dropped (no tooling reads them now), the
backlink action folded into notes, `fork_issue: 155` recorded now that
confluentinc#402's mirror exists, and every issue reference qualified by
repo per the new house rule. scripts/upstream-map.py validate passes.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RtNUsxokE9g2pSEjBHZqNA
astubbs added a commit that referenced this pull request Aug 6, 2026
#211 made a bare `#NN` below #1000 a CI failure on added lines:
the fork's numbers sit entirely inside confluentinc's range, so an
unqualified reference is a coin flip. Three added lines in
docs/inflight/pr-155-load-factor-noise.md tripped the gate; the javadoc
in AbstractParallelEoSStreamProcessor and LoadFactorCeilingReportingTest
passed only via the "upstream confluentinc#402" escape hatch, which the same commit
deprecates in favour of naming the owner. Both now say
#155 / confluentinc#402.

Also moves the "answer the original reporter when this merges" note out
of upstream-map.yaml and into the inflight doc. AGENTS.md is explicit
that the manifest has no todo: field and loose ends belong in
docs/inflight/ - the field was already dropped when the manifest was
slimmed, so leaving the note there would have been an entry no tooling
reads.

Verified with .github/scripts/issue-ref-gate.js over this branch's diff
against master: clean.

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

Two things #211/#212 surfaced in this PR's own files.

#212's lesson - await/assert the thing itself, never a proxy - has
an adjacent shape here worth naming. fixedMessageBufferSizeDoesNotWarnOnEveryPass
asserts NO warnings, which would pass vacuously if the appender were ever
attached to the wrong logger. It is not vacuous today, because the debug
assertion below it can only hold when the capture is live and pointed at
the code under test - but nothing said so, and the two are separable by a
well-meaning edit. Now they are commented as a pair, pointing at the
write-up.

The test needed no other change: it is fully synchronous, driving 500
checkPipelinePressure() passes on the test thread and reading the appender
after, so there is no await to get wrong.

Also rewords the upstream-map note that said "this manifest has no todo:
field". bin/todo-index.sh read the literal marker and wanted to index it,
which is the gate working - the fix is to stop writing a marker in prose,
not to regenerate the index around a false entry.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RtNUsxokE9g2pSEjBHZqNA
astubbs added a commit that referenced this pull request Aug 6, 2026
…lease on" (#210)

#113 moved release notes from per-PR entries to generation from the commit
log at release time. The policy is right; its stated timing was not, and the
wording misled a reader into concluding v6 would ship with whatever text already
sat under `== 0.6.0.0`.

"From the next release on" put 0.6.0.0 on the hand-written side of the line and
started generation after it. Generation covers the release being cut - 0.6.0.0
included. The phrasing was written when the freeze and the release looked
simultaneous; ten PRs landed in between and they came apart.

Restructured around the only question that stays true across releases: HAS THIS
RELEASE SHIPPED. 0.5.x is shipped legacy, frozen. 0.6.0.0 has not shipped, so it
is regenerated at release time and frozen only once it ships. Later releases
inherit the same test rather than needing the text edited again.

Both misreadings are now named and denied outright, because a reader who reaches
the right conclusion by luck will not reach it twice: 0.6.0.0 is not on the
hand-written side, and its current contents are not what v6 will publish - not
yours to add to, nor to trust.

The bad wording had already been copied into a fourth file,
docs/inflight/release-0600-blockers.md, within a day of being written. Corrected
there too.

States the correction exception, which previously had to be inferred: a PR never
ADDS an entry, but may correct a factual error in text already there - as
#198 did for the Kafka client version. Without that written down, the next
agent either leaves a false statement standing or believes #198 broke the
rule.

Corrects the claim that the changelog-ref gate "should never fire, since PRs no
longer touch the file". Four open PRs modify CHANGELOG.adoc, and the gate only
rejects entries citing no issue - so #57's cited entries pass it while
still violating the policy. It is neither a subset nor a superset of the rule.
Deliberately NOT tightened to reject every addition: "adds" and "corrects" are
both `+*` lines and are not mechanically distinguishable - the gate's own header
records that fuzzy-matching removed against added bullets was built and then
abandoned - and a blanket rule's only escape hatch legitimises a violating
addition exactly as easily as a legitimate correction.

Adds case 13 to the review gate's self-test: a match followed by >64 KiB of
comments must still pass. The SIGPIPE fix itself landed in #211; this case
is behavioural where that guard is static, so it catches a regression arriving by
some route other than a literal `| grep -q`.

References qualified as astubbs#NN per the gate added in #114, which
merged after this branch was written.

Co-authored-by: Claude Opus 5 (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