Skip to content

ci(review): let the PR reviewer verify claims instead of trusting them - #102

Merged
astubbs merged 6 commits into
masterfrom
ci/let-review-agent-run-tests
Aug 3, 2026
Merged

ci(review): let the PR reviewer verify claims instead of trusting them#102
astubbs merged 6 commits into
masterfrom
ci/let-review-agent-run-tests

Conversation

@astubbs

@astubbs astubbs commented Aug 1, 2026

Copy link
Copy Markdown
Owner

Description

The automated PR reviewer could never check a test claim — it can now run the suites itself, and its blocking findings now actually gate the merge.

This workflow triggers on pull_request (opened/synchronize), which fires before the CI test jobs finish. So "read the CI results" was never available to the reviewer, and with no execution grants it could only restate whatever the author's PR description asserted.

That is not hypothetical. On #100 the reviewer said as much in its own review:

I could not run the build/test suite myself in this sandbox (./mvnw requires interactive approval I don't have here) — the verification table in the PR description (622 tests passing, specific chaos seed reproduction) is asserted by the author but not independently re-run by me.

And it mattered: that PR added a regression test named MockConsumerTestWithRebalanceInProgressException, which matches none of surefire's default include patterns. The suite was green because the new test never ran. A review that trusted the author's totals would have waved through a permanent no-op. Running the suite — and checking which tests ran — is the only thing that catches that class of bug.

What changed

Execution

  • Grants the repo's own wrappersbin/ci-unit-test.sh, bin/ci-integration-test.sh — rather than blanket Bash(./mvnw:*): the wrappers pin the ci profile and the group exclusions, so the reviewer runs what CI runs instead of some variant of it.
  • Grants the fast read-only verification scriptsbin/check-copyright-headers.sh, bin/test-check-copyright-headers.sh, bin/check-quarantine-registry.sh, bin/check-quarantine-owners.sh — so the reviewer can re-run what a PR claims rather than inferring it from the diff.
  • Adds JDK 17 + Maven cache, and fetch-depth: 0. Without these the grants would be useless — the job had no JDK at all, so every invocation would have failed outright or spent its budget re-downloading dependencies, and fetch-depth: 1 cannot reach the PR base to diff against.
  • Appends a system prompt telling the reviewer it may execute tests, that CI results are not available to it, that when a PR adds a test it must verify the suite actually collected it rather than trusting a green total, and that it should say plainly when it could not verify something instead of implying it did.

Blocking findings now gate the merge

  • The master ruleset sets required_review_thread_resolution, so an unresolved review thread is the only thing that actually gates a merge. A blocking finding written only in a PR-level summary comment can be — and would be — merged straight past.
  • Blocking findings (correctness bugs, data loss/corruption, security holes, broken public contracts, a test that cannot do what it claims) now go through create_inline_comment, one thread per finding.
  • Non-blocking notes stay in the summary. If every nit became a resolvable thread you would clear a dozen to land a docs change, and the gate would stop meaning "something is actually wrong" — gates that are routinely dismissed get dismissed when it matters. There is an explicit tie-breaker: if unsure, summarise and say why, rather than block on a maybe.
  • Requires pull-requests: write (was read). It may be unnecessary — the summary comment posts fine under read, suggesting the action uses its own app token — but a silently failing inline comment would mean a blocking finding never gates the merge. The rationale sits beside the permission; drop it back if it proves redundant.

Bounds

  • Caps the job at 30 minutes, so a wedged suite cannot hold a runner indefinitely.
  • Chaos is deliberately not granted — Docker, ~2 minutes per scenario arm, far too slow for a per-PR pass, and non-gating anyway. Nor are the quarantine/test runners; test execution is already covered by the ci-*-test.sh wrappers.
  • Deliberately an enumerable allowlist, not blanket Bash(*). This job has no fork guard beyond sender.type != Bot — fork PRs are protected only by not receiving secrets, so the action fails rather than runs — and the reviewer reads attacker-influencable text (diff, PR body, comments). The allowlist is the margin against injection becoming execution.

Two defects the reviewer caught in its own review

Both fixed here, and both worth recording since this PR's thesis is "don't let assertions go unverified":

  1. A grant for bin/todo-index.sh — a script that exists only on unmerged docs: index every TODO/FIXME/XXX marker, triage into the existing refactoring backlog #103, so on this branch the grant was inert while the changelog advertised it as shipped. Dropped; it belongs in docs: index every TODO/FIXME/XXX marker, triage into the existing refactoring backlog #103 alongside the script. The workflow now carries a standing rule: every grant must be a script that exists on THIS branch.
  2. A bespoke ./mvnw --batch-mode -Pci -pl parallel-consumer-core test grant that contradicted the comment directly above it, skipping the -Dexcluded.groups=performance,chaos,quarantined the wrappers hardcode. That exclusion was once a silent no-op for unit tests — a real P1 — and QuarantinedAnnotationContractTest pins it for the wrapper scripts but cannot pin a command embedded in a workflow string. Removed.

Known limitation — this PR cannot verify itself

claude-code-action refuses to run when the workflow file differs from the copy on the default branch ("Workflow validation failed … must have identical content to the version on the repository's default branch") and reports that skip as success.

That is a deliberate and correct control — it stops a PR rewriting the reviewer's own grants and having that version execute — but it means:

  • none of this has actually executed: not the grants, not the JDK/cache setup, not the inline-comment behaviour;
  • this PR's own green review check verified nothing, and a silent skip is indistinguishable from a clean pass;
  • the first real exercise is whatever PR merges after this one. The bot reviews on this PR came via manual @claude mentions, which run a different, unmodified workflow.

Open follow-ups are recorded in docs/inflight.md under CI reliability / gate issues: whether CLAUDE_CODE_OAUTH_TOKEN is reachable from a Bash subprocess running PR-authored build code (unresolved either way, and pull-requests: write widened the blast radius); that actionlint is not granted, so the reviewer cannot lint the very artefact this PR changes; and whether bin/ci-integration-test.sh fits the 30-minute cap.

Notes

Checklist

  • Changelog entry added (CHANGELOG.adoc) - under == Unreleased → Build & CI, citing this PR; README.adoc regenerated from it
  • Docs updated - docs/inflight.md gains the open review-agent follow-ups under CI reliability / gate issues; the workflow's own inline comments carry the per-decision rationale
  • Tests added/updated - N/A - CI workflow configuration; validated with actionlint, and see the known limitation above: the behaviour itself cannot be exercised until after merge
  • Title & body reflect the final content of this PR
  • Self-hosted runner / security implications considered - runs on ubuntu-latest (GitHub-hosted, not the self-hosted box). Grants are six repo-owned scripts rather than arbitrary Maven or shell, and the job is time-capped. pull-requests: write is added for inline comments. The unresolved credential-exposure question (PR-authored build code running alongside the OAuth token) is recorded in docs/inflight.md rather than claimed as handled.

🤖 Generated with Claude Code

… author

The review workflow fires on pull_request open/synchronize - BEFORE the
CI test jobs finish - so 'just read the CI results' was never available
to it. With no execution grants it could only restate whatever the
author's PR description claimed.

PR #100 is the cautionary case: a regression test was named
MockConsumerTestWithRebalanceInProgressException, which matches none of
surefire's default include patterns, so it was never collected. The
suite was green precisely because the new test never ran, and a review
that read the author's '622 tests passing' table would have waved it
through. Only running the suite - and checking WHICH tests ran - catches
that.

- grants bin/ci-unit-test.sh and bin/ci-integration-test.sh (the repo's
  own wrappers, so the reviewer runs what CI runs, with the same group
  exclusions and profile) rather than blanket Bash(./mvnw:*)
- adds JDK 17 + Maven cache, without which any invocation would fail or
  burn its budget re-downloading dependencies
- fetch-depth 0, since comparing against the PR base needs history
- appends a system prompt telling the reviewer it MAY execute tests, that
  CI results are not available to it, to verify a new test was actually
  collected, and to say so plainly if it could not verify rather than
  implying it did
- caps the job at 30 minutes so a wedged suite cannot hold a runner

Chaos is deliberately NOT granted: it needs Docker and takes ~2 minutes
per scenario arm, far too slow for a per-PR review, and it is non-gating.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QqHpNSXC39ANv9kG1ZvUzn
@github-actions

github-actions Bot commented Aug 1, 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/claude-code-review.yml

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

OpenSSF Scorecard

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

Scanned Files

  • .github/workflows/claude-code-review.yml

Per AGENTS.md's reference convention ('link the PR/issue'). Added at
PR-creation time, since the entry necessarily predates the number.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QqHpNSXC39ANv9kG1ZvUzn
@github-actions

github-actions Bot commented Aug 1, 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 33 33 ➖ 0
Duplicated lines 995 995 ➖ 0
Duplication 3.02% 3.02% ➖ 0
Rule Limit Status
Max duplication 5% ✅ Pass (3.02%)
Max increase vs base +0.1% ✅ Pass (+0.00%)

No new clones introduced by this PR.

✅ jscpd (language-agnostic)

PR Base Change
Clones 82 82 ➖ 0
Duplicated lines 1175 1175 ➖ 0
Duplication 3.60% 3.60% ➖ 0
Rule Limit Status
Max duplication 5% ✅ Pass (3.60%)
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 1, 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.08
parallel-consumer-core/src/test/java/io/confluent/csid/utils/CollectionUtils.java 33.0
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.27
parallel-consumer-core/src/main/java/io/confluent/csid/utils/Java8StreamUtils.java 35.08
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.35 ⚠️
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/internal/InternalException.java 40.95
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/EncodingNotSupportedException.java 37.54
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/PCRetriableException.java 37.35
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/RunLengthV1EncodingNotSupported.java 35.81
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/RunLengthV2EncodingNotSupported.java 35.81
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/BitSetEncodingNotSupportedException.java 35.68
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/OffsetDecodingError.java 34.8
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/NoEncodingPossibleException.java 30.41
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.33 ⚠️
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/ParallelEoSStreamProcessor.java 54.18 ⚠️
parallel-consumer-vertx/src/main/java/io/confluent/parallelconsumer/vertx/JStreamVertxParallelEoSStreamProcessor.java 40.06
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/ParallelStreamProcessor.java 36.48
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/PollContextInternal.java 32.16
parallel-consumer-vertx/src/main/java/io/confluent/parallelconsumer/vertx/JStreamVertxParallelStreamProcessor.java 31.13
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.33 ⚠️
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/ParallelEoSStreamProcessor.java 50.0 ⚠️
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/ParallelStreamProcessor.java 36.16
parallel-consumer-vertx/src/main/java/io/confluent/parallelconsumer/vertx/JStreamVertxParallelEoSStreamProcessor.java 32.01
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/PollContextInternal.java 31.11
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 37.35
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/internal/InternalException.java 33.39
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.35 ⚠️
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/internal/InternalException.java 53.99 ⚠️
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/EncodingNotSupportedException.java 45.33
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/BitSetEncodingNotSupportedException.java 35.47
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/OffsetDecodingError.java 34.38
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/RunLengthV1EncodingNotSupported.java 31.59
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/RunLengthV2EncodingNotSupported.java 31.59
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/internal/InternalRuntimeException.java 30.78
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/NoEncodingPossibleException.java 30.42
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.84
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/state/PartitionState.java 31.03
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.18 ⚠️
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/JStreamParallelStreamProcessor.java 50.0 ⚠️
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/ParallelStreamProcessor.java 45.05
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/PollContextInternal.java 33.51
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/internal/AbstractParallelEoSStreamProcessor.java 32.79
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/internal/TestParallelEoSStreamProcessor.java 30.6
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.05
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/JStreamParallelEoSStreamProcessor.java 36.48
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/JStreamParallelStreamProcessor.java 36.16
parallel-consumer-vertx/src/main/java/io/confluent/parallelconsumer/vertx/JStreamVertxParallelStreamProcessor.java 32.2
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.65
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.51
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/PollContext.java 32.65
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/RecordContextInternal.java 32.58
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/JStreamParallelEoSStreamProcessor.java 32.16
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/JStreamParallelStreamProcessor.java 31.11
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 32.58
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 32.94
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/ParallelEoSStreamProcessor.java 32.79
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 32.94
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.55
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.7 ⚠️
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/ParallelConsumerException.java 53.99 ⚠️
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/OffsetDecodingError.java 51.38 ⚠️
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/NoEncodingPossibleException.java 48.8
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/ExceptionInUserFunctionException.java 40.95
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/internal/InternalRuntimeException.java 39.15
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/BitSetEncodingNotSupportedException.java 37.71
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/RunLengthV1EncodingNotSupported.java 34.47
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/RunLengthV2EncodingNotSupported.java 34.47
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/PCRetriableException.java 33.39
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.15
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/EncodingNotSupportedException.java 31.3
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/ParallelConsumerException.java 30.78
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.79
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.84
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 52.05 ⚠️
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/RunLengthV1EncodingNotSupported.java 38.07
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/RunLengthV2EncodingNotSupported.java 38.07
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/internal/InternalException.java 37.71
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/ExceptionInUserFunctionException.java 35.68
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/ParallelConsumerException.java 35.47
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/OffsetDecodingError.java 33.58
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/NoEncodingPossibleException.java 30.14
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.7 ⚠️
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/BitSetEncodingNotSupportedException.java 52.05 ⚠️
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/OffsetDecodingError.java 49.02
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/RunLengthV1EncodingNotSupported.java 47.75
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/RunLengthV2EncodingNotSupported.java 47.75
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/NoEncodingPossibleException.java 46.99
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/ParallelConsumerException.java 45.33
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/ExceptionInUserFunctionException.java 37.54
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/internal/InternalRuntimeException.java 31.3
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.8
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/EncodingNotSupportedException.java 46.99
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/OffsetDecodingError.java 45.68
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/RunLengthV1EncodingNotSupported.java 38.95
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/RunLengthV2EncodingNotSupported.java 38.95
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/ParallelConsumerException.java 30.42
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/ExceptionInUserFunctionException.java 30.41
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/BitSetEncodingNotSupportedException.java 30.14
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/OffsetDecodingError.java

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

File Similarity (%)
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/internal/InternalException.java 51.38 ⚠️
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/EncodingNotSupportedException.java 49.02
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/NoEncodingPossibleException.java 45.68
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/ExceptionInUserFunctionException.java 34.8
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/ParallelConsumerException.java 34.38
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/BitSetEncodingNotSupportedException.java 33.58
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/RunLengthV1EncodingNotSupported.java 32.45
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/RunLengthV2EncodingNotSupported.java 32.45
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 64.07 ⚠️
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/EncodingNotSupportedException.java 47.75
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/NoEncodingPossibleException.java 38.95
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/BitSetEncodingNotSupportedException.java 38.07
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/ExceptionInUserFunctionException.java 35.81
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/internal/InternalException.java 34.47
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/OffsetDecodingError.java 32.45
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/ParallelConsumerException.java 31.59
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 64.07 ⚠️
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/EncodingNotSupportedException.java 47.75
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/NoEncodingPossibleException.java 38.95
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/BitSetEncodingNotSupportedException.java 38.07
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/ExceptionInUserFunctionException.java 35.81
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/internal/InternalException.java 34.47
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/offsets/OffsetDecodingError.java 32.45
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/ParallelConsumerException.java 31.59
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/ParallelConsumerOptions.java 31.03
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/state/PartitionStateManager.java 30.76
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 41.9
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/state/PartitionState.java 30.76
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 38.34
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 38.34
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 41.9
parallel-consumer-core/src/test-integration/java/io/confluent/parallelconsumer/integrationTests/AmbientProbeExtension.java

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

File Similarity (%)
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/AmbientProbeExtensionTest.java 30.34
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 33.93
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.39 ⚠️
parallel-consumer-core/src/test-integration/java/io/confluent/parallelconsumer/integrationTests/TransactionAndCommitModeTest.java 46.89
parallel-consumer-core/src/test-integration/java/io/confluent/parallelconsumer/integrationTests/MultiInstanceRebalanceTest.java 38.66
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.19
parallel-consumer-core/src/test-integration/java/io/confluent/parallelconsumer/integrationTests/TransactionAndCommitModeTest.java 41.04
parallel-consumer-core/src/test-integration/java/io/confluent/parallelconsumer/integrationTests/MultiInstanceHighVolumeTest.java 38.66
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.76
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.76
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.71 ⚠️
parallel-consumer-core/src/test-integration/java/io/confluent/parallelconsumer/integrationTests/MultiInstanceHighVolumeTest.java 46.89
parallel-consumer-core/src/test-integration/java/io/confluent/parallelconsumer/integrationTests/MultiInstanceRebalanceTest.java 41.04
parallel-consumer-vertx/src/test-integration/java/io/confluent/parallelconsumer/vertx/integrationTests/VertxConcurrencyIT.java 30.14
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.71 ⚠️
parallel-consumer-core/src/test-integration/java/io/confluent/parallelconsumer/integrationTests/MultiInstanceHighVolumeTest.java 55.39 ⚠️
parallel-consumer-core/src/test-integration/java/io/confluent/parallelconsumer/integrationTests/MultiInstanceRebalanceTest.java 44.19
parallel-consumer-vertx/src/test-integration/java/io/confluent/parallelconsumer/vertx/integrationTests/VertxConcurrencyIT.java 39.4
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.59
parallel-consumer-core/src/test-integration/java/io/confluent/parallelconsumer/integrationTests/chaostests/ChaosRevokeUnderWorkIT.java 35.36
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.59
parallel-consumer-core/src/test-integration/java/io/confluent/parallelconsumer/integrationTests/chaostests/ChaosScenarioBase.java 37.67
parallel-consumer-core/src/test-integration/java/io/confluent/parallelconsumer/integrationTests/chaostests/ChaosRevokeUnderWorkIT.java 32.57
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 50.85 ⚠️
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 50.85 ⚠️
parallel-consumer-core/src/test-integration/java/io/confluent/parallelconsumer/integrationTests/chaostests/AbstractRevokeUnderWorkScenario.java 35.36
parallel-consumer-core/src/test-integration/java/io/confluent/parallelconsumer/integrationTests/chaostests/ChaosChurnStormIT.java 32.57
parallel-consumer-core/src/test-integration/java/io/confluent/parallelconsumer/integrationTests/chaostests/ProgressProbe.java 30.24
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 37.67
parallel-consumer-core/src/test-integration/java/io/confluent/parallelconsumer/integrationTests/chaostests/ProgressProbe.java

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

File Similarity (%)
parallel-consumer-core/src/test-integration/java/io/confluent/parallelconsumer/integrationTests/chaostests/ChaosRevokeUnderWorkIT.java 30.24
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.27
parallel-consumer-core/src/main/java/io/confluent/csid/utils/Java8StreamUtils.java 33.0
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 33.93
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/AmbientProbeExtensionTest.java

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

File Similarity (%)
parallel-consumer-core/src/test-integration/java/io/confluent/parallelconsumer/integrationTests/AmbientProbeExtension.java 30.34
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.35
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.47
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/QuarantineRegistryScriptTest.java 43.97
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 51.98 ⚠️
parallel-consumer-mutiny/src/test/java/io/confluent/parallelconsumer/mutiny/MutinyBatchTest.java 50.67 ⚠️
parallel-consumer-vertx/src/test/java/io/confluent/parallelconsumer/vertx/VertxBatchTest.java 44.79
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/BatchTestBase.java 30.35
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/MockConsumerTestWithCommitTimeoutException.java 56.71 ⚠️
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/MockConsumerTestWithEarlyClose.java 55.75 ⚠️
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/MockConsumerTestWithSaslAuthenticationException.java 47.41
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/MockConsumerTestWithCommitTimeoutException.java

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

File Similarity (%)
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/MockConsumerTestWithEarlyClose.java 70.38 ⚠️
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/MockConsumerTest.java 56.71 ⚠️
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/MockConsumerTestWithSaslAuthenticationException.java 49.74
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/MockConsumerTestWithEarlyClose.java

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

File Similarity (%)
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/MockConsumerTestWithCommitTimeoutException.java 70.38 ⚠️
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/MockConsumerTest.java 55.75 ⚠️
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/MockConsumerTestWithSaslAuthenticationException.java 52.98 ⚠️
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/MockConsumerTestWithSaslAuthenticationException.java

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

File Similarity (%)
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/MockConsumerTestWithEarlyClose.java 52.98 ⚠️
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/MockConsumerTestWithCommitTimeoutException.java 49.74
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/MockConsumerTest.java 47.41
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.49
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.49
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.47
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/QuarantineRegistryScriptTest.java 33.39
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.97
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/QuarantineLaneReportScriptTest.java 33.39
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.38 ⚠️
parallel-consumer-mutiny/src/test/java/io/confluent/parallelconsumer/mutiny/TestConventionsArchTest.java 89.72 ⚠️
parallel-consumer-reactor/src/test/java/io/confluent/parallelconsumer/reactor/TestConventionsArchTest.java 89.72 ⚠️
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.09
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.09
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.79
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 30.6
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.17
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.17
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.55
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.55
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.51 ⚠️
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 79.15 ⚠️
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/CoreBatchTest.java 50.67 ⚠️
parallel-consumer-vertx/src/test/java/io/confluent/parallelconsumer/vertx/VertxBatchTest.java 49.46
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 69.61 ⚠️
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 34.11
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 33.03
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.22 ⚠️
parallel-consumer-reactor/src/test/java/io/confluent/parallelconsumer/reactor/TestConventionsArchTest.java 90.55 ⚠️
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/TestConventionsArchTest.java 89.72 ⚠️
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.51 ⚠️
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 79.15 ⚠️
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/CoreBatchTest.java 51.98 ⚠️
parallel-consumer-vertx/src/test/java/io/confluent/parallelconsumer/vertx/VertxBatchTest.java 50.72 ⚠️
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 69.61 ⚠️
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 34.11
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 33.03
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.22 ⚠️
parallel-consumer-mutiny/src/test/java/io/confluent/parallelconsumer/mutiny/TestConventionsArchTest.java 90.55 ⚠️
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/TestConventionsArchTest.java 89.72 ⚠️
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.5
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/JStreamParallelEoSStreamProcessor.java 40.06
parallel-consumer-vertx/src/main/java/io/confluent/parallelconsumer/vertx/JStreamVertxParallelStreamProcessor.java 39.7
parallel-consumer-vertx/src/main/java/io/confluent/parallelconsumer/vertx/VertxParallelStreamProcessor.java 35.07
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/JStreamParallelStreamProcessor.java 32.01
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.7
parallel-consumer-vertx/src/main/java/io/confluent/parallelconsumer/vertx/VertxParallelStreamProcessor.java 38.86
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/ParallelStreamProcessor.java 32.2
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/JStreamParallelEoSStreamProcessor.java 31.13
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/JStreamVertxParallelEoSStreamProcessor.java 41.5
parallel-consumer-vertx/src/main/java/io/confluent/parallelconsumer/vertx/VertxParallelStreamProcessor.java 41.46
parallel-consumer-core/src/main/java/io/confluent/parallelconsumer/internal/ExternalEngine.java 39.55
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.46
parallel-consumer-vertx/src/main/java/io/confluent/parallelconsumer/vertx/JStreamVertxParallelStreamProcessor.java 38.86
parallel-consumer-vertx/src/main/java/io/confluent/parallelconsumer/vertx/JStreamVertxParallelEoSStreamProcessor.java 35.07
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.4
parallel-consumer-core/src/test-integration/java/io/confluent/parallelconsumer/integrationTests/TransactionAndCommitModeTest.java 30.14
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.22 ⚠️
parallel-consumer-reactor/src/test/java/io/confluent/parallelconsumer/reactor/TestConventionsArchTest.java 91.22 ⚠️
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/TestConventionsArchTest.java 90.38 ⚠️
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.72 ⚠️
parallel-consumer-mutiny/src/test/java/io/confluent/parallelconsumer/mutiny/MutinyBatchTest.java 49.46
parallel-consumer-core/src/test/java/io/confluent/parallelconsumer/CoreBatchTest.java 44.79

@github-actions

github-actions Bot commented Aug 1, 2026

Copy link
Copy Markdown

✅ SpotBugs Report

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

@github-actions

github-actions Bot commented Aug 1, 2026

Copy link
Copy Markdown

🧪🔒 Quarantine Lane Report

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

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

@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.

Needs looking in to

Comment thread .github/workflows/claude-code-review.yml
@astubbs

astubbs commented Aug 3, 2026

Copy link
Copy Markdown
Owner Author

@claude please review

@claude

claude Bot commented Aug 3, 2026

Copy link
Copy Markdown

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


Review: ci(review): let the PR reviewer run the tests instead of trusting the author

  • Gather context (read diff, changed files, CLAUDE.md)
  • Understand the request (code review)
  • Review .github/workflows/claude-code-review.yml changes
  • Review CHANGELOG.adoc / README.adoc changes
  • Post review feedback

Solid change overall — the JDK/cache setup, fetch-depth: 0, and 30-minute cap are all correctly motivated by the new test-execution grant, and the rationale (PR #100's uncollected test) is a real, well-documented justification. Two things worth addressing before merge:

1. Undocumented third allowedTools grant bypasses the exact hardening the wrappers exist for

.github/workflows/claude-code-review.yml:74 grants three things, but the PR description only mentions two:

Bash(bin/ci-unit-test.sh:*),Bash(bin/ci-integration-test.sh:*),Bash(./mvnw --batch-mode -Pci -pl parallel-consumer-core test:*)

The third grant (./mvnw ... -pl parallel-consumer-core test) isn't in the PR body, isn't in the inline comment above it ("Deliberately the repo's own wrappers rather than blanket Bash(./mvnw:*)"), and undercuts that stated design goal:

  • It skips -Dexcluded.groups=performance,chaos,quarantined, relying instead on the pom default. bin/ci-unit-test.sh/bin/ci-integration-test.sh hardcode that flag specifically because of a past bug (see QuarantinedAnnotationContractTest.bothSurefireAndFailsafeBindTheGroupProperties / gatingCiScriptsExcludeTheQuarantinedGroup's comment: "a real ce-review P1: only failsafe was wired, so the exclusion was a silent no-op for every UNIT test"). That contract test only pins bin/ci-unit-test.sh, bin/ci-integration-test.sh, and bin/ci-build.sh — this workflow-embedded command isn't covered, so if that binding regresses again, nothing catches it here.
  • It's scoped to -pl parallel-consumer-core only, so it's useless for PRs touching parallel-consumer-vertx/-mutiny/-reactor.
  • It drops clean and the wrappers' -Dlicense.skip / -Dsurefire.rerunFailingTestsCount=2, so it can reuse stale target/ output and is more flake-prone.

If this grant is intentional (e.g. a fast single-module smoke check), it needs its own explanation in the PR description/comment and ideally its own contract-test coverage. If it's leftover from iterating on the allowedTools string, it should be dropped so the reviewer only ever runs what the two vetted wrapper scripts run.

Fix this →

2. Security checklist doesn't cover the credential-exposure angle of executing PR-authored code

The PR's "security implications considered" note addresses the self-hosted-runner question and script scope, but there's a different risk this grant introduces: the review job now executes the PR's own test/build code (arbitrary Java, plus whatever Maven plugins run under -Pci) from inside the same process that holds secrets.CLAUDE_CODE_OAUTH_TOKEN (passed to claude-code-action to authenticate to the Claude API). If that token is present in the process environment (typical for how the CLI authenticates) and the Bash tool's subprocess inherits it (the normal OS default unless the action explicitly scrubs it), a malicious test or build plugin in the PR could exfiltrate it over the network — GitHub-hosted runners have outbound internet access by default. Worth confirming with the claude-code-action maintainers/docs whether the OAuth token is scrubbed from the environment before Bash tool subprocesses are spawned; if not, consider running review-triggered test execution in a step/credential scope that doesn't have that token available. (Note: this is somewhat mitigated for genuine fork PRs, since GitHub withholds repository secrets from pull_request-triggered runs originating from forks — but it applies fully to same-repo PRs from any contributor with push access, including a compromised account or a malicious dependency-bump PR.)

Minor / non-blocking

  • astubbs's earlier review thread asks whether the reviewer could post findings as inline review comments (required-to-resolve) instead of one large PR comment — worth noting mcp__github_inline_comment__create_inline_comment is already granted (pre-existing, not new in this PR), so the plugin may already support this; that thread looks unresolved and is separate from this diff.
  • bin/ci-integration-test.sh needs Docker — ubuntu-latest ships Docker Engine pre-installed, so this should work without extra setup, but it's worth a first real run to confirm TestContainers behaves inside this specific action's sandboxing.

Everything else — the timeout-minutes: 30, fetch-depth: 0 for base-branch diffing, the JDK/Maven cache setup, and the system-prompt wording around verifying test collection rather than trusting totals — looks correct and directly addresses the #100 failure mode.

Review feedback on #102: a finding that should block the merge has to be
an inline review comment, because the master ruleset sets
required_review_thread_resolution - an unresolved thread is the ONLY
thing that actually gates a merge here.

As written, this workflow had the reviewer post a single PR-level
summary comment, which nothing forces anyone to resolve. A genuine
blocking finding could be merged straight past. The inline-comment tool
was already granted; the agent was never told when to use it.

The system prompt now requires blocking findings (correctness bugs, data
loss or corruption, security holes, broken public contracts, or a test
that cannot do what it claims) to go inline via create_inline_comment,
one thread per finding, and explains WHY - so the instruction survives a
model that reasons rather than pattern-matches.

Deliberately NOT converting the whole review to inline threads: every
routine nit would then be merge-blocking, you would resolve a dozen
threads to land a docs change, and the gate would stop meaning
'something is actually wrong'. Gates that are routinely dismissed get
dismissed when it matters. Scarcity is what keeps them meaningful. There
is an explicit tie-breaker for the ambiguous case: if unsure, summarise
and say why, rather than blocking on a maybe.

Also bumps to pull-requests: write, since creating inline comments
writes to the PR. It may be unnecessary - the summary comment posts fine
under read, suggesting the action uses its own app token - but a
silently failing inline comment would mean a blocking finding never
gates the merge, which defeats the purpose. Rationale is in a comment
beside the permission; drop it back if redundant.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QqHpNSXC39ANv9kG1ZvUzn
A #103 reviewer could not run bin/todo-index.sh --check to confirm the
generated index was regenerated - it had the test wrappers granted but
not the repo's own verification scripts - so it had to infer freshness
from the diff. That is the exact 'author asserts vs actually verified'
gap this whole workstream is about.

Grants the fast, read-only VERIFICATION scripts: bin/check-copyright-
headers.sh, bin/test-check-copyright-headers.sh, bin/check-quarantine-
registry.sh, bin/check-quarantine-owners.sh, bin/todo-index.sh. All are
executable with shebangs, so the bare-path grant matches the existing
ci-*-test.sh convention. The system prompt now tells the reviewer they
exist and to prefer them over trusting the PR body.

NOT the quarantine/test RUNNERS (quarantined-test.sh,
quarantine-lane-report.sh): those execute suites, are slow, and test
execution is already covered by the ci-*-test.sh wrappers.

Deliberately still an allowlist, not blanket Bash(*): this job has no
fork guard beyond sender.type != Bot - fork PRs are currently protected
only by not receiving secrets, so the action fails rather than runs -
and it reads attacker-influencable text (diff, PR body, comments). An
enumerable allowlist is the margin against injection-into-execution;
blanket shell here plus the pull-requests: write added for inline
comments would be a pwn-request waiting for a trigger change. Reasoning
recorded in the workflow comment.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QqHpNSXC39ANv9kG1ZvUzn
@astubbs

astubbs commented Aug 3, 2026

Copy link
Copy Markdown
Owner Author

@claude please review again, paying special attention to the changes since last review

@claude

claude Bot commented Aug 3, 2026

Copy link
Copy Markdown

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


Review: ci(review): let the PR reviewer run the tests instead of trusting the author — re-review

  • Gather context (read diff, changed files, CLAUDE.md)
  • Understand the request (re-review focused on changes since last review)
  • Diff what changed since the previous review (commits d9f629d, d39763d)
  • Verify finding Create codeql-analysis.yml #1 (undocumented third allowedTools grant) was actually fixed
  • Verify finding Java 17 #2 (inline-comment mechanism for blocking findings) was implemented soundly
  • Check pull-requests: write permission bump and any other new risk surface
  • Post final review feedback

Two commits landed since the last review: d9f629d (inline review comments for blocking findings) and d39763d (grants the repo's fast verification scripts). One is solid, one has a real bug, and both of my previous findings are still open.

1. bin/todo-index.sh does not exist — the new grant and its instruction are a dead end (new, this round)

d39763d grants Bash(bin/todo-index.sh:*) and tells the reviewer (.github/workflows/claude-code-review.yml:93) to run bin/todo-index.sh --check "to confirm a generated index was actually regenerated." I checked:

$ ls bin/todo-index.sh
ls: cannot access 'bin/todo-index.sh': No such file or directory
$ find . -iname "*todo-index*"
(nothing)
$ git log --all --diff-filter=A --name-only | grep -i todo-index
(nothing)

The script has never existed anywhere in this repository's history, under any name. The commit message frames this as fixing a gap found by "a #103 reviewer" — that scenario doesn't correspond to anything in this repo. The claim has also propagated into CHANGELOG.adoc:29 and README.adoc:1600 ("bin/todo-index.sh --check") as a real, shipped capability.

Practically this is low-severity — the grant is inert and the reviewer will just get "No such file or directory" if it ever tries to act on the instruction, it won't break anything else. But it's a real, verifiable defect, and given this entire PR's thesis is "don't let assertions go unverified," landing an unverified, false claim into the changelog in the same PR is the exact failure mode this workstream exists to catch. Worth fixing before merge: either the script needs to be added, or the grant/prompt-line/changelog wording needs to be dropped.

Fix this →

2. Previous finding #1 (undocumented third allowedTools grant) — still unresolved

Neither commit touched this. .github/workflows/claude-code-review.yml:92 still grants Bash(./mvnw --batch-mode -Pci -pl parallel-consumer-core test:*) alongside the two wrapper scripts. The inline comment above it (now expanded, lines 74–77) says even more emphatically: "Deliberately the repo's own wrappers rather than blanket Bash(./mvnw:*): the wrappers pin the group exclusions and CI profile, so the reviewer runs what CI runs." — but the actual grant list still contains a third, bespoke mvnw invocation that is neither a wrapper nor documented, still skips -Dexcluded.groups=performance,chaos,quarantined, and is still scoped only to parallel-consumer-core. The comment and the code it sits above still say two different things.

3. Previous finding #2 (credential exposure from executing PR-authored code) — not addressed

No commit since the last review touches this. Worth noting the risk surface moved slightly: d9f629d added pull-requests: write (previously read), so a token exfiltrated from the job's environment while running PR-authored test/build code is now also write-capable on PRs. The d39763d commit message shows clear awareness of pwn-request-style risk in general ("blanket shell here plus the pull-requests: write added for inline comments would be a pwn-request waiting for a trigger change") but that reasoning is about tool-grant scope, not about whether the OAuth token itself is reachable from a Bash subprocess spawned while running the PR's own Maven/test code. Still worth a one-line confirmation from the claude-code-action docs/maintainers.

What's good about the two new commits

  • d9f629d (inline review comments) is a well-reasoned, correctly-scoped fix for the exact gap astubbs's review thread raised: blocking findings now go through create_inline_comment (already-granted tool, just never instructed), non-blocking stays in the summary, and there's an explicit tie-breaker for the ambiguous case ("if unsure, summarize and say why"). The pull-requests: write bump is justified and the comment next to it explains the tradeoff and says to revert it if it proves unnecessary — good practice.
  • The other four scripts granted by d39763d (check-copyright-headers.sh, test-check-copyright-headers.sh, check-quarantine-registry.sh, check-quarantine-owners.sh) all exist, are executable, and are legitimately fast/read-only — those grants are fine.
  • timeout-minutes: 30, fetch-depth: 0, and the JDK/Maven cache setup from the original PR are unchanged and still correct.

Recommendation

Fix or drop the bin/todo-index.sh grant/prompt/changelog wording (#1) before merge — it's a concrete, checkable bug in a PR about checking claims. #2 and #3 are carried over from the previous review and still worth resolving, though lower urgency.

Both findings were correct.

1. Bash(bin/todo-index.sh:*) referenced a script that does not exist on
   this branch. It is added by #103 (docs/todo-index), which is not
   merged, so from here the grant is inert and the prompt instruction
   and changelog line claimed a capability that does not exist. The
   reviewer was right to check with find/git log rather than take the
   commit message's word for it; it was wrong only about the script
   never existing anywhere, since it lives on the unmerged #103 branch.

   Landing an unverified claim in a PR whose whole thesis is 'do not let
   assertions go unverified' is exactly the failure this workstream
   exists to catch. Dropped from the grant list, the system prompt, and
   the changelog; the grant belongs in #103 alongside the script.

2. Bash(./mvnw --batch-mode -Pci -pl parallel-consumer-core test:*)
   contradicted the comment sitting directly above it, which says the
   reviewer runs the repo's wrappers so it runs what CI runs. That
   bespoke invocation skipped -Dexcluded.groups=performance,chaos,
   quarantined - which the wrappers hardcode because it was once a
   silent no-op for unit tests, a real P1, now pinned by
   QuarantinedAnnotationContractTest for the wrappers but NOT for a
   workflow-embedded command - was core-only, and dropped clean,
   -Dlicense.skip and rerunFailingTestsCount. Removed: if the reviewer
   runs tests, it runs what CI runs.

Adds a comment recording both rules, so the next person does not
reintroduce either: every grant must be a script that exists on THIS
branch, and there is deliberately no bespoke mvnw grant.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QqHpNSXC39ANv9kG1ZvUzn
@astubbs

astubbs commented Aug 3, 2026

Copy link
Copy Markdown
Owner Author

Both findings were correct and are fixed in the latest push. Thank you for checking with find/git log rather than taking my commit message's word for it — that is exactly the behaviour this PR is trying to install.

1. bin/todo-index.sh — right that it's absent here, one correction on provenance

It exists, but on an unmerged branch: #103 (docs/todo-index), which adds bin/todo-index.sh along with docs/TODO_INDEX.md. So it isn't in this branch's tree or on master, and git log --all on a checkout that lacks that ref won't see it — your conclusion "not here, grant is inert" was right; only "never existed anywhere in this repository's history" was off, and that's a fetch-scope artifact rather than a reasoning error.

That doesn't rescue the grant, though. I granted a script from a different, unmerged branch — so on this branch it was inert, and the prompt instruction plus the CHANGELOG.adoc/README.adoc lines advertised a capability that does not exist. Shipping an unverified claim inside the PR whose entire thesis is "don't let assertions go unverified" is precisely the failure mode this workstream exists to catch, and you caught it.

Fixed: grant, system-prompt sentence, and changelog wording all dropped; README.adoc regenerated. The grant belongs in #103, next to the script it depends on, where it can actually be exercised.

I also added a rule to the workflow comment so this can't recur: every grant here must be a script that EXISTS ON THIS BRANCH, with this incident named as the reason.

2. The bespoke mvnw grant — agreed, removed

You were right that the comment and the code disagreed. Bash(./mvnw --batch-mode -Pci -pl parallel-consumer-core test:*) sat directly under a paragraph claiming the reviewer only runs the repo's wrappers "so it runs what CI runs", while itself skipping -Dexcluded.groups=performance,chaos,quarantined, being core-only, and dropping clean / -Dlicense.skip / rerunFailingTestsCount.

Your point about QuarantinedAnnotationContractTest is the one that settled it: that test pins the exclusion for ci-unit-test.sh, ci-integration-test.sh and ci-build.sh, but cannot cover a command embedded in a workflow string — so a regression of that past P1 would go uncaught through exactly this path. Removed, with the reasoning recorded in the comment.

3. Credential exposure — acknowledged, not resolved

I'm not going to claim this one is handled. Running the PR's own Maven/test code in the same job that holds secrets.CLAUDE_CODE_OAUTH_TOKEN means a malicious build plugin could read it from the environment if the action doesn't scrub it before spawning Bash subprocesses, and pull-requests: write did widen what an exfiltrated token could do. I can't verify the action's internals from here, so treating it as open is the honest position.

Two things bound it in the meantime: fork PRs don't receive secrets (so this is same-repo-only, i.e. push-access holders), and the grants are an enumerable allowlist rather than blanket shell. Neither addresses your actual point, which is about the token's reachability rather than the tool scope. Recorded for follow-up rather than closed.


Nothing else changed. The inline-blocking-comment mechanism, timeout-minutes, fetch-depth: 0 and the JDK/cache setup are as you reviewed them.

One structural note for whoever merges: this PR cannot self-review. claude-code-action refuses to run when the workflow file differs from the copy on the default branch ("Workflow validation failed … must have identical content to the version on the repository's default branch"), and it reports the job as success while skipping — so a silent skip is indistinguishable from a clean pass. That's a deliberate and sensible control on the action's part, but it means everything in this PR is only exercised after merge, by the next PR that runs.

🤖 Generated with Claude Code

@astubbs

astubbs commented Aug 3, 2026

Copy link
Copy Markdown
Owner Author

@claude last review please

@claude

claude Bot commented Aug 3, 2026

Copy link
Copy Markdown

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


Review: ci(review): let the PR reviewer run the tests instead of trusting the author — final review

Verified independently rather than taking the commit message's word for it — same standard this PR asks the reviewer to hold PRs to.

Finding #1 (bespoke mvnw grant) — confirmed fixed

grep -n mvnw on the current workflow shows the string ./mvnw only inside two explanatory comments (why there's no bespoke grant); it no longer appears inside the actual --allowedTools list on claude-code-review.yml:103. The two wrapper scripts (bin/ci-unit-test.sh, bin/ci-integration-test.sh) are the only test runners granted now, so "runs what CI runs" is true again.

Finding #2 (bin/todo-index.sh) — confirmed fixed

  • ls bin/todo-index.sh → does not exist on this branch (consistent with astubbs's correction that it lives on unmerged docs: index every TODO/FIXME/XXX marker, triage into the existing refactoring backlog #103, not "nowhere ever" — noted and appreciated).
  • The grant, the bin/todo-index.sh --check system-prompt sentence, and both changelog/README mentions are all gone. CHANGELOG.adoc:29 and README.adoc:1600 are byte-identical and now say only bin/check-*.sh, matching what's actually granted.
  • All six scripts still listed in --allowedTools exist on this branch and are executable: ci-unit-test.sh, ci-integration-test.sh, check-copyright-headers.sh, test-check-copyright-headers.sh, check-quarantine-registry.sh, check-quarantine-owners.sh. No dangling grants.
  • The new "every grant must be a script that exists on THIS branch" rule is recorded directly in the workflow comment (claude-code-review.yml:86-88), so this class of mistake has a documented guard against recurrence.

Finding #3 (credential exposure via PR-authored test code) — still open, correctly not silently dropped

Nothing in this round touches it, and astubbs's comment explicitly declines to claim it's resolved rather than papering over it. That's the right call — it's a real, unverified-either-way risk (whether claude-code-action scrubs CLAUDE_CODE_OAUTH_TOKEN from the environment before spawning Bash subprocesses) and forcing a resolution here isn't warranted just to close the thread. Leaving it recorded as a follow-up rather than merging it silently is consistent with the PR's own stated standard.

Sanity checks

  • YAML structure (permissions block, claude_args block scalar, quoting in --allowedTools/--append-system-prompt) looks well-formed on inspection; the PR author's actionlint validation claim isn't independently re-run here (couldn't execute actionlint in this session — sandboxed shell required approval I don't have), so that specific claim is trusted, not verified, in this pass. Flagging per this PR's own standard: I did not execute the check.
  • CI on the current commit (f6a76cb): PR Checklist, PR Dependency Check, Copyright Headers, Quarantine Lane, and the review workflow itself all completed green; CI and highcpu are still in progress/queued at review time — nothing failing.
  • Worth flagging (informational, not a defect in this PR): the review job shows completed/success on this PR's own commits. Per astubbs's note in-thread, claude-code-action refuses to run when the workflow file differs from the default branch's copy and reports that as a success, not a failure — so this green check does not confirm the new grants/prompt have actually executed yet. That's a property of the action, not a bug here, but it means this PR's own effectiveness is unverified until it's exercised post-merge by a subsequent PR.

Conclusion

Both blocking-adjacent findings from the previous round are genuinely fixed, not just asserted fixed. No new issues found in the delta. The one open item (credential exposure) is pre-existing, already discussed at length across two prior reviews, and reasonably left as a follow-up rather than blocking this PR. No further changes requested from me.

Four things #102 does not resolve, so they are not lost at merge:

- A green 'review' check can mean the reviewer never ran.
  claude-code-action refuses to run when the workflow file differs from
  the default branch's copy, and reports that skip as SUCCESS. Any PR
  editing a validated workflow therefore gets a green review check that
  verified nothing - it bit #102 and #104, both workflow changes. The
  control itself is correct (it stops a PR rewriting the reviewer's own
  grants and having that version execute), but it is invisible unless
  you read the job log, so it needs saying out loud.
- Credential exposure is unresolved, not cleared: the job runs
  PR-authored build code alongside CLAUDE_CODE_OAUTH_TOKEN, and #102
  widened the blast radius to pull-requests: write. Bounded by fork PRs
  not getting secrets and by the allowlist - neither of which answers
  the actual question about token scrubbing.
- The reviewer cannot lint workflows: actionlint is not granted, so on a
  workflow PR it can only eyeball YAML, as it said itself on #102
  ('trusted, not verified'). Cheap to grant, but it must land in a
  non-workflow PR or the validation skip means it is never exercised.
- bin/ci-integration-test.sh may not fit the 30-minute cap, and none of
  #102's setup (cache, Docker, the grants) has actually executed yet -
  same reason.

Filed under CI reliability / gate issues rather than refactoring.md:
these are in-flight gate concerns tied to open PRs, not deferred code
work.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QqHpNSXC39ANv9kG1ZvUzn
@astubbs astubbs changed the title ci(review): let the PR reviewer run the tests instead of trusting the author ci(review): let the PR reviewer verify claims instead of trusting them Aug 3, 2026
@astubbs
astubbs merged commit 50e8d8e into master Aug 3, 2026
28 of 31 checks passed
@astubbs
astubbs deleted the ci/let-review-agent-run-tests branch August 3, 2026 02:02
astubbs added a commit that referenced this pull request Aug 3, 2026
…esn't exist

Two findings from the #101 review rounds.

1. gotK1 was write-only state, left behind when the old
   while (!gotK0 && !gotK1) loop condition was replaced by the
   event-based wait. Removed.

2. docs/inflight.md claimed the remaining awaitForSomeLoopCycles/sleep
   waits in this class were 'filed under Test infrastructure -
   timing-based waits in docs/refactoring.md'. That section exists only
   on #103's unmerged branch - zero occurrences here or on master - so
   the ledger cited a reference to nothing, in the PR whose own thesis
   is 'do not let something look tracked when it is not'. The reviewer
   flagged it three rounds running.

   Reworded to say #103 adds that entry and to file them there once it
   merges, rather than claiming they already are. Same mistake as the
   bin/todo-index.sh grant on #102: cross-referencing content that lives
   on another unmerged branch.

Full reactor after both: 11 modules, 740 tests, 0 failures.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QqHpNSXC39ANv9kG1ZvUzn
astubbs added a commit that referenced this pull request Aug 3, 2026
Review on #103 noted the scan covers .java/.sh/.xml/.yml/.yaml but not
docs, and that the omission was reasonable but unexplained in the
script's own scope comment. It was the missing rationale that was the
gap, so this adds it - with evidence rather than assertion, because
'surely docs could contain a TODO too' is a reasonable first reaction.

Scanning them was tried. It added 4 hits and not one was a marker:
three were docs/refactoring.md QUOTING markers the index already lists
from their .java source, so the same work appeared twice and the count
inflated, and the fourth was prose ('seeded from a code scan
(TODO/FIXME + ...)'). That is structural, not bad luck - refactoring.md
is where marker triage lives, and AGENTS.md / inflight.md /
CHANGELOG.adoc describe this tool, so scanning docs means indexing the
index-of-work. The generated index is the reductio: on its own it
accounts for ~95 self-referential hits.

Also keeps two things the experiment surfaced, needed regardless:

- a filter for compound names (todo-index.sh as a FILENAME, not a
  marker). This is live, not theoretical: merging master brought in
  #102's workflow comment naming the script, and the scanner was
  counting it as a 92nd marker. --check caught it, which is a decent
  self-validation of the tool.
-  excluded belt-and-braces, so a future widening cannot make the
  index index itself.

Index back to 91 markers, --check clean.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QqHpNSXC39ANv9kG1ZvUzn
astubbs added a commit that referenced this pull request Aug 3, 2026
…actoring backlog (#103)

91 TODO/FIXME/XXX markers were scattered across the tree with nothing
tracking them. This adds a generated inventory, and triages the useful
ones into the backlog that already exists rather than a new one.

docs/TODO_INDEX.md - generated inventory

bin/todo-index.sh walks the tracked tree and writes every marker,
grouped by module with file and line. --check exits non-zero when the
committed index is stale, so it can be wired into CI later.

This does not overlap docs/refactoring.md's existing // TODO(refactor):
convention - that captures 3 markers; this inventories all 91, a
population nothing was tracking.

Triage goes in docs/refactoring.md

An earlier revision of this PR added a separate docs/TODO_TRIAGE.md.
That was wrong and has been removed. docs/refactoring.md was already a
295-line backlog with a release-gated 'Breaking changes queued for next
major version' section (already listing the deprecated commitInterval
options I had 'discovered'), a 'Remove static state' section carrying
upstream refs (confluentinc#405, #126, #143) and design branches I did not have, and
per-file entries for #233, the encoders and WorkContainer. My triage
re-derived that taxonomy from scratch with worse provenance.

The root error: concluding 'no breaking-changes list exists' after
grepping only docs/inflight.md. Too narrow a search to support the
conclusion drawn from it.

Two findings genuinely absent from refactoring.md were folded into it:
the loop-cycle waits in ParallelEoSStreamProcessorTest (not a style
point - that class is on the known intermittent-failure list, and
cycle-counting IS the flake mechanism), and the MockConsumer
.groupMetadata() workaround copy-pasted across four example tests (one
Apache Kafka defect, four times; not ours to fix, but the duplication
is).

The guardrail is the durable part

AGENTS.md gains a 'Where things live' table - one row per document, what
it owns and what it is explicitly NOT for, since the boundaries are what
get guessed wrong. There was no docs index at all: pointers were
scattered across six sections, and docs/SELF_HOSTED_RUNNER.md was linked
from nowhere. That layout only works if you already know which section
to read, which is circular - and is how this PR went wrong.

An earlier guardrail attempt lived inside the 'Refactoring backlog'
section, so it only reached someone who had already found the file it
was warning them about. The warning is now at the top, before the
mistake rather than after it.

Why .adoc/.md are not scanned

Raised in review, and recorded as a comment in list_files() rather than
left as an unexplained omission. It was tried: scanning docs added 4
hits and not one was a marker. Three were docs/refactoring.md QUOTING
markers the index already lists from their .java source - so the same
work appeared twice and the count inflated - and the fourth was prose.

That is structural, not bad luck: refactoring.md is where marker triage
lives, and AGENTS.md / inflight.md / CHANGELOG.adoc describe this tool,
so scanning docs means indexing the index-of-work. The generated index
is the reductio - alone it accounts for ~95 self-referential hits. The
comment also says what to do instead: if a genuine marker lands in
prose, move it into the code it concerns, where the scan will find it.

Marker detection

101 on the first pass, 91 real. Excluded with reasons in the script:
shell variables (todo=(), ${todo[*]}), YAML field keys (upstream-map
.yaml uses todo: as a schema field), string literals, prose referencing
a marker elsewhere, and compound names where the word is part of a
filename (todo-index.sh). That last is live, not theoretical: merging
master brought in #102's workflow comment naming the script and the
scanner counted it as a 92nd marker until filtered - caught by --check,
a fair self-validation of the tool.

One self-inflicted bug found while building it: the anchored exclusions
were applied to grep -n output, so ^ never matched and they silently did
nothing. Noted in the script so it is not reintroduced.

Not wired into CI as a gate. --check exists for it, but making it gating
means every added or removed marker fails the build until regenerated -
worth deciding deliberately, not as a side effect here.

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
astubbs added a commit that referenced this pull request Aug 3, 2026
AGENTS.md already said changelog entries must link the PR ("a bare #NN
refers to this fork ... and link the PR/issue"). It was missed anyway,
for a structural reason rather than carelessness: the entry is written
BEFORE the PR exists, so at authoring time there is no number to cite,
and nothing afterwards prompts you to return. #100, #101, #102 and #103
each shipped an entry with no self-reference, and each was caught one at
a time by a human reading the diff. That is the profile of a rule worth
making mechanical.

The gate: when a PR ADDS a new CHANGELOG.adoc entry, at least one added
entry must reference this PR (pull/NN or #NN).

Deliberately narrow, to avoid false failures:
- only genuinely new asciidoc bullets count, so reflows and edits to
  older entries are ignored;
- word-bounded matching, so #100 does not match inside #1000;
- opt-out for a PR that touches the changelog without adding an entry of
  its own: `changelog-ref: N/A - <reason>` on its own line in the body,
  reason required, mirroring the checklist's existing N/A convention;
- bots exempt, consistent with the checklist gate;
- no changelog change at all means nothing to check - whether an entry
  was NEEDED is already the checklist item's job.

The logic lives in .github/scripts/changelog-ref-gate.js rather than
inline in the workflow, and is unit tested (28 tests, plain node, no
runner) with the tests running BEFORE the gate, so a regression fails
the job loudly instead of silently mis-judging PRs. That is not
gold-plating: this logic shipped two real misjudgements during review -
an opt-out regex a body merely QUOTING the syntax could trip, and
positional add/remove pairing that mis-read a block holding both an edit
and a new entry. Mirrors the existing copyright.yml self-test step.

Pairing is by CONTENT, not position: an added bullet reads as an edit of
a removed one when they share a (#NN) citation, or failing that when
their wording overlaps enough. Position alone turns -A,-B,+A',+NEW,+B'
into exactly the wrong answer - +NEW consumed as an edit and never
checked.

KNOWN LIMITATION, raised in review and confirmed by construction. When
NEITHER bullet carries a citation, pairing falls back to word overlap -
and this changelog is full of same-template entries ("build(deps): Bump
<lib> to <version>"). Given a removed "Bump Testcontainers to 1.20.0", a
genuinely new "Bump Kafka to 3.9.0", and a reworded edit of the
Testcontainers line, the gate pairs the NEW line as the edit: it escapes
the citation check while the real edit is falsely flagged. Wrong both
ways, and the escaping half is the false negative this gate exists to
prevent.

Not tuned blind - the threshold is a considered choice and a guessed
replacement could easily be worse. Instead it is pinned by a regression
test that states outright it records ACCEPTED rather than DESIRED
behaviour (a failure caused by the gate getting stricter is an
improvement), and documented next to EDIT_THRESHOLD with the direction
to take if it bites: FAIL CLOSED, so an uncertain pair is treated as a
new entry needing a citation. That trades a silent miss for a visible
false alarm - and the false alarm has an escape hatch, whereas the miss
has nothing.

Needs pull-requests: read to fetch the patch, and an actions/checkout
(persist-credentials: false, since nothing there consumes secrets) so
the module and its tests are on disk.

---------

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