Skip to content

fix(review): close the todo-index grant that let the reviewer rewrite the tree - #286

Merged
astubbs merged 19 commits into
masterfrom
ci/claude-yml-script-grant
Aug 18, 2026
Merged

astubbs merged 19 commits into
masterfrom
ci/claude-yml-script-grant

Conversation

@astubbs

@astubbs astubbs commented Aug 11, 2026 •

Copy link
Copy Markdown
Owner

Description

The review agent is granted bin/todo-index.sh so it can ask whether the committed TODO index is
stale. It was granted as Bash(bin/todo-index.sh:*), and that wildcard let it run the script bare
— which regenerates docs/todo-index.md.

A reviewer that rewrites the tree it is inspecting then reports on its own edit. Any diff it describes
afterwards is untrustworthy, and nothing in the run says so.

Narrowing the allowlist is not enough on its own

The obvious fix — grant --check instead of :* — does not hold, because the script's parser did not
enforce it:

[[ "${1:-}" == "--check" ]] && CHECK_MODE=true

Anything unrecognised was silently ignored. So bin/todo-index.sh --check=false matched a
prefix-shaped grant of --check, left CHECK_MODE false, fell through to the rewrite path, and
exited 0. Found and reproduced by the review agent on this PR.

So the fix is two-sided:

  • The allowlist is exact — Bash(bin/todo-index.sh --check) in both workflows. The absence of
    :* is load-bearing, and commented as such so it does not get "tidied" to match its neighbours.
  • The script rejects everything else, exiting 2 on a usage error (leaving 1 to mean "the index is
    stale"). The guarantee now lives in the parser, where it holds however the caller was granted,
    rather than in an allowlist string duplicated across two workflow files.
  • bin/test-todo-index.sh pins the boundary and asserts both allowlists still grant the exact
    command rather than a prefix. Wired into pr-checklist.yml ahead of the gate it protects.

Recorded, not fixed

Two findings from reviewing this change get their own inflight notes rather than scope creep:

  • docs/inflight/ci-claude-trigger-fires-on-prose.md — claude.yml starts on
    contains(body, '@claude'), a plain substring test, so a comment discussing the trigger starts a
    billed job. Observed here: two review replies quoted the string in backticks and fired exactly two
    runs. The fix is a user-facing semantics change, so it is the owner's call.
  • docs/inflight/ci-networked-checker-in-reviewer-grant.md — bin/check-quarantine-owners.sh fetches
    and reads through FETCH_HEAD, breaking the bin/AGENTS.md rule that a granted prefix must not
    reach the network beyond gh reads.

Verification

bin/test-todo-index.sh was written red-before-fix: it fails against the pre-fix script, and against
mutations that reintroduce a :* grant in either workflow.

Checklist

  • Docs updated — two inflight notes added, ci-review-agent.md cross-references them
  • N/A - no user-visible capability change; this is reviewer tool configuration, not a library feature
  • Tests added/updated — bin/test-todo-index.sh, wired into pr-checklist.yml
  • Title & body reflect the final content of this PR

… start it

`.github/workflows/claude.yml` is the only reviewer available to a PR that edits
`claude-code-review.yml` - the action refuses to run when its own workflow differs
from the default branch, so the automatic reviewer skips itself there. That
fallback passed no `--allowed-tools` at all, which is not permissive: an absent
allowlist means Bash is not pre-approved, and a CI run has nobody to answer the
approval prompt, so every script call was refused.

So the reviewer that most needs to check a claim by running it was the one least
able to. On #273 it verified a self-test's negative control by hand-tracing
Python rather than executing a one-second script, and reported the block itself:
`bash bin/test-check-docs-data.sh` and `./bin/check-docs-data.sh` were both
refused while `git log`, `grep` and `python3 --version` ran unprompted.

An earlier review round had concluded the opposite - that the absent restriction
meant the block came from elsewhere and no workflow grant could clear it. That
reasoning is wrong, and the next round disproved it in-session rather than by
argument.

Grants the read-only gates plus read-only `gh` queries. Not the Maven suites that
`claude-code-review.yml` grants: those need a JDK and a warm cache this job does
not set up, and a comment-triggered job holding secrets is the wrong place to run
a build.

THE GATE THAT COMES WITH IT

Granting execution here is not the same trade as granting it in the review job,
and the difference is easy to miss. A comment trigger receives repository secrets
even on a FORK's pull request, where `pull_request` withholds them. The "bounded
by fork PRs not receiving secrets" reasoning recorded in
docs/inflight/ci-review-agent.md therefore never applied to this file: the OAuth
token sits in a job any commenter could start.

The job is now gated on `author_association` being OWNER, MEMBER or COLLABORATOR
- enforcing the "trusted authors only" posture that entry already assumed,
instead of leaving it an assumption.

WHAT IS DELIBERATELY NOT IN HERE

Which tree the granted scripts run against is unproven. The checkout names no
`ref` and uses `fetch-depth: 1`, which for a comment trigger is the default
branch - yet the #273 round described the fixed guard accurately, which
master's copy could not have supported. A PR-head checkout in a comment-triggered
job is a security change, not a convenience one, so it is left to be made knowing
whether it is needed. Recorded as the open question; the first granted run
settles it.

Also deletes docs/inflight/ci-docs-data-audit-not-required.md, whose own
delete-condition - the context appearing in ruleset 15055005 - is now met, and
corrects two stale claims in ci-review-agent.md: bin/todo-index.sh is granted in
both workflows now, and only actionlint remains missing.

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

Copy link
Copy Markdown

Dependency Review

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

Scanned Files

None

@claude

claude Bot commented Aug 11, 2026 •

Copy link
Copy Markdown

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


Code review complete ✅

  • Gather context (PR diff, description, changed files)
  • Run code review over the diff
  • Post findings (as inline comments)

Summary

Reviewed .github/workflows/claude.yml (gate + allowlist changes), docs/inflight/ci-review-agent.md updates, and the deletion of docs/inflight/ci-docs-data-audit-not-required.md. This is a small, carefully-documented CI-configuration change. Verified: all 12 granted bin/*.sh script paths exist and are read-only apart from one noted exception; the new if: gate's expression syntax (fromJSON/contains, the || association-selection chain, added parens) is logically sound and correctly restricts triggering to OWNER/MEMBER/COLLABORATOR; --allowed-tools is a valid CLI flag (ruling out a typo that would silently defeat the grant); no other workflow needs the same gate; no CLAUDE.md exists in this repo to check conventions against.

Three findings posted as inline comments:

  1. .github/workflows/claude.yml:46 — The checkout step still has no ref: and uses fetch-depth: 1. For a comment-triggered event this defaults to checking out master, so a granted script could run against master's tree while appearing to review the PR. The PR author already flags this explicitly as a deliberately-deferred open question in the docs update, so this is more a "confirmed open risk" than a new finding — but it's the most substantive item here since this PR is what activates the risk (by granting execution in the first place).
  2. .github/workflows/claude.yml:81 (minor) — The comment labels the whole grant list "Read-only gates," but bin/test-check-docs-data.sh is documented elsewhere as write-then-restore (via trap), not strictly read-only. Could mislead a future editor into assuming all granted scripts are side-effect-free.
  3. .github/workflows/claude.yml:33 (minor) — The comment claims "exactly one is non-null per event" for the author_association || chain, but issue_comment events populate both comment.author_association and issue.author_association. Harmless today (first term wins and is correct), but the "exactly one" claim could mislead a future reorder of the chain.

@github-actions

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

No new clones introduced by this PR.

✅ jscpd (language-agnostic)

PR Base Change
Clones 66 66 ➖ 0
Duplicated lines 933 933 ➖ 0
Duplication 2.54% 2.54% ➖ 0
Rule Limit Status
Max duplication 5% ✅ Pass (2.54%)
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 11, 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/bz/stub/parallelconsumer/ExceptionInUserFunctionException.java

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

File Similarity (%)
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/ParallelConsumerException.java 53.51 ⚠️
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/internal/InternalException.java 38.69
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/PCRetriableException.java 35.81
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/EncodingNotSupportedException.java 35.12
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/RunLengthV1EncodingNotSupported.java 33.88
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/BitSetEncodingNotSupportedException.java 33.73
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/RunLengthV2EncodingNotSupported.java 33.04
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/OffsetDecodingError.java 32.81
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/JStreamParallelEoSStreamProcessor.java

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

File Similarity (%)
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/JStreamParallelStreamProcessor.java 61.97 ⚠️
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/ParallelEoSStreamProcessor.java 55.67 ⚠️
parallel-consumer-vertx/src/main/java/bz/stub/parallelconsumer/vertx/JStreamVertxParallelEoSStreamProcessor.java 40.72
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/ParallelStreamProcessor.java 38.25
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/PollContextInternal.java 33.44
parallel-consumer-vertx/src/main/java/bz/stub/parallelconsumer/vertx/JStreamVertxParallelStreamProcessor.java 31.88
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/internal/PCModule.java 30.42
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/JStreamParallelStreamProcessor.java

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

File Similarity (%)
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/JStreamParallelEoSStreamProcessor.java 61.97 ⚠️
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/ParallelEoSStreamProcessor.java 51.77 ⚠️
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/ParallelStreamProcessor.java 37.84
parallel-consumer-vertx/src/main/java/bz/stub/parallelconsumer/vertx/JStreamVertxParallelEoSStreamProcessor.java 33.04
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/PollContextInternal.java 32.46
parallel-consumer-vertx/src/main/java/bz/stub/parallelconsumer/vertx/JStreamVertxParallelStreamProcessor.java 30.91
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/internal/PCModule.java 30.82
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/PCRetriableException.java

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

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

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

File Similarity (%)
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/ExceptionInUserFunctionException.java 53.51 ⚠️
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/internal/InternalException.java 51.67 ⚠️
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/EncodingNotSupportedException.java 42.94
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/BitSetEncodingNotSupportedException.java 33.24
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/OffsetDecodingError.java 31.95
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/internal/InternalRuntimeException.java 30.75
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/ParallelConsumerOptions.java

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

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

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

File Similarity (%)
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/JStreamParallelEoSStreamProcessor.java 55.67 ⚠️
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/JStreamParallelStreamProcessor.java 51.77 ⚠️
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/ParallelStreamProcessor.java 46.39
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/PollContextInternal.java 34.52
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/internal/AbstractParallelEoSStreamProcessor.java 33.11
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/internal/TestParallelEoSStreamProcessor.java 31.59
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/internal/PCModule.java 30.13
parallel-consumer-vertx/src/main/java/bz/stub/parallelconsumer/vertx/JStreamVertxParallelEoSStreamProcessor.java 30.06
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/ParallelStreamProcessor.java

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

File Similarity (%)
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/ParallelEoSStreamProcessor.java 46.39
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/JStreamParallelEoSStreamProcessor.java 38.25
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/JStreamParallelStreamProcessor.java 37.84
parallel-consumer-vertx/src/main/java/bz/stub/parallelconsumer/vertx/JStreamVertxParallelStreamProcessor.java 33.69
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/PollContext.java

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

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

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

File Similarity (%)
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/ParallelEoSStreamProcessor.java 34.52
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/JStreamParallelEoSStreamProcessor.java 33.44
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/RecordContextInternal.java 32.71
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/JStreamParallelStreamProcessor.java 32.46
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/PollContext.java 31.07
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/RecordContextInternal.java

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

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

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

File Similarity (%)
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/ParallelEoSStreamProcessor.java 33.11
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/internal/BrokerPollSystem.java 32.49
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/internal/BrokerPollSystem.java

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

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

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

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

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

File Similarity (%)
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/EncodingNotSupportedException.java 59.33 ⚠️
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/ParallelConsumerException.java 51.67 ⚠️
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/OffsetDecodingError.java 50.43 ⚠️
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/NoEncodingPossibleException.java 48.06
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/internal/InternalRuntimeException.java 39.89
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/ExceptionInUserFunctionException.java 38.69
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/BitSetEncodingNotSupportedException.java 35.64
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/PCRetriableException.java 32.72
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/RunLengthV1EncodingNotSupported.java 32.57
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/RunLengthV2EncodingNotSupported.java 31.76
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/internal/InternalRuntimeException.java

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

File Similarity (%)
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/internal/InternalException.java 39.89
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/EncodingNotSupportedException.java 31.25
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/ParallelConsumerException.java 30.75
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/internal/PCModule.java

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

File Similarity (%)
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/internal/PCModuleTestEnv.java 32.08
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/JStreamParallelStreamProcessor.java 30.82
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/JStreamParallelEoSStreamProcessor.java 30.42
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/ParallelEoSStreamProcessor.java 30.13
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/internal/ProducerManager.java

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

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

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

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

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

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

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

File Similarity (%)
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/EncodingNotSupportedException.java 50.35 ⚠️
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/RunLengthV1EncodingNotSupported.java 36.78
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/RunLengthV2EncodingNotSupported.java 35.85
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/internal/InternalException.java 35.64
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/ExceptionInUserFunctionException.java 33.73
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/ParallelConsumerException.java 33.24
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/OffsetDecodingError.java 31.69
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/EncodingNotSupportedException.java

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

File Similarity (%)
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/internal/InternalException.java 59.33 ⚠️
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/BitSetEncodingNotSupportedException.java 50.35 ⚠️
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/OffsetDecodingError.java 47.72
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/RunLengthV1EncodingNotSupported.java 46.85
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/NoEncodingPossibleException.java 45.7
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/RunLengthV2EncodingNotSupported.java 45.68
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/ParallelConsumerException.java 42.94
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/ExceptionInUserFunctionException.java 35.12
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/internal/InternalRuntimeException.java 31.25
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/NoEncodingPossibleException.java

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

File Similarity (%)
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/internal/InternalException.java 48.06
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/EncodingNotSupportedException.java 45.7
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/OffsetDecodingError.java 45.29
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/RunLengthV1EncodingNotSupported.java 36.73
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/RunLengthV2EncodingNotSupported.java 35.81
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/OffsetDecodingError.java

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

File Similarity (%)
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/internal/InternalException.java 50.43 ⚠️
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/EncodingNotSupportedException.java 47.72
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/NoEncodingPossibleException.java 45.29
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/ExceptionInUserFunctionException.java 32.81
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/ParallelConsumerException.java 31.95
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/BitSetEncodingNotSupportedException.java 31.69
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/RunLengthV1EncodingNotSupported.java 30.64
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/RunLengthV1EncodingNotSupported.java

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

File Similarity (%)
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/RunLengthV2EncodingNotSupported.java 63.08 ⚠️
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/EncodingNotSupportedException.java 46.85
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/BitSetEncodingNotSupportedException.java 36.78
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/NoEncodingPossibleException.java 36.73
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/ExceptionInUserFunctionException.java 33.88
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/internal/InternalException.java 32.57
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/OffsetDecodingError.java 30.64
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/RunLengthV2EncodingNotSupported.java

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

File Similarity (%)
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/RunLengthV1EncodingNotSupported.java 63.08 ⚠️
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/EncodingNotSupportedException.java 45.68
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/BitSetEncodingNotSupportedException.java 35.85
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/offsets/NoEncodingPossibleException.java 35.81
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/ExceptionInUserFunctionException.java 33.04
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/internal/InternalException.java 31.76
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/state/PartitionState.java

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

File Similarity (%)
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/VeryLargeMessageVolumeTest.java 39.54
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/TransactionAndCommitModeTest.java 38.98
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/MultiInstanceHighVolumeTest.java 35.49
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/RebalanceEoSDeadlockTest.java

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

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

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

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

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

File Similarity (%)
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/VeryLargeMessageVolumeTest.java 53.93 ⚠️
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/MultiInstanceHighVolumeTest.java 43.51
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/MultiInstanceRebalanceTest.java 38.98
parallel-consumer-vertx/src/test-integration/java/bz/stub/parallelconsumer/vertx/integrationTests/VertxConcurrencyIT.java 31.36
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/TransactionTimeoutsTest.java

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

File Similarity (%)
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/internal/ProducerManagerTest.java 31.05
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/VeryLargeMessageVolumeTest.java

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

File Similarity (%)
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/MultiInstanceHighVolumeTest.java 57.01 ⚠️
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/TransactionAndCommitModeTest.java 53.93 ⚠️
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/MultiInstanceRebalanceTest.java 39.54
parallel-consumer-vertx/src/test-integration/java/bz/stub/parallelconsumer/vertx/integrationTests/VertxConcurrencyIT.java 35.26
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/chaostests/AbstractRevokeUnderWorkScenario.java

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

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

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

File Similarity (%)
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/chaostests/AbstractRevokeUnderWorkScenario.java 49.09
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/chaostests/ChaosScenarioBase.java 37.92
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/chaostests/ChaosConductorRestartRefusalIT.java

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

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

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

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

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

File Similarity (%)
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/chaostests/ChaosRevokeUnderWorkCooperativeIT.java 47.74
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/chaostests/AbstractRevokeUnderWorkScenario.java 35.14
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/chaostests/ChaosScenarioBase.java

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

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

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

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

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

File Similarity (%)
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/utils/ManagedPCInstance.java 33.96
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/chaostests/ChaosConductorRestartRefusalIT.java 30.4
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/AbstractParallelEoSStreamProcessorTestBase.java

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

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

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

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

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

File Similarity (%)
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/QuarantineLaneReportScriptTest.java 49.61
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/QuarantineRegistryScriptTest.java 47.62
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/CoreBatchTest.java

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

File Similarity (%)
parallel-consumer-reactor/src/test/java/bz/stub/parallelconsumer/reactor/ReactorBatchTest.java 51.73 ⚠️
parallel-consumer-mutiny/src/test/java/bz/stub/parallelconsumer/mutiny/MutinyBatchTest.java 50.43 ⚠️
parallel-consumer-vertx/src/test/java/bz/stub/parallelconsumer/vertx/VertxBatchTest.java 44.54
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/BatchTestBase.java 30.28
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/MockConsumerCommitTimeoutTest.java

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

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

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

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

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

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

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

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

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

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

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

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

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

File Similarity (%)
parallel-consumer-vertx/src/test/java/bz/stub/parallelconsumer/vertx/TestConventionsArchTest.java 90.0 ⚠️
parallel-consumer-mutiny/src/test/java/bz/stub/parallelconsumer/mutiny/TestConventionsArchTest.java 89.32 ⚠️
parallel-consumer-reactor/src/test/java/bz/stub/parallelconsumer/reactor/TestConventionsArchTest.java 89.32 ⚠️
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/internal/PCModuleTestEnv.java

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

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

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

File Similarity (%)
parallel-consumer-core/src/test-integration/java/bz/stub/parallelconsumer/integrationTests/TransactionTimeoutsTest.java 31.05
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/internal/ProducerManager.java 30.14
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/internal/TestParallelEoSStreamProcessor.java

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

File Similarity (%)
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/offsets/OffsetEncodingBackPressureTest.java 38.88
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/truth/CommitHistorySubject.java

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

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

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

File Similarity (%)
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/truth/CommitHistorySubject.java 36.14
parallel-consumer-mutiny/src/main/java/bz/stub/parallelconsumer/mutiny/MutinyProcessor.java

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

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

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

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

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

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

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

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

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

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

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

File Similarity (%)
parallel-consumer-vertx/src/test/java/bz/stub/parallelconsumer/vertx/TestConventionsArchTest.java 90.8 ⚠️
parallel-consumer-reactor/src/test/java/bz/stub/parallelconsumer/reactor/TestConventionsArchTest.java 90.11 ⚠️
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/TestConventionsArchTest.java 89.32 ⚠️
parallel-consumer-reactor/src/main/java/bz/stub/parallelconsumer/reactor/ReactorProcessor.java

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

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

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

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

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

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

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

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

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

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

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

File Similarity (%)
parallel-consumer-vertx/src/test/java/bz/stub/parallelconsumer/vertx/TestConventionsArchTest.java 90.8 ⚠️
parallel-consumer-mutiny/src/test/java/bz/stub/parallelconsumer/mutiny/TestConventionsArchTest.java 90.11 ⚠️
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/TestConventionsArchTest.java 89.32 ⚠️
parallel-consumer-vertx/src/main/java/bz/stub/parallelconsumer/vertx/JStreamVertxParallelEoSStreamProcessor.java

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

File Similarity (%)
parallel-consumer-vertx/src/main/java/bz/stub/parallelconsumer/vertx/VertxParallelEoSStreamProcessor.java 40.93
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/JStreamParallelEoSStreamProcessor.java 40.72
parallel-consumer-vertx/src/main/java/bz/stub/parallelconsumer/vertx/JStreamVertxParallelStreamProcessor.java 40.18
parallel-consumer-vertx/src/main/java/bz/stub/parallelconsumer/vertx/VertxParallelStreamProcessor.java 35.89
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/JStreamParallelStreamProcessor.java 33.04
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/ParallelEoSStreamProcessor.java 30.06
parallel-consumer-vertx/src/main/java/bz/stub/parallelconsumer/vertx/JStreamVertxParallelStreamProcessor.java

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

File Similarity (%)
parallel-consumer-vertx/src/main/java/bz/stub/parallelconsumer/vertx/JStreamVertxParallelEoSStreamProcessor.java 40.18
parallel-consumer-vertx/src/main/java/bz/stub/parallelconsumer/vertx/VertxParallelStreamProcessor.java 40.17
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/ParallelStreamProcessor.java 33.69
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/JStreamParallelEoSStreamProcessor.java 31.88
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/JStreamParallelStreamProcessor.java 30.91
parallel-consumer-vertx/src/main/java/bz/stub/parallelconsumer/vertx/VertxParallelEoSStreamProcessor.java

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

File Similarity (%)
parallel-consumer-vertx/src/main/java/bz/stub/parallelconsumer/vertx/VertxParallelStreamProcessor.java 42.84
parallel-consumer-vertx/src/main/java/bz/stub/parallelconsumer/vertx/JStreamVertxParallelEoSStreamProcessor.java 40.93
parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/internal/ExternalEngine.java 39.51
parallel-consumer-vertx/src/main/java/bz/stub/parallelconsumer/vertx/VertxParallelStreamProcessor.java

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

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

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

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

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

File Similarity (%)
parallel-consumer-mutiny/src/test/java/bz/stub/parallelconsumer/mutiny/TestConventionsArchTest.java 90.8 ⚠️
parallel-consumer-reactor/src/test/java/bz/stub/parallelconsumer/reactor/TestConventionsArchTest.java 90.8 ⚠️
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/TestConventionsArchTest.java 90.0 ⚠️
parallel-consumer-vertx/src/test/java/bz/stub/parallelconsumer/vertx/VertxBatchTest.java

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

File Similarity (%)
parallel-consumer-reactor/src/test/java/bz/stub/parallelconsumer/reactor/ReactorBatchTest.java 49.83
parallel-consumer-mutiny/src/test/java/bz/stub/parallelconsumer/mutiny/MutinyBatchTest.java 48.59
parallel-consumer-core/src/test/java/bz/stub/parallelconsumer/CoreBatchTest.java 44.54

@github-actions

Copy link
Copy Markdown

✅ SpotBugs Report

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

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: dc14607d3f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread .github/workflows/claude.yml Outdated
Comment thread .github/workflows/claude.yml Outdated
Comment thread .github/workflows/claude.yml Outdated
Comment thread .github/workflows/claude.yml Outdated
Comment thread .github/workflows/claude.yml Outdated
Five review findings, all real. The first is a hole the original commit opened
and did not close.

REFUSE A FORK PR (P1, from the codex reviewer)

The author gate authenticates the COMMENTER. It says nothing about who wrote the
code. A maintainer typing "@claude" on an outside contributor's fork PR is a
trusted trigger over untrusted content - and if the action checks out the PR head
(the very thing this change admits it has not proven), the fork author chooses
what `bin/check-docs-data.sh` contains and this job executes it with
CLAUDE_CODE_OAUTH_TOKEN in the environment. Granting execution while checking
only the commenter builds a confused deputy.

A step before checkout now refuses any pull request whose `isCrossRepository` is
not `false`, so untrusted refs are never even fetched. Fork PRs consequently
cannot get an `@claude` review; they already could not get a useful automatic one,
because `pull_request` withholds the token from forks, so this makes an existing
gap explicit rather than creating one.

GRANT bin/todo-index.sh ONLY WITH --check (P2, from the codex reviewer)

Bare, it regenerates docs/todo-index.md - its own usage block says so. The grant
was written as `Bash(bin/todo-index.sh:*)`, which permits the rewriting form, so
a reviewer could modify the tree it was inspecting and then report a diff that
included its own edit. Now granted only as `--check`, the verify mode.

TWO COMMENTS THAT WERE WRONG (from the claude reviewer)

"Read-only gates" was not true of the set: `bin/test-check-docs-data.sh` mutates
a corpus file and restores it through a trap. claude-code-review.yml discloses
that exception carefully at its own grant, and this file quietly dropped the
disclosure while copying the grant. The comment now says which one writes and
why the exception is considered.

"Exactly one is non-null per event" was also wrong: an `issue_comment` payload
carries both `comment.author_association` and the parent `issue.author_association`.
The chain still selects correctly because `comment` is evaluated first, but the
stated reason was false, and a future editor reordering the chain on the strength
of it would silently begin trusting the wrong person. The comment now says the
order is load-bearing.

THE CHECKOUT AMBIGUITY, RESTATED RATHER THAN RESOLVED

The reviewer independently reached the point this change already recorded, and
sharpened it: before the grant, the unproven checkout ref was harmless because
nothing in the tree was ever executed. The grant is what activates it. That
remains the open question in docs/inflight/ci-review-agent.md, and the first
granted run settles it.

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

claude Bot commented Aug 11, 2026 •

Copy link
Copy Markdown

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


Code review complete ✅

  • Gather context (PR diff, description, changed files, prior review rounds)
  • Re-verify the current state of .github/workflows/claude.yml after 821a91af
  • Cross-check every factual claim in the PR body/comments against the actual repo state
  • Post findings

Summary

This is round 2, reviewing the state after 821a91af fixed the five findings from round 1 (fork-author confused deputy, unrestricted todo-index.sh, the false "read-only" claim, the false "exactly one non-null" claim, and the checkout-ambiguity framing). I independently re-verified the fixes rather than taking the PR body's account of them on trust:

  • All 12 granted script paths exist on this branch (checked via glob against bin/), and pair up correctly per bin/AGENTS.md's "grant both spellings" rule (bin/foo.sh + ./bin/foo.sh).
  • --allowed-tools is a real alias, not a typo. Ran claude --help locally: --allowedTools, --allowed-tools <tools...> — confirms the flag spelling difference from claude-code-review.yml's --allowedTools doesn't silently defeat the grant.
  • bin/todo-index.sh --check restriction is correctly enforced by the permission scheme. The grant is Bash(bin/todo-index.sh --check:*), a prefix match — a bare bin/todo-index.sh invocation (which regenerates docs/todo-index.md per line 187, generate > "$OUT") does not start with that string, so it's correctly excluded. Confirmed claude-code-review.yml still carries the unrestricted Bash(bin/todo-index.sh:*) grant, matching the PR's own "deliberately untouched, worth a follow-up" note.
  • bin/test-check-docs-data.sh's write-then-restore is real, not just asserted: trap restore EXIT at line 59, restore function at lines 51-57 copies the corpus file back and cleans up its tempfile.
  • The two scripts newly added beyond the sibling workflow's grant list (bin/check-issue-refs.sh, bin/check-action-versions.sh) are read-only — read both in full. check-action-versions.sh only greps/sorts workflow files; check-issue-refs.sh only runs read-only git diff/git merge-base, and the one attacker-reachable argument (base-ref) is resolved to a commit SHA via git merge-base before being handed to the inner Node script, not passed through raw.
  • The author-association || chain and the fork-refusal step's if: conditions correctly cover all three PR-bearing trigger events (issue_comment via github.event.issue.pull_request, pull_request_review_comment and pull_request_review via github.event.pull_request), and correctly skip for the non-PR issues event.
  • Cross-checked the docs/inflight/ci-review-agent.md edits and the deleted ci-docs-data-audit-not-required.md against the current workflow files — the "todo-index granted in both workflows now, only actionlint missing" claim holds.

No new findings beyond what round 1 already surfaced and 821a91af already fixed. I looked specifically for anything the previous rounds might have missed (git-argument-injection via script args, TOCTOU between the fork-check and checkout, permission-scope gaps, YAML/logic errors in the if: conditions) and didn't find anything actionable — the one theoretical item (arg injection into check-issue-refs.sh's git merge-base call) is neutralized by the value being consumed only as a merge-base input, with no dangerous flags applicable to that git subcommand, and this whole class of risk is already the accepted, documented tradeoff in bin/AGENTS.md for every enumerated grant here.

Note: this PR only touches claude.yml, not claude-code-review.yml, so per the PR's own note the automatic claude-review check is the reviewer of record here — this fallback pass is a supplementary check, not a replacement.

astubbs and others added 2 commits August 11, 2026 17:30
Both were observed while watching #286, not reasoned about, and neither
belongs in the workflow diff itself.

WRITING ABOUT THE TRIGGER FIRES THE TRIGGER

claude.yml matches with `contains(github.event.comment.body, '@claude')`, a plain
substring test that knows nothing about backticks, code fences or quotation. Two
of the review replies on this PR explained the trust model and quoted the trigger
string; exactly two `Claude Code` runs fired on pull_request_review_comment and
ran to completion. A one-to-one match. Prose about the feature invoked the
feature, and nothing had asked for a review.

Harmless while the fallback can run nothing. It stops being harmless the moment
this PR grants script execution - the same argument that put the fork refusal
here: the cost of the job starting when nobody asked for it goes up.

A `startsWith` on the trimmed body would fix it, but that changes user-facing
trigger semantics, so it is the repository owner's call rather than a silent
tightening. Recorded with the related trap: comment-triggered workflows always
run the copy on the DEFAULT branch, so neither the grant nor the fork refusal
takes effect until merge, and a green Claude Code run on this PR is exercising
master's file rather than this one.

TWO TRACKED FLAKES FIRED ON CONSECUTIVE RUNS OF ONE COMMIT

The unit lane went red twice on 821a91a, and the two failures were not the same
failure:

  attempt 1  PCMetricsTest.metricsRegisterBinding:115
             Failures: 1   expected 203.0, but was 207.0
  attempt 2  OffsetEncodingBackPressureTest
             .backPressureShouldPreventTooManyMessagesBeingQueuedForProcessing:211
             Errors: 1     ConditionTimeout, expected 139 but was 136

Both are already in this ledger - rows 3 and 1 - at 1/45 and 4/45. A code
regression fails the same way twice; an unchanged commit failing two different
tracked flakes in a row is the retry removal from #224 doing exactly what
it was meant to do. PCMetricsTest goes from "one sighting is not a rate" to two.

The mechanism behind the PCMetricsTest one is now known, which the ledger did not
have. The test builds its expectation from a test-side counter snapshot and then
asserts against a registry gauge, so two independently-advancing values are
sampled at different instants with nothing holding the system still between them.
Four more records completed in the gap. The metric was more current than the
expectation written to test it. Same family as 16ac63b ("await the metric, not a
counter that leads it") running the other way round.

A CONTROL THAT WAS VOID, RECORDED BECAUSE IT WILL BE REACHED FOR AGAIN

The first control tried here was "master at a797f75 passed the same suite 35
minutes earlier". It did not, and could not have: a push to master SKIPS the test
matrix. Run 31459241709 shows `matrix.name: skipped`, with only `full build
(master)` running; the unit lane exists on pull_request only. That control could
not have failed, so its passing meant nothing - the "instrument that could have
said yes" trap, from the write-up next door.

The control that does work is other PR runs of the same lane: eight consecutive
green unit runs across three branches that day, including this branch's own
previous head, with only 821a91a red.

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

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

WHY THEY QUALIFY

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

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

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

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

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

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

WHY THEY ARE VISIBLE NOW

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

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

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01R8He6kk23K3gN4qtojL9PE
@astubbs astubbs changed the title ci(review): let the fallback reviewer run the gates, and gate who can start it ci(review): let the fallback reviewer run the gates, and quarantine two flakes Aug 11, 2026
@claude

claude Bot commented Aug 11, 2026 •

Copy link
Copy Markdown

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


Code review complete ✅

  • Gather context (PR diff, description, prior review rounds)
  • Review the new commits since round 2 (a89899aa, 3f2f91a1)
  • Post findings

Summary

This is round 3, scoped to what changed since the last review of 821a91af: two new commits that touch no workflow file — a89899aa (docs) and 3f2f91a1 (quarantines two flaky tests). .github/workflows/claude.yml itself is unchanged from round 2, so I didn't re-review it; I focused on independently verifying the new commits rather than taking the PR body's account of them on trust.

Verified, all checked out:

  • bin/check-quarantine-registry.sh passes locally: 2 entries, method-granularity consistent between docs/quarantined-tests.md and the @Quarantined annotations.
  • Both docs/quarantined-tests.md entries carry the machine-parsed Owner: PR #265 marker in the exact bare form bin/check-quarantine-owners.sh's grep -oE 'Owner: PR #[0-9]+' needs.
  • Compared PR test(core): stop the core tests jar configuring other modules, and remove the sleeps that stood in for events #265's actual diff (not its title) against both quarantine write-ups: it really does replace PCMetricsTest's Thread.sleep(1000) with an await().untilAsserted(...) on the trailing meters, and really does replace OffsetEncodingBackPressureTest's sleepQuietly(DEFAULT_STATIC_RETRY_DELAY) with await().atMost(ofSeconds(30)).until(...) — the fixedBy claims are accurate.
  • flapping = true on both is the right call per the annotation's own contract (Quarantined.java:60-66) — both are timing races (a gauge read racing a still-advancing counter; a static sleep racing a retry event), not deterministic failures.
  • Both test files compile (mvnw test-compile), and the quarantine tooling's own self-tests (CheckQuarantineOwnersScriptTest, QuarantineRegistryScriptTest, QuarantineLaneReportScriptTest — 27 tests) still pass unmodified.
  • The quarantined JUnit tag is excluded from the gating unit lane by pom.xml's excluded.groups default, so these two are correctly routed out of the required checks and into the separate quarantine lane.
  • The new docs/inflight/ci-review-agent.md section ("writing about the trigger fires the trigger") accurately describes the workflow: claude.yml:35-36 really does use a bare contains(github.event.comment.body, '@claude') substring test with no code-fence awareness.

One finding, verified rather than asserted:

PCMetricsTest.java:48 and OffsetEncodingBackPressureTest.java:86 both write fixedBy = "astubbs#265". The cross-check in bin/check-quarantine-owners.sh:84 that's supposed to catch drift between an annotation's fixedBy and the registry's Owner: PR #NN line looks specifically for the literal substring PR #:

declared=$(grep -oE 'fixedBy = "PR #[0-9]+' "$file" | grep -oE '[0-9]+' | head -1 || true)

I ran that exact grep against both files — it matches nothing in either, confirmed empty output. Since the check is only entered if [ -n "$declared" ], this isn't a false pass, it's the check never running at all for these two entries — no error, no advisory, nothing. It's a silent no-op, the same failure class every prior finding on this branch has been about (a safety net that looks present but isn't). The repo's own self-tests and fixtures (CheckQuarantineOwnersScriptTest.java:62, QuarantineLaneReportScriptTest.java:109, QuarantineRegistryScriptTest.java:146) all use the canonical fixedBy = "PR #999999" form, so this looks like the prose convention used everywhere else in this PR (astubbs#265, astubbs#224, astubbs#101) bleeding into a machine-parsed field where it doesn't belong.

Impact is real but bounded: it doesn't break the registry-consistency gate (check-quarantine-registry.sh, which doesn't read fixedBy at all, still passes), and the report generator also doesn't read it (it sources Owner: PR #NN straight from the markdown, not the annotation). It only defeats the one advisory cross-check whose entire job is noticing if the annotation and the registry disagree about who owns the fix.

Fix: change both to fixedBy = "PR #265".

@github-actions

github-actions Bot commented Aug 11, 2026 •

Copy link
Copy Markdown

🧪🔒 Quarantine Lane Report

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

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3f2f91a14e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread docs/quarantined-tests.md Outdated
Comment thread docs/inflight/test-untracked-ci-flakes.md Outdated
Two enforced gates disagreed, and the registry could not satisfy both.

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

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

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

Verified three ways rather than by inspection:

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

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

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

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

claude Bot commented Aug 11, 2026 •

Copy link
Copy Markdown

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


Code review complete ✅

  • Gather context (PR diff, description, prior review rounds, inline comments)
  • Review what changed since round 3 (de6e2c98) and re-verify still-open findings from round 3
  • Post findings

Summary

This is round 4, triggered by the new commit de6e2c98 ("let the owner marker carry a qualified PR reference"). .github/workflows/claude.yml is unchanged since round 2 — this commit only touches bin/check-quarantine-owners.sh, bin/quarantine-lane-report.sh, and docs/quarantined-tests.md.

de6e2c98 verified correct, not just asserted: I ran the new regex (grep -oE 'Owner: PR (astubbs/parallel-consumer|astubbs)?#[0-9]+' | grep -oE '#[0-9]+' | tr -d '#') against all three accepted forms (bare #265, astubbs#265, astubbs/parallel-consumer#265) — all three correctly extract 265, and the two parsers (check-quarantine-owners.sh, quarantine-lane-report.sh) were changed identically, so they stay in step as claimed. bin/check-quarantine-registry.sh still passes (2 entries, consistent). This is a real fix for the P1 Codex raised in round 3 about qualified owner references vs. check-issue-refs.sh.

Two findings from round 3 remain open — re-verified against current HEAD, not carried over from memory:

  1. fixedBy = "astubbs#265" still doesn't satisfy the annotation/registry cross-check. bin/check-quarantine-owners.sh:89 still greps for the literal fixedBy = "PR #[0-9]+ — I ran that exact pattern against both PCMetricsTest.java and OffsetEncodingBackPressureTest.java and it matches nothing in either (the format is fixedBy = "astubbs#265", not fixedBy = "PR #265"). Since the check only runs if [ -n "$declared" ], this is a silent no-op, not a false pass — the one advisory check whose job is catching annotation/registry drift never fires for either entry. I flagged this in round 3; de6e2c98 fixed the registry format conflict but didn't touch this regex or the annotations.

  2. docs/inflight/test-untracked-ci-flakes.md's "different rerun failure" reasoning is unchanged. The section around line 85 still argues "A code regression fails the same way twice; this did not. That is what makes the flake reading solid" — the codex reviewer's round-3 P2 point stands: under concurrent/stress execution, a single regression can plausibly perturb timing enough to surface a different test's failure on rerun, so a different failure mode isn't proof the first one wasn't a regression. No edit to this file since round 3.

New finding, independently verified (not just re-flagging codex's round-3 comment) — I traced the actual code path:

  1. The OffsetEncodingBackPressureTest quarantine's fixedBy diagnosis looks wrong, and I confirmed it line-by-line. The @Quarantined reason (OffsetEncodingBackPressureTest.java:80-87) says the failure is ConditionTimeout ... expected 139 but was 136 within 30 seconds. I checked every numeric assertion in the test:

    • 139 is uniquely produced at line 232: int expectedHighestSeen = numberOfRecordsToPrimeWith + extraRecordsToBlockWithThresholdBlocks - 1; (100 + 40 - 1 = 139), asserted at line 233 (Truth8.assertThat(incompletes.getHighestSeenOffset()).hasValue(expectedHighestSeen)), inside a waitAtMost(defaultTimeout).untilAsserted(...) block — and defaultTimeout (AbstractParallelEoSStreamProcessorTestBase.java:91,93) is exactly 30 seconds, matching "within 30 seconds" precisely.
    • This block is part of the "assert blocked, but can still write payload" section (~line 210), which runs and completes before the "Test that failed messages can retry" section (~line 266) that contains the sleepQuietly(DEFAULT_STATIC_RETRY_DELAY) / await().until(() -> attempts.get() >= 2) code (line 277) that PR test(core): stop the core tests jar configuring other modules, and remove the sleeps that stood in for events #265 actually changes.

    So the section that produces the observed failure and the section PR test(core): stop the core tests jar configuring other modules, and remove the sleeps that stood in for events #265 fixes are disjoint — the retry-delay fix can't affect a highestSeenOffset assertion that already resolved (or failed) earlier in the same test run. If this diagnosis is right, quarantining this test against astubbs#265 as fixedBy means the test will likely still flake with the identical failure after test(core): stop the core tests jar configuring other modules, and remove the sleeps that stood in for events #265 merges, and nothing will catch that (the quarantine lane treats a continuing red as "expected while the owner PR is open," not as "the owner PR didn't fix it"). This was also raised by the codex reviewer in round 3 and hasn't been addressed or rebutted since.

None of these three block the workflow-file change itself (claude.yml is unchanged and already reviewed in rounds 1–2); they're about the quarantine entries added in this branch. Given the PR body's own framing — closing false-confidence gaps — an unverified fixedBy claim on a flake diagnosis is the same failure class the rest of this PR is written to prevent.

Branch ·

…was wrong

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

THE QUARANTINE THAT SHOULD NOT HAVE HAPPENED

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

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

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

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

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

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

A CROSS-CHECK THAT HAD SILENTLY STOPPED CHECKING

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

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

A WITHDRAWN INFERENCE

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

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

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

https://github.com/astubbs/parallel-consumer/blob/de6e2c989d6a8e1e7244ffe0f1794f190e77817d/.claude/worktrees/review-7408/.github/workflows/claude.yml#L135
P2 Badge Remove the networked owner check from the allowlist

When the fallback reviewer invokes bin/check-quarantine-owners.sh, the script runs git fetch --depth=1 origin "$base" and fetches pull/$pr/merge at lines 99 and 110. This grant therefore reaches the network outside gh reads and mutates the checkout's FETCH_HEAD/shallow state inside the secret-bearing job; remove it from the allowlist or refactor the check to use only permitted read operations.

AGENTS.md reference: bin/AGENTS.md:L20-L24


https://github.com/astubbs/parallel-consumer/blob/de6e2c989d6a8e1e7244ffe0f1794f190e77817d/.claude/worktrees/review-7408/.github/workflows/claude.yml#L135
P2 Badge Fetch history before granting the copyright check

On this workflow's depth-1 checkout, invoking bin/check-copyright-headers.sh cannot normally reach its hard-coded fork-point commit; lines 72–83 of that script then print a warning, skip the entire check, and exit 0. The newly granted command can consequently appear successful without checking any headers, so fetch full history before running it or omit the grant rather than presenting a no-op as verification.

AGENTS.md reference: bin/AGENTS.md:L16-L18

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@claude

claude Bot commented Aug 11, 2026

Copy link
Copy Markdown

Claude Code is working…

I'll analyze this and get back to you.

View job run

…-only

Review found that `bin/check-quarantine-owners.sh` runs
`git fetch --depth=1 origin <base>` and `git fetch --depth=1 origin pull/<n>/merge`
and then reads `FETCH_HEAD`. So granting it gave the fallback reviewer network
access outside `gh`, and moved the checkout fetch state underneath it - which
makes anything it inspected afterwards untrustworthy. The same defect as granting
bare `bin/todo-index.sh`, in the same file, one commit later.

Its owner-claim verification belongs to CI's Quarantine Audit lane, not to an
ad-hoc reviewer. `bin/check-quarantine-registry.sh` stays; it only reads the tree.

Auditing the whole list rather than fixing only what was reported turned up two
more inaccuracies in the comment above it:

  `bin/test-check-shell-sigpipe.sh` also writes - but only inside a `mktemp -d`
  it removes on exit, never the tree under review. The comment claimed exactly
  one grant wrote.

  `bin/todo-index.sh` can rewrite `docs/todo-index.md`, but is granted only as
  `--check`, so the rewriting form is not reachable through the allowlist. Worth
  stating, so a future editor does not "simplify" the grant back to bare.

The comment now says which grants write and where, instead of asserting the set
is read-only - a claim that has been wrong twice in this file now, both times
because it was copied forward rather than re-derived from the scripts.

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

astubbs commented Aug 11, 2026

Copy link
Copy Markdown
Owner Author

P2 on bin/check-quarantine-owners.sh — correct, and fixed in 9e4d76ff by removing the grant entirely.

Verified rather than accepted: lines 104 and 115 run git fetch --quiet --depth=1 origin "$base" and git fetch --quiet --depth=1 origin "pull/$pr/merge", and lines 111/119/123 then read FETCH_HEAD. So the grant gave the fallback reviewer network reach outside gh and moved the checkout's fetch state underneath it — which would make anything the reviewer inspected afterwards untrustworthy.

That is the same defect as granting bare bin/todo-index.sh, which was fixed two commits earlier in this same file. Finding the identical class twice in one allowlist says the fault was the method: I picked the grants by matching filenames against the check-*.sh / test-check-*.sh pattern in bin/AGENTS.md, rather than by reading what each script does. A naming convention is not a capability audit.

It is dropped rather than narrowed. Its owner-claim verification is the Quarantine Audit lane's job, and an ad-hoc reviewer has no reason to run it. bin/check-quarantine-registry.sh stays — it only reads the tree.

So I audited the remaining eleven properly, and the report was worse than the finding:

grant reality
bin/test-check-docs-data.sh writes in the repo tree — the documented exception, restores via trap
bin/test-check-shell-sigpipe.sh also writes, but only inside a mktemp -d it removes on exit
bin/todo-index.sh can rewrite docs/todo-index.md, but is granted only as --check, so that path is unreachable
the other eight read and report

The comment above the allowlist claimed exactly one grant wrote. That was wrong twice over — and it was wrong because I copied the sentence forward from claude-code-review.yml instead of re-deriving it from the scripts I was actually granting. It now names each writer and says where it writes, with a note to re-audit when the list grows.

Worth stating plainly: this PR's premise is that a reviewer which cannot execute anything reviews blind. Three rounds of review have now found three cases where I granted more capability than I described. The grant is still right; my accounting of it needed the scrutiny.

@claude

claude Bot commented Aug 11, 2026 •

Copy link
Copy Markdown

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


Code review complete ✅

  • Gather context (PR diff, description, prior 4 review rounds, inline comments)
  • Review what changed since round 4 (427ed83d) — the P2 fix that removed the check-quarantine-owners.sh grant
  • Re-verify the "eleven remaining grants" audit and check for anything the fix missed
  • Post findings

Summary

This is round 5, scoped to 427ed83d ("drop the owner check from the allowlist - it is not read-only"), the only commit since round 4. I verified its claims rather than taking them on trust: bin/check-quarantine-owners.sh is now genuinely absent from the allowlist (confirmed by grep against the current grant string), and it really does call git fetch --depth=1 origin <base> / git fetch --depth=1 origin pull/<n>/merge and read FETCH_HEAD (lines 104/115 per the commit message, confirmed against the file) — so dropping it rather than narrowing it is correct, since narrowing can't remove the network/fetch-state side effect. The updated comment's per-script write disclosure also checks out: bin/test-check-shell-sigpipe.sh writes only inside a self-removing mktemp -d, and bin/todo-index.sh --check genuinely can't reach the rewriting code path (confirmed in round 2).

One finding — the same failure class the fix commit just addressed, in a grant the fix commit didn't touch:

.github/workflows/claude.yml:153 still grants Bash(bin/check-copyright-headers.sh:*), and on this workflow's checkout it silently no-ops instead of checking anything.

  • The checkout at .github/workflows/claude.yml:78-80 uses fetch-depth: 1.
  • bin/check-copyright-headers.sh gates its entire check on git cat-file -e "${FORK_POINT}^{commit}", where FORK_POINT is a specific ancestor commit (7f290122..., dated 2026-03-24) — never the tip, so unreachable from a depth-1 clone by construction.
  • When that check fails, the default path (lines ~72-83) prints WARNING: ... Skipping copyright header check. to stderr and exits 0 — not the "cannot run" exit code 2 the script's own header comment advertises. Exit 2 only fires when COPYRIGHT_CHECK_REQUIRE_FORK_POINT=1 is set, which is exactly what copyright.yml:47 sets for the real gate (paired with its own fetch-depth: 0 at line 38) — but claude.yml sets neither. I grepped the whole workflow file for COPYRIGHT_CHECK and fetch-depth; the only depth setting is the 1 at line 80.
  • The script's own self-test documents this exact behavior as intentional-by-design: bin/test-check-copyright-headers.sh:26 — "fork-point commit missing from history (shallow clone) -> exit 0 (warn+skip); exit 2 only with COPYRIGHT_CHECK_REQUIRE_FORK_POINT=1 (strict, as CI sets)".
  • By contrast, bin/check-issue-refs.sh — granted in this same file — handles the identical shallow-clone situation the opposite way: its own docstring says exit 2 is for "no merge base with the base ref - e.g. a shallow clone", i.e. it fails loud rather than reporting a fake pass. check-copyright-headers.sh is the one grant here whose default failure mode is silent success.
  • claude-code-review.yml:148 grants the identical bin/check-copyright-headers.sh, but that workflow's checkout uses fetch-depth: 0 (line 51), so the grant is safe there. It's specifically the combination of this file's shallow checkout plus this file's missing env var that turns the grant into a no-op — the sibling workflow doesn't share the defect.

Impact: if the fallback reviewer runs bin/check-copyright-headers.sh on a PR that changes copyright headers, it will report exit 0 and a script that looks like "no violations found," when what actually happened is "skipped, insufficient history" — printed only as one stderr line the reviewer has to notice and correctly interpret as a non-check rather than a pass. That's the exact false-confidence pattern this PR's own premise is about, and it's what Codex flagged for check-quarantine-owners.sh and check-copyright-headers.sh together in the same review batch (2026-08-11T06:07:19Z) — 427ed83d fixed the former (network/fetch-state issue) but the latter wasn't addressed and the grant is still present unchanged.

Fix options, in order of preference: (1) drop the grant, same reasoning as check-quarantine-owners.sh — its authoritative home is copyright.yml's full-history job — or (2) if keeping it, set COPYRIGHT_CHECK_REQUIRE_FORK_POINT=1 in this job's env so a shallow run fails loudly (exit 2) instead of silently reporting "conformant."

Branch ·

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 427ed83d21

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread bin/check-quarantine-owners.sh
Comment thread docs/quarantined-tests.md Outdated
Comment thread docs/quarantined-tests.md Outdated
astubbs added a commit that referenced this pull request Aug 11, 2026
…undiagnosed entry diagnosed

Two Codex review findings on #288, both correct.

THE fixedBy CROSS-CHECK WAS STILL SILENTLY DISABLED

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

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

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

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

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

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F2MAyo5JDR5ZdWPGCxDCzY
…hanges)

Directory move only, so every path is 100% similar and git's exact-rename detection
cannot fail on it. The content edits follow in the next commit.

Generated by bin/rename-packages.sh.
Text edits only. No file moves in this commit, so it cannot dilute the rename
detection in its parent.

Generated by bin/rename-packages.sh.
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, you can upgrade your account or add credits to your account and enable them for code reviews in your settings.

Master moved a long way under this branch, and most of what it moved was this
branch's own subject matter. Resolving the merge honestly leaves a one-file
deletion, so the resolutions are recorded here rather than left to be inferred
from a 37-conflict merge.

Superseded on master, taken from master wholesale
-------------------------------------------------------------------------------

- `.github/workflows/claude.yml` - #287 landed a superset of this branch's
  grant: the same curated allowlist as the dispatch route (REVIEW_TOOL_ALLOWLIST),
  a trusted-author gate, a fork carve-out, a 30-minute cap and `refresh-gate`.
  It also SETTLED this branch's stated open question - the action checks the PR
  branch out over master's checkout, so the granted scripts run against the PR's
  tree. Master's fork handling differs by design: it withholds the allowlist and
  still answers, where this branch refused the run outright.

- `docs/quarantined-tests.md`, `bin/check-quarantine-owners.sh`,
  `bin/quarantine-lane-report.sh` - the qualified `Owner: PR astubbs#NN` marker
  this branch introduced is already on master via #288, parsers and
  registry prose included.

- `docs/inflight/test-untracked-ci-flakes.md` - master's copy is a strict superset:
  it carries this branch's `PCMetricsTest` diagnosis and its "quarantined and
  removed again, the diagnosis was wrong" note about the backpressure test, plus a
  `ProducerManagerTest` entry, the rule-1 exception and a citation repair this
  branch predates.

- `docs/inflight/ci-review-agent.md` - rewritten by #287 around the
  two-route model. Two of this branch's entries are now stale rather than merely
  older: `actionlint` IS granted, and "which tree does it run against" is answered.

The quarantine this branch added is dropped, not re-resolved
-------------------------------------------------------------------------------

`PCMetricsTest.metricsRegisterBinding` was quarantined here naming #265 as
`fixedBy`. #265 has since MERGED, and it fixed this test causally: the
`Thread.sleep(1000)` between the counter snapshot and the gauge read - which is the
exact mechanism the quarantine reason describes - is now an
`await().untilAsserted(...)` requiring the trailing meters to agree with the
counters before the snapshot is asserted. #265 deleted the annotation and
the registry entry in the same commit, per rule 3.

Re-applying the entry would therefore be a hard failure, not a judgement call:
`bin/check-quarantine-owners.sh` errors on a merged owner whose test is still
quarantined ("re-enable overdue"). And a *fresh* sighting would need a fresh
diagnosis under rule 1 - the old reason no longer describes code that exists.
No such sighting: master's gating CI has been green on every run since
#265 merged on 2026-08-13.

If it flakes again, re-quarantining is the inverse of that commit, as #265's
own message says - a new entry with a new diagnosis, not this one restored.

Rename/rename, and the mis-pairing AGENTS.md warns about
-------------------------------------------------------------------------------

Both sides had run `bin/rename-packages.sh` independently, so the tree conflicts
were rename/rename and resolved to master throughout - this branch's Java delta was
the quarantine annotation and nothing else. The predicted cross-module mis-pairing
did surface: git paired the STREAMS module's `TestConventionsArchTest.java` against
the METRICS module's. Asserted after resolution - all six arch tests present, one
per module, and no `io/confluent` path left in the index.

Verified: `bin/check-quarantine-registry.sh` (2 entries, consistent) and
`bin/check-copyright-headers.sh` (241 files, 0 violations) both clean.
Two sharp edges on the review routes, one fixed and one recorded because its fix
is a user-facing decision rather than a tightening.

`bin/todo-index.sh` was granted without its argument
-------------------------------------------------------------------------------

Both allowlists carried `Bash(bin/todo-index.sh:*)`. Bare, that script does not
report - it REGENERATES `docs/todo-index.md` (`generate > "$OUT"` on its main
path). So the reviewer was permitted to modify the working tree it had been
asked to inspect, and any diff it reported afterwards was partly its own work.

That is precisely the false-confidence class the allowlist exists to prevent,
arriving through the allowlist itself: a reviewer that cannot tell its own edit
from the PR's is worse than one that cannot run the script at all, because its
output still reads as a finding.

Granted now as `Bash(bin/todo-index.sh --check:*)` (both bare and `./` forms, per
the as-written matching rule already documented there). `--check` is the
read-only mode the script documents, and it answers the only question a reviewer
has: is the committed index stale? Nothing else about the grant changes.

It also makes an adjacent claim true again. The dispatch workflow's comment calls
this family "fast, read-only VERIFICATION scripts" and names
`bin/test-check-docs-data.sh` as "the one grant that writes", flagged as a
considered exception. That was false while todo-index.sh was granted bare - there
were two, and only one was disclosed.

Applied to BOTH files, which is what their own `KEEP IN SYNC` note requires:
`.github/workflows/claude.yml` (REVIEW_TOOL_ALLOWLIST) and
`.github/workflows/claude-code-review-dispatch.yml` (`--allowedTools`).

Prior art, as the PR-discipline rule asks: the defect class is "a grant whose
default mode mutates". Swept the rest of both lists for it. `bin/check-*.sh` and
`bin/test-check-*.sh` are the two read-only guard prefixes by convention;
`bin/test-check-docs-data.sh` writes and restores through a trap and is already
disclosed; the `ci-*-test.sh` wrappers and `./mvnw` write only to `target/`; the
`gh` and `git rev-parse` grants are read-only. `bin/todo-index.sh` was the only
undisclosed writer.

Recorded, not fixed: writing about the trigger fires the trigger
-------------------------------------------------------------------------------

`claude.yml` matches on `contains(github.event.comment.body, '@claude')` - a plain
substring test that does not know about backticks, code fences or quotation - so
a comment DISCUSSING the mechanism starts a billed job.

Observed rather than theorised, on #286 itself: two review replies
explained the trust model and quoted the trigger string in backticks, and exactly
two `Claude Code` runs fired on `pull_request_review_comment` and ran to
completion. One-to-one with the two replies containing it.

Harmless while the fallback route could execute nothing. Not harmless now that it
carries the curated allowlist: an unasked-for start costs a runner and a
token-bearing job. The fix is cheap - `startsWith` on the trimmed body - but it
would stop a mid-sentence mention working, which is a user-facing semantics
change and therefore the repository owner's call. Filed in
`docs/inflight/ci-review-agent.md` with that framing rather than applied.

Verification
-------------------------------------------------------------------------------

Both workflows parse (`yaml.safe_load`), and `bin/check-issue-refs.sh` is clean.
`actionlint` is NOT installed on this machine and is Ansible-managed, so it was
not run locally - the `workflows: action versions` lane covers it.
@astubbs astubbs changed the title ci(review): let the fallback reviewer run the gates, and quarantine two flakes ci(review): stop the reviewer rewriting the tree it is inspecting Aug 17, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2f3272be48

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread .github/workflows/claude.yml Outdated
Comment thread docs/inflight/ci-review-agent.md Outdated
…well as the allowlist

Review feedback on #286. The previous commit narrowed
the reviewer's `bin/todo-index.sh` grant to `--check` and left the hole open.

`Bash(bin/todo-index.sh --check:*)` is a PREFIX grant
-------------------------------------------------------------------------------

`:*` is the trailing-wildcard form, so `bin/todo-index.sh --check=false` matched
the "restricted" grant. The script's `[[ "${1:-}" == "--check" ]]` test then did
NOT equal `--check=false`, left CHECK_MODE false, took the `generate > "$OUT"`
branch and exited 0 - rewriting the tree the reviewer was inspecting, which is
exactly what the narrowing was for.

Reproduced before and after, rather than argued:

    $ echo MARKER >> docs/todo-index.md
    $ bin/todo-index.sh --check=false ; echo $?
    0                      # before: marker gone, file regenerated
    2                      # after:  usage: bin/todo-index.sh [--check]

Fixed on both sides, because they are independently wrong
-------------------------------------------------------------------------------

1. The grant is now EXACT - `Bash(bin/todo-index.sh --check)`, no `:*` - in
   `.github/workflows/claude.yml` and `.github/workflows/claude-code-review-dispatch.yml`,
   which carry an explicit KEEP IN SYNC contract. It is the only entry in either
   list without a trailing wildcard, so both comments now say so and say not to
   "tidy" it back for consistency with its neighbours.

2. `bin/todo-index.sh` REJECTS UNKNOWN ARGUMENTS instead of silently ignoring
   them, exiting 2 (1 stays "the index is stale"). This is the half that matters:
   an allowlist string in two workflow files is not where a guarantee should
   live, and the script is reachable by routes no allowlist governs. Verified
   that `--check=false`, `--check=true`, `--Check`, `-c` and `--check extra` are
   all refused, while `--check` and the bare regenerate mode still work.

An allowlist-only fix would have been a fix to the exploit, not to the class:
any future prefix-shaped grant of any argument would reopen it.

Also here: the duplicated default-branch rule
-------------------------------------------------------------------------------

`docs/inflight/ci-review-agent.md` gained a "Related trap" paragraph restating
that comment-triggered workflows run the default branch's copy - a fact the same
file already states in its comment-route entry, and which `docs/ci.md` owns under
"Editing the reviewer". Replaced with a pointer naming that owner, keeping only
the consequence specific to the trigger entry: the tightening cannot be exercised
on the PR that makes it. Repo rule is never to state a fact twice.

Verification
-------------------------------------------------------------------------------

Both workflows parse; `bin/check-shell-sigpipe.sh`, `bin/check-issue-refs.sh`,
`bin/check-copyright-headers.sh` and `bin/todo-index.sh --check` all clean.
`shellcheck` and `actionlint` are not installed on this machine (Ansible-managed);
the Repo Hygiene and action-version lanes cover them.
@astubbs

astubbs commented Aug 17, 2026

Copy link
Copy Markdown
Owner Author

When the fallback reviewer invokes bin/check-quarantine-owners.sh, the script runs git fetch --depth=1 origin "$base" and fetches pull/$pr/merge [...] This grant therefore reaches the network outside gh reads and mutates the checkout's FETCH_HEAD/shallow state inside the secret-bearing job

Leaving this one open for a decision — it is valid, it is live on master, and it also falsifies a claim I made in this PR.

Confirmed. bin/check-quarantine-owners.sh fetches twice and reads through FETCH_HEAD:

114:  if ! git fetch --quiet --depth=1 origin "$base" 2>/dev/null; then
125:  if ! git fetch --quiet --depth=1 origin "pull/$pr/merge" 2>/dev/null; then

It violates a written rule. bin/AGENTS.md says, of the check-*.sh / test-check-*.sh prefixes: "do not give that prefix to a script that writes, publishes, deploys, or reaches the network beyond gh reads." This script has the prefix and reaches the network. bin/check-cve-exclusions.sh has one networked line too and wants the same look.

Why it survived this PR. The branch originally dropped the enumerated grant for it (commit 427ed83d2), but that commit was superseded when the branch merged master, where the grant is the pattern Bash(bin/check-*.sh:*). The pattern re-covers the script, so the finding survives in a form the old fix no longer addresses.

It makes my own commit message wrong. 2f3272be4 claims a same-defect sweep concluding "bin/todo-index.sh was the only undisclosed writer." That is false — this one mutates repository state and reaches the network. I have corrected the claim in the PR body; the commit message stands as written since rewriting it needs a force-push.

Why I am not just fixing it: every option changes something outside this PR's scope.

  • (a) Refactor the script to drop the fetch. Cleanest against the rule, but the fetch is load-bearing — it is how the check inspects the owning PR's merge preview to see whether the quarantine annotation is actually removed. Removing it removes the capability.
  • (b) Rename it out of the granted prefix (e.g. bin/quarantine-owner-audit.sh). Honest and cheap to reason about, but it is referenced from docs/quarantined-tests.md, AGENTS.md, workflows and its own self-test, so it is a rename with a citation sweep.
  • (c) Accept and document it as a second considered exception, alongside bin/test-check-docs-data.sh. Least work; weakens the prefix rule to "read-only, except the ones we listed", which is how the rule stops being checkable.
  • (d) Enumerate an explicit deny — not available: --allowedTools has no deny form, so this would mean abandoning the pattern grant and enumerating every guard by hand, which the dispatch workflow's comments argue against at length.

My lean: (b). It keeps the prefix rule literally true — which is what makes it enforceable by a future bin/-wide check — without giving up what the script does. It is also the only option that fixes bin/check-cve-exclusions.sh by the same move.

Out of scope for this PR either way: it is a pre-existing master defect, not something this change introduced.

astubbs added a commit that referenced this pull request Aug 17, 2026
…t the evidence it contradicted

Review feedback on #304, plus a live defect the second
finding uncovered.

The closed entry was still a narrative
-------------------------------------------------------------------------------

docs/inflight/AGENTS.md says not to rewrite a closed item into a "FIXED/DONE"
narrative, and to shrink the file to its open follow-ups. The first commit closed
`PCMetricsTest.metricsRegisterBinding` with an eight-line bullet carrying the
mechanism, the generalised rule and a cross-reference - next to a three-line one
for #260. That is the shape the rule forbids, however accurate it is: an
agent scanning for current work still meets the test as though it were live.

Now four lines: what fixed it, the rule it satisfied, and a pointer. The
generalisation is NOT restated here - it already lives in
`docs/solutions/test-flakiness/assert-the-commit-frontier-not-the-tick-path.md`,
which cites it and observes that a ledger row was the wrong place to keep it.
Deleting the restatement closes the loop that write-up opened instead of leaving
the rule in two places to drift.

The retained "Controls for these flakes" section no longer leans on the closed
entry to justify itself. It is method for the two tests still open - the void
control (a green push-to-master proves nothing; the unit lane is
`pull_request`-only) and the working one - and now says so directly.

`docs/data/testing-evidence.yaml` was contradicting the registry it cites
-------------------------------------------------------------------------------

Found while answering the same reviewer on #286, where
it was raised against a quarantine entry that PR no longer adds. The
contradiction is real on master regardless:

    current_status: Empty - no test carries the annotation ...
    $ bin/check-quarantine-registry.sh
    Quarantine registry consistent (2 entr(ies), method-granularity checked).

Two tests are held out of the gating lane - ProducerManagerTest and
OffsetEncodingBackPressureTest - while the published evidence says the mechanism
is unused. This file feeds release evidence and module-maturity claims, so it was
overstating the suite's health in the one direction that matters.

The fix is deliberately NOT a corrected count. That is what rotted: the field was
true when written and nothing updates it when a test is quarantined or
re-enabled, so a number would rot identically on the next change. It now names
the registry as the live list and the only accurate count - which is what this
block's own comment already demanded ("Do not restate them here; they would
drift, and this file would then contradict the document it is citing as
evidence"). `meaning` loses its "currently unused" clause for the same reason.

Verification
-------------------------------------------------------------------------------

`bin/check-docs-data.sh` (39 files structurally valid), a YAML parse of the
evidence file, and `bin/check-issue-refs.sh` all clean. `current_status` has no
consumer other than this file, so the wording change breaks no renderer.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 501998ce0d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread .github/workflows/claude-code-review-dispatch.yml
Comment thread bin/todo-index.sh
…-fix

Review feedback on #286: the previous commit closed a
permission-boundary bug in `bin/todo-index.sh` and left nothing to stop it
reopening. A repo-wide search finds no self-test for the script at all, and CI
exercised only the valid `--check` path - so both a parser relaxation and a
restored `:*` in either allowlist would go green.

bin/AGENTS.md requires the case, and requires it to have failed:
"a regression test that has never failed proves nothing".

What it pins
-------------------------------------------------------------------------------

`bin/test-todo-index.sh`, run from `pr-checklist.yml` immediately BEFORE the
`bin/todo-index.sh --check` gate it protects, per the same doc. Nine cases:

- `--check` on a current index passes; on a stale one reports 1 and rewrites
  nothing; bare regenerates. The valid paths, so a test that fails everything is
  distinguishable from one that fails the right thing.
- `--check=false`, `--check=true`, `--Check`, `-c` and `--check extra` are each
  refused with exit 2 AND leave the index untouched. Both halves are asserted:
  the exit code proves the argument was rejected, the sentinel proves the
  rejection happened before the regenerate branch.
- Both workflows grant the EXACT command, and neither carries a wildcard
  todo-index grant. This is the half a parser fix cannot cover: `:*` restored to
  either allowlist "for consistency" with its wildcard-bearing neighbours
  reopens the hole from the other side. The wildcard assertion reads grant lines
  only, since both files discuss the old forms in prose deliberately.

Red before the fix, and only where it should be
-------------------------------------------------------------------------------

Checked out `bin/todo-index.sh` and both workflows from 2f3272b (the revision
whose grant was `Bash(bin/todo-index.sh --check:*)`) and ran it:

    ok:   --check on a current index passes
    ok:   --check on a stale index reports stale and does not rewrite
    ok:   bare invocation regenerates the index
    FAIL: --check=false is refused and does not rewrite (expected '2 untouched', got '0 REWRITTEN')
    ...
    9 assertion(s) failed

`0 REWRITTEN` is the vulnerability stated as a test result: the allowed command
regenerated the tree and reported success. The three valid-path cases still pass
against that revision, so the failures are the boundary and not the harness.

Safety of running it in the real checkout
-------------------------------------------------------------------------------

Case 3 has to regenerate `docs/todo-index.md` to be worth anything, so the test
backs the file up, restores through an EXIT trap, and refuses to start if the
index already has uncommitted changes. Because CI runs it immediately before the
`--check` gate, a silently failed restore would leave that gate inspecting a file
this test had regenerated - which would pass by construction. So the restore is
asserted (`cmp` against the backup) rather than assumed.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6a007ae1f5

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread bin/test-todo-index.sh Outdated
Review feedback on #286. The self-test added in
6a007ae pinned the todo-index grant against only the bare `bin/...` spelling,
so half the permission contract was unguarded.

A permission rule matches the command AS WRITTEN, which is why both workflows
grant `bin/todo-index.sh --check` and `./bin/todo-index.sh --check` separately -
the dot-prefixed invocation does not match the bare grant. Both predicates in the
test recognised only `Bash(bin/todo-index.sh...)`, so removing or wildcarding
just the `./` grant left every assertion green.

Both spellings are now asserted independently, exact-grant and no-wildcard. Both
mutations verified to fail, and to fail ONLY on the spelling mutated:

    # ./bin/ grant deleted from claude.yml
    FAIL: claude.yml grants the exact './bin/todo-index.sh --check' command

    # ./bin/ grant changed to :*
    FAIL: claude.yml grants the exact './bin/todo-index.sh --check' command
    FAIL: claude.yml has no wildcard './bin/todo-index.sh' grant

The bare-spelling assertions stay green through both, which is what shows the two
are independent rather than one predicate matching both by accident - the literal
`Bash(` prefix is what stops `bin/` also matching `./bin/`.

17 assertions, all passing on the fixed tree.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 646ecc62c8

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread bin/test-todo-index.sh
Comment thread docs/inflight/ci-review-agent.md Outdated
Comment thread .github/workflows/claude.yml
Comment thread bin/test-todo-index.sh Outdated
…track the networked checker

Review feedback on #286. Two real gaps, both in work this
PR added.

The grant assertion tested the wrong invariant
-------------------------------------------------------------------------------

It asked whether a wildcard rule existed whose text STARTED WITH the todo-index
spelling. A broader neighbour re-covers the bare script without ever mentioning
it: `Bash(bin/*.sh:*)` or `Bash(*:*)` would let the reviewer run the rewriting
form again while every literal-spelling assertion still reported absent. The
dispatch workflow's own allowlist comment names `Bash(bin/*.sh:*)` as precisely
that hazard, so it was documented and untested.

The assertion is now the actual security property: parse every `Bash(...)` rule on
the grant line and require that NONE of them permits the bare command, in either
spelling. Trailing-wildcard rules are matched as prefixes and plain rules exactly,
with the pattern left unquoted so `*` globs the way the rules themselves do. When
it fails it names the offending rule.

Verified against three mutations, each caught:

    Bash(bin/*.sh:*) added   -> permits no rule matching the bare 'bin/todo-index.sh' ... got 'bin/*.sh:*'
    Bash(*:*) added          -> both spellings fail, got '*:*'
    ./ grant wildcarded      -> exact-grant and bare-permission assertions both fail

The new invariant subsumes the old one, so nothing is lost by replacing it.

"Now tracked" was not true
-------------------------------------------------------------------------------

The previous commit said the pre-existing `bin/check-quarantine-owners.sh`
network/FETCH_HEAD problem was left open and "now tracked". The only record was a
PR comment. docs/inflight/AGENTS.md is explicit that known problems belong in that
directory precisely because the next session scans it and will not read every PR
comment, so the claim was false in the way that matters.

Added docs/inflight/ci-networked-checker-in-reviewer-grant.md with the evidence,
the three options, the lean (rename), why an explicit deny is unavailable, and a
delete-when condition.

It also corrects a false claim that reached the PR description:
`bin/check-cve-exclusions.sh` does NOT reach the network. Its `curl` is inside
`cat <<'REPRO'`, printed as remediation guidance and never executed - a naive
`grep curl` says otherwise, which is how it got asserted. A heredoc-aware sweep of
every granted `check-*.sh`/`test-check-*.sh` finds `check-quarantine-owners.sh` to
be the only instance.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ca0d18f75e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread .github/workflows/claude.yml Outdated
Comment thread docs/inflight/ci-review-agent.md Outdated
…r defect its own note

Review feedback on #286. Both findings are about where
this PR put its words, not what it changed.

Four copies of one explanation
-------------------------------------------------------------------------------

The `--check=false` mechanism was written out at length in `claude.yml`,
`claude-code-review-dispatch.yml`, `bin/todo-index.sh` and `bin/test-todo-index.sh`
- plus twice more inline in the test. Six near-identical passages that a future
change has to keep synchronised, when only the allowlist VALUES genuinely need
duplicating. AGENTS.md forbids stating a fact twice precisely because the copies
drift, and separately warns that a rule needing several paragraphs to defend
itself is a rule that needs rewriting. Both apply.

`bin/todo-index.sh`'s header is now the single owner - it is the parser that
enforces the boundary, and AGENTS.md names an enforcing script's own header as a
legitimate home for the detail. The two workflows keep a short local warning: the
grant is exact, a wildcard reopens a tree-rewrite hole, do not tidy it to match its
neighbours, full reasoning over there. The self-test's header says what each case
asserts and defers the why.

The local warnings are deliberately not bare pointers. A reader about to "tidy"
the odd-looking entry needs the consequence at the point of temptation; what they
do not need is the incident retold three times.

A distinct defect inside an omnibus note
-------------------------------------------------------------------------------

The trigger-substring problem went into `docs/inflight/ci-review-agent.md`, which
already tracks many unrelated reviewer gaps. docs/inflight/AGENTS.md is explicit
that the directory is one item per file, and that the prefix is the point: an
agent listing the directory should see the shape of what is open without reading
anything. Buried in an omnibus, the item is invisible to that listing, and any
future work on it collides with unrelated edits to the same file.

Moved to `docs/inflight/ci-claude-trigger-fires-on-prose.md` with its own
delete-when condition. `ci-review-agent.md` keeps a two-line cross-reference so a
reader arriving from the reviewer's gap list still finds it.

Verification
-------------------------------------------------------------------------------

bin/test-todo-index.sh (17 assertions), bin/check-shell-sigpipe.sh,
bin/check-copyright-headers.sh and bin/check-issue-refs.sh all clean; both
workflows parse.
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, you can upgrade your account or add credits to your account and enable them for code reviews in your settings.

astubbs added a commit that referenced this pull request Aug 17, 2026
… a measurement

`ci-disabled-jobs-and-runner-load.md` asked whether highcpu jobs still die of
runner-lost-communication, and said to re-check before spending anything on a
shared concurrency group. Chasing a red Chaos Pain Suite on #286 produced
the answer, so it is recorded rather than left as an open question a second time.

They still do. In one ~30-minute window the highcpu workflow failed on three
unrelated branches - ci/claude-yml-script-grant, fix/concurrent-listener-registration
and docs/inflight-note-currency - while succeeding on two of those same branches
minutes either side. Unrelated branches failing together with interleaved successes
is master-state under rule 2; no PR's diff explains it, and two of the three had no
Java in them at all.

The signature is the one the entry already names, and it is not a test failure. In
run 32010207847 the `Chaos Pain Suite tests` step's log stops dead at 08:34:16
mid-scenario, the step does not complete until 08:40:40, and it fails with no
BUILD FAILURE, no stack trace and no ##[error]. The process was killed; it did not
report anything. That is what makes this class expensive: a reader grepping the log
for a failing test finds nothing at all, and the natural next move is to suspect
the PR.

Also recorded, because it changes what the fix would have to address: several agent
sessions were building against the same box concurrently. The load is not only CI's,
so a shared concurrency group across workflows would only bound part of it.

No action taken on the lane itself - Chaos Pain Suite is deliberately non-gating, so
a red there is a finding rather than a merge blocker.
@astubbs astubbs changed the title ci(review): stop the reviewer rewriting the tree it is inspecting fix(review): close the todo-index grant that let the reviewer rewrite the tree Aug 18, 2026

@astubbs astubbs left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

lgtm

@astubbs astubbs left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

lgtm

@astubbs
astubbs merged commit 27138e5 into master Aug 18, 2026
48 of 51 checks passed
@astubbs
astubbs deleted the ci/claude-yml-script-grant branch August 18, 2026 01:54
astubbs added a commit that referenced this pull request Aug 18, 2026
…ions

Master landed #310's ranked revival of the 2022 micro-actor family the
same day this branch wrote up the interrupt-overload finding, and the two were
not pointed at each other.

Forward: this branch's design read as greenfield - "add a nudge variant" - when
a framework already exists, 537 lines in 4 files coupled to PC by one 16-line
marker interface, with six ranked directions for reviving it. Both the solution
write-up and the contract-debts note now say to read next-actor-revival.md
first, and name survivor 5 (skeleton-first strangler) as the shape a
payload-free nudge should land in rather than a rewrite.

Back: survivor 6 is a concurrency mass budget - an ArchUnit ratchet on
primitive counts, conversions graded on locks removed - and this branch has
already taken a reading it can start from. Four meanings on one bit, four
hand-clears, one of which does not clear and only warns that it cannot tell
which meaning it got. That is a mass measurement with a documented failure
behind it, which is more useful to a ratchet than a count taken cold.

Also merges master: #310 and, in the previous merge, #304,
#305, #307, #286 and #312.

Core unit suite: Tests run 372, Failures 0, Errors 0, BUILD SUCCESS.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013ahSzHD72EvTGTYkmpTsx6
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