Skip to content

Choose which bots review which project - #57

Merged
kristofferR merged 19 commits into
mainfrom
feat/per-repo-reviewers
Jul 27, 2026
Merged

Choose which bots review which project#57
kristofferR merged 19 commits into
mainfrom
feat/per-repo-reviewers

Conversation

@kristofferR

@kristofferR kristofferR commented Jul 26, 2026

Copy link
Copy Markdown
Owner

Roadmap item H, and the request that started this refactor: "which bots you want for which project
should be much easier to set up."

Reopened against main — the original PR (#52) was closed automatically when its base branch was
deleted on merging #51. Same branch, rebased onto main, all review threads on it already resolved.

crq reviewers kristofferR/some-repo                                  # who runs here, and what each costs
crq reviewers set kristofferR/some-repo --bots codex --required codex
crq reviewers clear kristofferR/some-repo

Each reviewer reports its budget: account is serialized against the shared CodeRabbit allowance,
none runs immediately and waits for nobody. That is the only property the queue cares about.

It lives in the shared state ref, not a committed .crq.yaml: the daemon has no checkout of the
repositories it reviews, and a daemon and an agent reading different configurations while writing one
state ref is a new class of divergence.

The primary stays fleet-wide. Its markers are compiled into the dialect classifiers when the
Service is built, so a per-repo primary would mean per-repo classifiers.

What review changed

Thirteen findings on the original PR, six of them P1, all resolved:

  • The override could only ever subtract — with CRQ_COBOTS=codex, asking a project for Bugbot was
    rejected as unknown. Choices resolve against the registry now, and required implies enabled.
  • A retained co-reviewer promoted to required kept its never trigger, so the round waited for
    evidence no command was ever posted for.
  • A registry-bot primary lost its silenced entry through an override, costing the primary its
    wording and check-run hooks.
  • Autoreview decided from the primary alone, so a repo requiring Codex whose head CodeRabbit had
    already reviewed was never enqueued.
  • Changing the required set on a head with a completed round stranded the PR. It is reopened now —
    and safely, because DecideFire's already-reviewed gate counts a completion reply paired to the
    round's command, not only a submitted Review object.
  • A repo enabling a bot the fleet disabled was built from registry defaults, discarding the
    operator's CRQ_COBOT_<NAME>_* settings.
  • Capabilities are recorded per process, so a new CLI cannot vouch for an old daemon on the same
    machine — and crq reviewers names any host driving the queue that predates overrides.
  • applyFire revalidates the override before acting, so a reviewer removed mid-decision is not
    triggered anyway.

gofmt -l . clean, go vet ./... clean, go test ./... -count=1 green.

Ref #42

Summary by CodeRabbit

  • New Features
    • Added repository-specific reviewer routing, including crq reviewers commands to view, set, or clear overrides.
    • Supports per-project required reviewers and reviewer budgets, with effective reviewer sets reflected in queue behavior.
  • Bug Fixes
    • Reduced duplicate posts by improving “already completed” detection and dedupe behavior.
    • Requeue behavior now better respects reviewer changes while handling held fire slots and primary acknowledgement.
  • Documentation
    • Updated command and configuration docs for reviewer routing, requiredness, and fleet-default behavior.

The reviewers were a property of the process: one CRQ_COBOTS for every
repository the fleet touches. A repo that only wants Codex, or one where
Bugbot should gate, had no way to say so — and the answer to "which bots
do you want here" was to edit a global env file and restart a daemon.

crq reviewers <repo> now reports who runs there and what each one costs;
crq reviewers set chooses them; crq reviewers clear goes back to the
fleet default. Each reviewer reports its budget, which is the only
property the queue cares about: account is serialized against the shared
CodeRabbit allowance, none runs immediately and waits for nobody.

The configuration lives in the shared state ref rather than a .crq.yaml
the repository carries. The daemon has no checkout of the repositories it
reviews, so an in-repo file would be invisible to it or cost a REST fetch
per PR — and a daemon and an agent reading different configurations while
writing one state ref is a class of bug worth not having.

The override reaches the derived views, not just the stored list: after
applying it, Reviewers, RequiredBots and FeedbackBots are rebuilt exactly
as LoadConfig builds them, so crq cannot gate on or surface findings from
a bot the repository excluded. "Chosen to be none" is kept distinct from
"not chosen".

The primary stays fleet-wide. Its markers and command are compiled into
the dialect classifiers when the Service is built, so a per-repo primary
means per-repo classifiers.
Eight review findings, two of them P1.

Choices resolved against the fleet's enabled list, so the feature could
only ever subtract: with CRQ_COBOTS=codex, asking a project for bugbot
was rejected as unknown though it is a registered reviewer. They resolve
against the registry now, and a bot the fleet does not enable is built
from its registry entry. Naming a bot in --required enables it too, the
rule fleet parsing already follows — one that gates but is never
triggered waits forever.

A primary that is itself a registry bot keeps its silenced entry through
an override. That entry carries its wording and check-run hooks, so
dropping it costs the PRIMARY its evidence and the round waits out a
clean result crq can no longer read. Same defect as the fleet path had,
one layer up.

A second call naming one half no longer wipes the other: the existing
override is loaded and merged, which is what the nil-versus-empty
contract promised. An empty --required is refused, because gating on
nobody makes Feedback converge before any chosen reviewer runs, and
clear takes no mutation flags — ignoring them turned a malformed call
into a silent wipe.

The Codex-only degrade is gated on Codex being a reviewer here, or an
unsolicited auto-review would release the head during an account block
on behalf of a bot the project excluded.

And sharing a ref only stops an old binary ERASING the field; it does not
make it act on one. State now records which hosts write it and what they
understand, and `crq reviewers` names any host driving the queue that
predates overrides, instead of implying agreement.
Nine review findings, four of them P1, and they converge on one mistake:
the override changed who has to answer without changing who gets asked.

`--required bugbot` with no `--bots` set the required half only, so
nothing enabled Bugbot and it became an unknown reviewer with no command.
Required now implies enabled whichever half was named, the rule fleet
parsing already follows. A retained co-reviewer that becomes required is
promoted out of a never trigger for the same reason — Codex's fleet entry
is never while it is optional, so keeping that entry and flipping only the
Required bit left the engine waiting for evidence no command was posted
for. Only a never trigger is promoted, so a deliberate selfheal survives.

Autoreview decided from the primary alone, so a repo requiring Codex whose
head CodeRabbit had already reviewed was never enqueued and Codex was
never asked. It evaluates the repository's own required set now.

And changing the requirements on a head with a completed round stranded
the PR outright: convergence reported the new reviewer pending while
enqueue kept skipping the head, because a completed round IS the dedup
marker. Those rounds are reopened when the required set actually changes.

Three more. The two halves are merged inside the CAS closure, or two
hosts setting different halves both derive from one snapshot and the later
write drops the other's. An explicit CRQ_FEEDBACK_BOTS survives an
override, since it is the one list an operator may widen beyond who
reviews. And the lagging-host check now matches the leader's "host=x
pid=n" form against the host key capabilities are recorded under —
otherwise every current-version daemon read as needing an upgrade.

The docs no longer call the Codex example Codex-only: an override chooses
the co-reviewers, so the primary is still triggered and still spends
quota. Leaving it out of --required means the round does not wait for it.
Three of four findings; the fourth is answered rather than fixed.

`crq reviewers owner/repo --bots codex` is a set command missing its
verb. It showed the configuration and exited 0, which tells automation
the mutation worked when nothing changed. It is refused now, naming the
verb.

`crq reviewers clear owner-repo` cleared a key nothing uses and exited 0,
so a typo left the real override in force while the caller believed it
had restored the fleet default. Clear validates the shape set already
validates.

On the fourth: reopening a completed round can re-ask a primary that
finished with a completion reply and no Review object, because
DecideFire's already-reviewed gate reads submitted reviews. Marking the
round co-only does not help — that flag records what a fire DID, it does
not gate one — and the alternatives all need an observation the CAS
closure cannot make. So the trade is stated in the code: one duplicate
review in an uncommon case, against a PR stranded silently and
permanently. The loud failure is the better one, and the gate is where a
real fix belongs.
Four P1s, and the first retires a trade-off I had argued for instead of
fixing.

Reopening a completed round could re-ask a primary that answered with a
completion reply and no Review object, because the already-reviewed gate
read only obs.Reviews. The reviewer's point was that the gate is where
the fix belongs, and they were right: it now also counts a completion
reply paired to that round's own command. Reopening no longer risks a
duplicate review, so the round can be requeued when the required set
changes without the cost I had written into a comment.

A repository enabling a bot the fleet disabled was built from registry
defaults, silently discarding the operator's CRQ_COBOT_<NAME>_CMD,
TRIGGER and GRACE — a different bot than the one configured. Every
registry co-reviewer is now resolved with the environment applied,
enabled or not, and an override picks from that.

Capabilities are keyed per PROCESS rather than per host. A new CLI and an
old daemon on one machine is the ordinary upgrade, and a per-host key let
the CLI's write vouch for the daemon that had not been upgraded — hiding
exactly the case the signal exists to catch.

And applyFire revalidates the override before acting. Deciding and
writing are two steps, so an operator removing a co-reviewer between them
would otherwise have crq post that bot's trigger on the authority of a
configuration that no longer exists.
@coderabbitai

coderabbitai Bot commented Jul 26, 2026

Copy link
Copy Markdown

Review Change Stack

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 52c0d691-a310-43bb-99b5-8aff55995cce

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds repository-scoped reviewer overrides, persisted writer capability tracking, per-repository queue configuration, new crq reviewers commands, round reopening on reviewer changes, completion and slot-hold coordination, and documentation for reviewer selection and budgets.

Changes

Repository reviewer configuration

Layer / File(s) Summary
Persist overrides, writer capabilities, and slot holds
internal/state/*, internal/crq/state.go, internal/state/store.go
State stores repository overrides, writer capabilities, reopen markers, and compatibility-safe fire-slot holds.
Derive and manage effective reviewers
internal/crq/config.go, internal/crq/reviewers.go, internal/crq/repoconfig.go, internal/crq/*_test.go
Configuration resolves co-bots, applies repository overrides, validates selections, reports effective reviewers, and reopens or forces affected rounds.
Route decisions through repository configuration
internal/crq/service.go, internal/crq/auto.go, internal/crq/feedback.go, internal/engine/*, internal/crq/*_test.go
Queue decisions, feedback, firing, self-healing, incremental gating, completion evidence, and slot handling use repository-specific configuration with write-time revalidation.
Expose reviewer configuration commands
cmd/crq/main.go, README.md, llms.txt, skills/coderabbit-queue/SKILL.md, AGENTS.md
Adds show, set, and clear commands with parsing, help text, JSON output, reviewer semantics, and compatibility documentation.

Estimated code review effort: 5 (Critical) | ~90 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Operator
  participant CLI
  participant Service
  participant State
  participant Queue
  Operator->>CLI: crq reviewers set repo --bots codex --required codex
  CLI->>Service: SetReviewers(repo, bots, required)
  Service->>State: Store repository override
  Service->>Queue: Reopen affected rounds
  Queue->>Service: Process repository round
  Service->>State: Load effective repository configuration
  Service-->>Queue: Apply repository-specific reviewer policy
Loading

Possibly related issues

Possibly related PRs

Poem

A rabbit hops through queues of code,
With chosen bots along the road.
Required hops are marked just right,
Old rounds wake to join the fight.
“Reviewers set!” the bunny sings. 🐇

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 73.08% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly captures the main change: adding per-project reviewer bot selection and override controls.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/per-repo-reviewers

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@kristofferR

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 26, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@kristofferR

Copy link
Copy Markdown
Owner Author

@codex review

@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: 37d0bc2dcb

ℹ️ 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 internal/engine/fire.go Outdated
Comment thread internal/state/state.go
Comment thread internal/crq/repoconfig.go
Comment thread internal/state/state.go Outdated
@kristofferR

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 26, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@kristofferR

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 26, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@kristofferR

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 26, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@kristofferR

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 26, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

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

Actionable comments posted: 8

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@cmd/crq/main.go`:
- Around line 530-533: Update the reviewer budget description in cmd/crq/main.go
at lines 530-533 to remove the claim that budget "none" waits for nobody, while
retaining its meaning as no account serialization. Update
skills/coderabbit-queue/SKILL.md at lines 182-183 to state that --required
independently controls whether a reviewer gates convergence.
- Around line 535-537: Update the CLI help text describing --bots and --required
so the empty-value behavior applies only to --bots, while documenting that
--required rejects an empty reviewer list. Preserve the distinction between
selecting co-reviewers and choosing convergence-gating reviewers.
- Around line 365-368: The reviewer-setting documentation is inconsistent with
the handler’s partial-update contract because it requires --bots even when only
--required is supplied. Update cmd/crq/main.go lines 365-368, cmd/crq/main.go
lines 524-526, and README.md lines 388-390 to show --bots and --required as
independently optional while preserving the existing reviewers set behavior.
- Around line 774-777: Update the reviewers show-path validation around the repo
check to require the same valid owner/name repository shape enforced by
SetReviewers and ClearReviewers, rejecting malformed targets such as “show”
before calling Service.Reviewers. Preserve the existing usage error and return
behavior for invalid repositories.

In `@internal/crq/feedback.go`:
- Around line 91-92: Update the configured-bot checks in the feedback handling
flow at the remaining call sites around lines 192, 366, and 410 to invoke
isConfiguredBot on the repo-derived cfg rather than the fleet-level Config.
Preserve the existing login values and surrounding behavior while ensuring repo
override co-reviewers are recognized.

In `@internal/crq/repoconfig.go`:
- Around line 142-162: Move the CAS write closures used by SetReviewers and
ClearReviewers out of repoconfig.go into service.go, exposing Service methods
for repoconfig.go to call after validation. Ensure those apply-phase methods
check cfg.DryRun and perform no store.Update or other writes in dry-run mode,
while preserving the existing reviewer updates, timestamps, reopening behavior,
sync, and return results.
- Around line 143-156: Update SetReviewers around the store.Update closure to
detect when both coBots and required are nil and return ErrNoChange before
mutating the override or invoking st.SetRepoOverride, reopenForChangedReviewers,
or related syncs. Reuse the existing no-op guard pattern and preserve normal
updates when either reviewer setting is provided.

In `@internal/crq/service.go`:
- Around line 670-694: Scope the staleness guard in applyFire to only verdicts
that can post configuration-dependent actions: FireCoOnly, FireCoDeferred,
FireAdopt when PostCo is set, and FirePost when PostCo is set. Avoid calling
s.store.Load for FireNo and the other verdicts, while preserving the existing
overrideChanged check and handler behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: ef4c99ab-c722-4f32-b218-0fd636bd2fbf

📥 Commits

Reviewing files that changed from the base of the PR and between fbd4907 and 37d0bc2.

📒 Files selected for processing (19)
  • README.md
  • cmd/crq/main.go
  • internal/crq/auto.go
  • internal/crq/codex_replay_test.go
  • internal/crq/config.go
  • internal/crq/feedback.go
  • internal/crq/repoconfig.go
  • internal/crq/repoconfig_test.go
  • internal/crq/reviewers.go
  • internal/crq/reviewers_test.go
  • internal/crq/service.go
  • internal/crq/service_test.go
  • internal/crq/state.go
  • internal/engine/fire.go
  • internal/state/state.go
  • internal/state/store.go
  • internal/state/writers_test.go
  • llms.txt
  • skills/coderabbit-queue/SKILL.md
📜 Review details
🧰 Additional context used
📓 Path-based instructions (5)
internal/crq/**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

Keep internal/crq limited to orchestration and effects wiring; service.go is the only effects executor for CAS writes and PostIssueComment, and DryRun must write nothing.

Files:

  • internal/crq/state.go
  • internal/crq/codex_replay_test.go
  • internal/crq/reviewers_test.go
  • internal/crq/auto.go
  • internal/crq/service_test.go
  • internal/crq/feedback.go
  • internal/crq/repoconfig_test.go
  • internal/crq/reviewers.go
  • internal/crq/repoconfig.go
  • internal/crq/config.go
  • internal/crq/service.go
internal/state/**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

internal/state/**/*.go: Persist schema v3 with one Round per PR, one global FireSlot, AccountQuota, and an Archive; never delete rounds, and preserve unknown JSON members during round trips.
Model round lifecycle transitions as Round methods, reject illegal edges, and never delete a round; completed rounds remain deduplication markers, while rate-limited retries use awaiting_retry without deleting fired history.

Files:

  • internal/state/writers_test.go
  • internal/state/store.go
  • internal/state/state.go
internal/crq/config.go

📄 CodeRabbit inference engine (AGENTS.md)

Add a default entry in parseCoBots when a new co-reviewer should be enabled by default.

Files:

  • internal/crq/config.go
internal/engine/**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

internal/engine/**/*.go: Keep internal/engine pure: decision logic must receive now, perform no I/O, context, or GitHub access, and table-test every rule.
DecideFire must be the single fire owner and evaluate guards in order: open, readable/current head, eligible phase, primary review unavailable, already reviewed, free slot, account quota, minimum interval, then adopt/post.
Keep convergence, fire, and co-reviewer rules in internal/engine; keep orchestration in internal/crq, and table-test engine rules.

Files:

  • internal/engine/fire.go
internal/crq/service.go

📄 CodeRabbit inference engine (AGENTS.md)

The apply phase in service.go is the only place allowed to execute effects: CAS state writes and PostIssueComment; DryRun must report without writing.

Files:

  • internal/crq/service.go
🪛 LanguageTool
skills/coderabbit-queue/SKILL.md

[style] ~187-~187: To strengthen your wording, consider replacing the phrasal verb “leave out”.
Context: ... override chooses the co-reviewers. Leaving the primary out of --required means the round does not w...

(OMIT_EXCLUDE)

🔇 Additional comments (17)
cmd/crq/main.go (2)

214-219: LGTM!


814-827: LGTM!

llms.txt (1)

205-220: LGTM!

internal/state/state.go (1)

272-316: LGTM!

Also applies to: 318-428, 503-526

internal/state/store.go (1)

46-48: LGTM!

Also applies to: 215-215

internal/crq/config.go (1)

47-62: LGTM!

Also applies to: 199-211, 347-384, 418-447, 535-542

internal/crq/state.go (1)

26-27: LGTM!

Also applies to: 38-40, 57-57

internal/state/writers_test.go (1)

1-67: LGTM!

internal/crq/reviewers.go (1)

178-262: LGTM!

Also applies to: 264-281, 283-296, 298-308, 310-326, 328-340

internal/crq/service_test.go (1)

2364-2364: LGTM!

Also applies to: 2385-2385, 2398-2398

internal/crq/repoconfig_test.go (1)

1-241: LGTM!

internal/crq/reviewers_test.go (1)

228-278: LGTM!

internal/crq/auto.go (1)

296-362: LGTM!

internal/crq/feedback.go (1)

127-133: LGTM!

Also applies to: 159-160, 170-170, 449-453, 464-464

internal/crq/service.go (1)

301-308: LGTM!

Also applies to: 348-375, 403-412, 492-498, 632-641, 800-934, 985-1024, 1137-1165, 1268-1272, 1298-1302, 1336-1417, 1432-1470

internal/engine/fire.go (1)

160-168: 🎯 Functional Correctness

Correctly extends "already reviewed" detection to completion replies.

Sound addition and it preserves the required guard order (primary-unavailable → already-reviewed → free-slot → account-quota → min-interval).

Please confirm fire_test.go (not included in this batch) has a table-test case for this new completion-reply branch, per the engine guideline requiring every rule to be table-tested.

As per coding guidelines, "table-test every rule."

Source: Coding guidelines

internal/crq/codex_replay_test.go (1)

516-518: LGTM!

Comment thread cmd/crq/main.go
Comment thread cmd/crq/main.go Outdated
Comment thread cmd/crq/main.go Outdated
Comment thread cmd/crq/main.go
Comment thread internal/crq/feedback.go
Comment thread internal/crq/repoconfig.go
Comment thread internal/crq/repoconfig.go
Comment thread internal/crq/service.go
Ten findings across both reviewers; two are answered rather than fixed.

Changing a repository's required set requeued every completed round it
had. Rounds are never deleted, so a repository's merged and closed PRs
stay behind as completed dedup markers: on a busy repo that hands Pump
hundreds of dead rounds to observe and drop, one per tick, ahead of every
real one. A stranded PR is by definition an open one, so the requeue asks
GitHub which PRs are open first and touches only those.

Reopening also stamped LastAttemptAt, which is the adoption floor for a
FAILED attempt. Raising it discarded a newly required co-reviewer's own
unanswered trigger as too old to adopt, so crq posted that bot a second
request for the very round the reopen exists to let it answer.

The reopened round's already-reviewed gate read the ADOPTION helper,
which deliberately omits Completion's prior-review requirement and its
failed-summary guard — it answers "was this command spoken for", a
weaker question. A completion reply nothing backs would have written a
completed marker that every later same-head check skips, forever.

Capabilities are keyed per process, but a round recorded its bare
hostname, which no writer entry can match. Every `crq reviewers` call
during a fire therefore named the current process in lagging_hosts and
told the operator to upgrade a binary that already understands
overrides. The round now records the writer id; the dashboard still
prints the machine name.

applyFire re-read the state on EVERY verdict to revalidate the override,
including the FireNo no-op that is most of what a pump does — an extra
four API calls per tick against the git-backed store. Only the verdicts
that post a configuration-chosen command pay for it now.

Setting reviewers with neither half named wrote a fresh UpdatedAt
anyway, and that timestamp IS the override's identity, so a no-op call
discarded every in-flight fire decision for the repository. Reading a
repository now applies the shape check set and clear apply, so
`crq reviewers show` fails instead of reporting the fleet default for a
repository nobody has.

The help conflated budget with requiredness ("none ... waits for
nobody"), required --bots for an update the handler accepts with
--required alone, and offered an empty value for a flag that refuses
one.

Not fixed: feedback.go reading isConfiguredBot from the fleet config
rather than the repo's is identical by construction — the primary is not
overridable, so ForRepo never touches Config.Bot. And SetReviewers'
store.Update is an operator's explicit mutation, not the apply phase of
a review decision: Enqueue and Cancel write outside it too, and DryRun
means "request no reviews", not "silently ignore a configuration
command".
@kristofferR

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 27, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@kristofferR

Copy link
Copy Markdown
Owner Author

@codex review

@kristofferR

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 27, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@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: e09bfae29f

ℹ️ 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 internal/crq/service.go Outdated
Comment thread internal/crq/repoconfig.go
Comment thread internal/crq/repoconfig.go Outdated
A reviewer change requeues a repository's completed rounds, but three
paths let one slip through and leave the PR waiting on a bot crq never
asks.

A closed PR's round was skipped, and closed is not final: reopened at
the same head, its completed round is the dedup marker that hides the
requirement added while it was shut. Mark those rounds instead of
requeueing them — requeueing dead work would put it ahead of every live
round — and let whichever enqueue path next finds the PR alive reopen it.

FireDedupe was exempt from the apply-time revalidation because it posts
nothing. But its completed round asserts that everyone gating the head
has answered, and an override landing after the decision finds the round
still queued, so nothing requeues it. Revalidate dedupe too, and report
the refusal as the lost race it is rather than as a dedupe.

`crq reviewers <repo>` accepted "owner/", "/name" and "owner/name/extra".
The read path never contacts GitHub, so a typo printed the fleet default
and exited 0, reading as a report about a project crq follows.
@kristofferR

Copy link
Copy Markdown
Owner Author

@codex review

@kristofferR

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@kristofferR

Copy link
Copy Markdown
Owner Author

@codex review

@kristofferR

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 27, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@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: 770df01b1a

ℹ️ 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 internal/crq/service.go
Comment thread internal/crq/repoconfig.go Outdated
Comment thread internal/crq/reviewers.go
Comment thread internal/engine/progress.go
@kristofferR

Copy link
Copy Markdown
Owner Author

@codex review

@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: 330cf83e3f

ℹ️ 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 internal/crq/repoconfig.go
Comment thread internal/engine/completion.go Outdated
Comment thread internal/crq/service.go
@kristofferR

Copy link
Copy Markdown
Owner Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Delightful!

Reviewed commit: ae9badb9e5

ℹ️ 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".

@kristofferR

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 27, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@kristofferR

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 27, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@kristofferR

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 27, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@kristofferR

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 27, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

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

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
internal/engine/fire.go (1)

308-338: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add a coAwareDedupe/DecideFire table case for the forced co-reviewer gate.

Line 314's new || r.ForceCoReviewer(cp.Login) gate has no dedicated fire-rule test (only DecideCoPost's own unit test covers the force branch in isolation). A regression here — e.g. a forced co-reviewer being dropped from gates and silently deduped away when the primary already reviewed the head — wouldn't be caught by any existing table case.

As per coding guidelines, internal/engine/*_test.go: Table-test convergence and fire rules in engine_test.go. — a case with ForceCoReviewers set on a round whose primary already reviewed the head (asserting FireCoOnly/FireCoReviewWait rather than FireDedupe) would close this gap.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/engine/fire.go` around lines 308 - 338, The fire-rule table tests
need coverage for the forced co-reviewer gate in coAwareDedupe and DecideFire.
Add a case in the engine fire-rule table with ForceCoReviewers set for a round
where the primary has already reviewed the head, and assert the forced
co-reviewer produces FireCoOnly or FireCoReviewWait rather than FireDedupe.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@internal/crq/config.go`:
- Around line 541-557: Ensure the processRun initialization safely enforces an
8-character token before slicing randomToken’s result. Update randomToken or the
processRun assignment so the time-based fallback cannot produce a string shorter
than 8 characters, while preserving WriterID’s existing run identifier format.

In `@internal/crq/repoconfig.go`:
- Around line 88-94: Update the SetReviewers CAS closure to compare the merged
reviewer halves and their Set* flags with the stored override before writing;
when they are identical, return ErrNoChange so UpdatedAt and the override
identity remain unchanged. Preserve the existing no-op path for both unspecified
halves that returns s.Reviewers(ctx, repo), and only persist changes when the
reviewer configuration differs.

In `@internal/state/writers_test.go`:
- Around line 100-116: Strengthen TestReopenKeepsTheAdoptionFloor by
initializing r.LastAttemptAt to a non-nil timestamp before calling Complete and
Reopen. Keep the existing assertion, so the test verifies Reopen preserves the
seeded adoption floor rather than merely confirming it remains unset.

---

Outside diff comments:
In `@internal/engine/fire.go`:
- Around line 308-338: The fire-rule table tests need coverage for the forced
co-reviewer gate in coAwareDedupe and DecideFire. Add a case in the engine
fire-rule table with ForceCoReviewers set for a round where the primary has
already reviewed the head, and assert the forced co-reviewer produces FireCoOnly
or FireCoReviewWait rather than FireDedupe.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 8bfe68e3-1a70-4246-9da7-ce97ae54ccaa

📥 Commits

Reviewing files that changed from the base of the PR and between 37d0bc2 and ae9badb.

📒 Files selected for processing (25)
  • AGENTS.md
  • README.md
  • cmd/crq/main.go
  • internal/crq/auto.go
  • internal/crq/config.go
  • internal/crq/feedback.go
  • internal/crq/feedback_test.go
  • internal/crq/repoconfig.go
  • internal/crq/repoconfig_test.go
  • internal/crq/reviewers.go
  • internal/crq/service.go
  • internal/crq/service_test.go
  • internal/crq/state.go
  • internal/engine/completion.go
  • internal/engine/coreview.go
  • internal/engine/coreview_test.go
  • internal/engine/engine_test.go
  • internal/engine/fire.go
  • internal/engine/progress.go
  • internal/state/dashboard.go
  • internal/state/state.go
  • internal/state/tolerant.go
  • internal/state/tolerant_test.go
  • internal/state/writers_test.go
  • skills/coderabbit-queue/SKILL.md
📜 Review details
🧰 Additional context used
📓 Path-based instructions (7)
internal/engine/**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

internal/engine/**/*.go: Keep internal/engine pure: decision logic must receive now, perform no I/O, and use generic co-reviewer evidence keyed by login; all rules must be table-tested.
DecideFire is the sole fire owner and must evaluate guards in order: open, readable/current head, eligible phase, primary availability, already reviewed, slot, account quota, interval, then adopt/post; primary-unavailable and already-reviewed checks must precede slot and quota gates.
Co-reviewers must not consume the global FireSlot; serialize their trigger posts using per-round CoBots[login].ClaimedAt CAS claims.

Files:

  • internal/engine/coreview_test.go
  • internal/engine/fire.go
  • internal/engine/completion.go
  • internal/engine/coreview.go
  • internal/engine/engine_test.go
  • internal/engine/progress.go
internal/{dialect,gh,state,engine,crq}/**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

Respect the dependency direction dialect ← engine ← crq, state ← crq, and gh ← {state, crq}; do not introduce dependency cycles.

Files:

  • internal/engine/coreview_test.go
  • internal/engine/fire.go
  • internal/engine/completion.go
  • internal/state/dashboard.go
  • internal/engine/coreview.go
  • internal/state/writers_test.go
  • internal/crq/feedback_test.go
  • internal/state/tolerant.go
  • internal/crq/state.go
  • internal/state/tolerant_test.go
  • internal/engine/engine_test.go
  • internal/engine/progress.go
  • internal/crq/config.go
  • internal/crq/auto.go
  • internal/crq/service_test.go
  • internal/crq/repoconfig.go
  • internal/crq/reviewers.go
  • internal/crq/feedback.go
  • internal/crq/repoconfig_test.go
  • internal/state/state.go
  • internal/crq/service.go
internal/{state,engine,crq,gh}/**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

Do not use the literal phrase “rate limit” outside internal/gh and internal/dialect; distinguish GitHub Throttle from CodeRabbit AccountQuota or “account blocked.”

Files:

  • internal/engine/coreview_test.go
  • internal/engine/fire.go
  • internal/engine/completion.go
  • internal/state/dashboard.go
  • internal/engine/coreview.go
  • internal/state/writers_test.go
  • internal/crq/feedback_test.go
  • internal/state/tolerant.go
  • internal/crq/state.go
  • internal/state/tolerant_test.go
  • internal/engine/engine_test.go
  • internal/engine/progress.go
  • internal/crq/config.go
  • internal/crq/auto.go
  • internal/crq/service_test.go
  • internal/crq/repoconfig.go
  • internal/crq/reviewers.go
  • internal/crq/feedback.go
  • internal/crq/repoconfig_test.go
  • internal/state/state.go
  • internal/crq/service.go
internal/engine/*_test.go

📄 CodeRabbit inference engine (AGENTS.md)

Table-test convergence and fire rules in engine_test.go.

Files:

  • internal/engine/coreview_test.go
  • internal/engine/engine_test.go
internal/state/**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

internal/state/**/*.go: Maintain persisted schema v3 with one Round per PR, one global FireSlot, AccountQuota, and an Archive; never delete rounds, preserve unknown JSON members, and dual-write Codex fields for compatibility.
Implement legal Round transitions as methods that return errors for illegal edges; never delete a round, and keep completed rounds as deduplication markers.

Files:

  • internal/state/dashboard.go
  • internal/state/writers_test.go
  • internal/state/tolerant.go
  • internal/state/tolerant_test.go
  • internal/state/state.go
internal/crq/**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

internal/crq/**/*.go: Keep internal/crq limited to orchestration and package wiring; it must not contain bot wording or duplicate decision logic.
observe is the single place that queries GitHub and constructs engine.Observation; service.go is the only effects executor for CAS writes and comment posting, and DryRun must write nothing.
Keep bot identity as data through login-keyed registry and observation structures; do not create per-bot event kinds or verdicts.

Files:

  • internal/crq/feedback_test.go
  • internal/crq/state.go
  • internal/crq/config.go
  • internal/crq/auto.go
  • internal/crq/service_test.go
  • internal/crq/repoconfig.go
  • internal/crq/reviewers.go
  • internal/crq/feedback.go
  • internal/crq/repoconfig_test.go
  • internal/crq/service.go
internal/crq/config.go

📄 CodeRabbit inference engine (AGENTS.md)

Add a default in parseCoBots when a new co-reviewer should be enabled by default.

Files:

  • internal/crq/config.go
🧠 Learnings (3)
📓 Common learnings
Learnt from: CR
Repo: kristofferR/coderabbit-queue

Timestamp: 2026-07-27T12:09:25.123Z
Learning: Use the observe → decide → apply architecture: observe external state once, decide purely in the engine, and apply effects only through the service layer.
Learnt from: CR
Repo: kristofferR/coderabbit-queue

Timestamp: 2026-07-27T12:09:25.123Z
Learning: Preserve frozen `crq loop` exit codes: 0 for converged/skipped, 10 for findings, and 2 for timeout.
📚 Learning: 2026-07-27T01:11:18.244Z
Learnt from: kristofferR
Repo: kristofferR/coderabbit-queue PR: 57
File: internal/crq/feedback.go:91-92
Timestamp: 2026-07-27T01:11:18.244Z
Learning: When reviewing code in `internal/crq` that deals with bot configuration, keep the separation of concerns intact: `Config.isConfiguredBot(login)` should only be evaluated against the fleet-wide primary `Config.Bot`. Do not override or reinterpret `Config.Bot` based on repo-specific reviewer/co-reviewer data. If repo-added co-reviewers are involved, they must be handled via repo-derived bot sets (e.g., `Config.evidenceBots()`), and not via `isConfiguredBot`. `Config.ForRepo(...)` should adjust co-reviewer-derived fields like `CoBots`, `RequiredBots`, `Reviewers`, and `FeedbackBots`, but intentionally not change the meaning of `Config.Bot` used by `isConfiguredBot`.

Applied to files:

  • internal/crq/feedback_test.go
  • internal/crq/state.go
  • internal/crq/config.go
  • internal/crq/auto.go
  • internal/crq/service_test.go
  • internal/crq/repoconfig.go
  • internal/crq/reviewers.go
  • internal/crq/feedback.go
  • internal/crq/repoconfig_test.go
  • internal/crq/service.go
📚 Learning: 2026-07-27T01:11:20.071Z
Learnt from: kristofferR
Repo: kristofferR/coderabbit-queue PR: 57
File: internal/crq/repoconfig.go:163-183
Timestamp: 2026-07-27T01:11:20.071Z
Learning: In internal/crq, treat the “observe → decide → apply” effects restriction as applying only to effects produced by review decisions. Explicit operator mutation commands (e.g., Service.SetReviewers, Service.ClearReviewers, enqueue/cancel flows) are allowed to perform state mutations outside the standard apply path, so review logic should not incorrectly require them to follow observe/decide/apply.

For CRQ_DRY_RUN: it should suppress review requests and fire-record writes, but it must not make explicit configuration/mutation commands (e.g., `crq reviewers set`) silently succeed without persisting the requested changes.

Ensure Service.applyFire revalidates repository reviewer overrides just before posting, to protect against stale/changed overrides since earlier reads.

Applied to files:

  • internal/crq/feedback_test.go
  • internal/crq/state.go
  • internal/crq/config.go
  • internal/crq/auto.go
  • internal/crq/service_test.go
  • internal/crq/repoconfig.go
  • internal/crq/reviewers.go
  • internal/crq/feedback.go
  • internal/crq/repoconfig_test.go
  • internal/crq/service.go
🪛 OpenGrep (1.25.0)
internal/crq/service_test.go

[ERROR] 2645-2645: Possible credit card number (PAN) detected in source code. Credit card numbers should never be hardcoded or stored in source files. Use a secrets manager or tokenization service instead.

(coderabbit.pii.credit-card-number)

🔇 Additional comments (28)
internal/state/dashboard.go (1)

194-205: LGTM!

Also applies to: 282-282, 319-319, 331-331

internal/crq/feedback_test.go (1)

2205-2242: LGTM!

Also applies to: 2244-2279

cmd/crq/main.go (1)

214-219: LGTM!

Also applies to: 365-368, 522-550, 738-815, 817-830

README.md (1)

388-390: LGTM!

Also applies to: 518-520

skills/coderabbit-queue/SKILL.md (1)

174-196: LGTM!

internal/crq/state.go (1)

129-142: LGTM!

internal/state/state.go (1)

106-123: LGTM!

Also applies to: 256-266, 303-317, 399-403, 494-507, 541-580, 651-676, 789-841, 921-926, 1051-1075

internal/state/tolerant.go (1)

31-56: LGTM!

internal/state/writers_test.go (1)

68-94: LGTM!

internal/state/tolerant_test.go (1)

71-163: LGTM!

AGENTS.md (1)

39-42: LGTM!

Also applies to: 79-97

internal/crq/reviewers.go (1)

234-250: LGTM!

Also applies to: 286-300

internal/crq/repoconfig.go (1)

156-184: LGTM!

Also applies to: 187-214, 216-229, 255-325, 327-385

internal/crq/repoconfig_test.go (1)

129-138: LGTM!

Also applies to: 186-263, 287-290, 334-406, 408-509, 511-533, 535-642, 644-724, 726-844

internal/crq/config.go (1)

331-343: LGTM!

Also applies to: 353-379

internal/crq/auto.go (1)

22-25: LGTM!

Also applies to: 297-372

internal/crq/feedback.go (4)

19-71: LGTM!

Also applies to: 87-175


486-728: LGTM!


1409-1479: LGTM!


809-849: 🗄️ Data Integrity & Integration

No change needed for the slot-hold path. sync only writes dashboard state and does not participate in the CAS round-commit flow, so skipping it here does not leave the persistence mutation unstamped.

			> Likely an incorrect or invalid review comment.
internal/crq/service.go (1)

116-167: LGTM! This resolves the earlier scoping concern about the staleness guard by validating overrideChanged inside each verdict's own CAS commit rather than via a single upfront read, and correctly keeps co-reviewer trigger posting off the global FireSlot.

Also applies to: 181-218, 232-335, 488-584, 587-592, 639-685, 695-987, 1006-1144, 1376-1517

internal/crq/service_test.go (1)

363-393: LGTM!

Also applies to: 743-788, 1433-1472, 2419-2453, 2630-2693

internal/engine/completion.go (1)

250-287: LGTM!

internal/engine/coreview.go (1)

396-436: LGTM!

internal/engine/coreview_test.go (1)

102-113: LGTM!

internal/engine/engine_test.go (1)

153-176: LGTM!

Also applies to: 193-231, 1010-1104

internal/engine/fire.go (1)

127-221: LGTM!

internal/engine/progress.go (1)

48-170: LGTM!

Also applies to: 172-211

Comment thread internal/crq/config.go
Comment thread internal/crq/repoconfig.go
Comment thread internal/state/writers_test.go
@kristofferR

Copy link
Copy Markdown
Owner Author

@codex review

@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: a454a83f63

ℹ️ 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 internal/crq/reviewers.go Outdated
Comment thread internal/crq/feedback.go
Comment thread internal/engine/progress.go
Comment thread internal/state/state.go Outdated
@kristofferR

Copy link
Copy Markdown
Owner Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Another round soon, please!

Reviewed commit: 90e78e9106

ℹ️ 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".

# Conflicts:
#	README.md
#	cmd/crq/main.go
#	llms.txt
#	skills/coderabbit-queue/SKILL.md
@kristofferR
kristofferR merged commit 22a414c into main Jul 27, 2026
1 of 2 checks passed
kristofferR added a commit that referenced this pull request Jul 27, 2026
* Delete the trigger comments nothing needs any more

A PR driven through a dozen rounds collects a dozen "@coderabbitai
review" comments and a dozen acknowledgements, which buries the
conversation a human came to read. crq now removes its own half of that
as rounds progress, and `crq tidy` does it on demand.

Deleting a comment crq still reads is how this becomes expensive, so a
comment has to clear three guards. It belongs to a round that has
PROGRESSED — a live round keeps its command, because that is the comment
crq adopts instead of posting another. The bot acted after it, so it was
read rather than merely old. And it predates the current head, because
adoption only ever considers commands newer than the head commit; delete
one of those and the next pump posts a duplicate and buys a second
review.

Only comments crq posted. Candidates are the command IDs recorded on its
own rounds, never anything matching the text — a person's "@coderabbitai
review" is their decision to ask, not crq's to erase, and crq posts under
the same account so authorship alone cannot tell them apart.

Never the bots' own comments. An auto-generated reply can be a rate-limit
or skipped-review notice, which crq classifies as evidence and surfaces
as a finding, so deleting those would quietly destroy feedback nobody had
read yet.

A recorded command that is already gone counts as tidied rather than
failing: the bot removes some of its own command comments, and a person
may have tidied by hand.

* Remember the review request each retry replaces

A rate-limited round retries, and every retry posts a NEW
"@coderabbitai review" — the bot answered the previous one with the
rate-limit notice, so it can never be adopted again. crq overwrote
CommandID and forgot the old comment, which is why a throttled PR
collects a column of identical requests: nothing knew they were there,
and tidying could only ever find commands from rounds that had finished.

A round now records the commands it supersedes, bounded so a PR that
retries all day cannot grow its round without limit, and tidy treats them
as spent whichever phase the round is in. They are exempt from the
predates-the-head check on purpose: crq's own record that it has posted a
successor is stronger evidence than any timestamp.

Observed on PR #50 — five heads, nine review requests, three of them for
the first head alone. Codex is not affected: it gets one command per head
because crq skips the trigger when the bot has already reviewed it.

* Only delete the review requests crq wrote itself

Adoption was the hole. A round records the command it adopted in exactly
the same CommandID as one it posted, so "the command IDs crq recorded on
its own rounds" included a person's "@coderabbitai review" — and once the
head moved on and the bot had spoken, tidy would delete it. With a
maintainer token nothing even objects.

A round now records the comments it WROTE, with the reviewer each was
addressed to and when it landed, and that list is the only candidate
source. Adopting a comment is not writing one. It also replaces the
spent-command list: a command missing from the round's current anchors is
one the round replaced, which is the same fact without a second field.

Four things fall out of carrying the reviewer with the comment:

  * a co-only round's anchor is the co-reviewer's trigger, not the
    primary's — unrelated CodeRabbit activity no longer passes for the
    answer that trigger is still waiting on, and the id stops appearing
    on the deletion list twice;
  * a superseded co-reviewer trigger is attributed to the bot that was
    asked rather than to CodeRabbit;
  * candidates are filtered against the comments actually on the PR, so
    a comment tidy already deleted is not DELETEd again on every later
    pass with the 404 read back as a fresh removal;
  * state is re-read after the observation and before the deletes, so a
    round another fleet member started in that window keeps its command.

An unreadable head commit now keeps every non-superseded command instead
of clearing the guard: the command may well be adoptable again once the
read recovers, and deleting it buys a second review. And a round that
completes while holding the slot ("cleared") or inside the reviewing
sweep is tidied — between them that is most successful rounds, so the
automatic cleanup was barely running.

* Keep tidy off comments that stopped being trigger comments

Four things review found in the tidy pass.

A recorded comment ID proves crq wrote that comment, not that it is still
the one-line command crq wrote. crq posts under the operator's own account,
so anyone can edit it into an explanatory note — and the pass would then
delete someone's words as a spent request. The body is now checked against
the reviewer's trigger command; anything else, including a command whose
config changed since, is kept.

A refused delete was only logged, so a caller reading an empty `deleted`
could not tell "nothing was spent" from "this token may not delete". The
pass still tries every ID and now reports the failures in `.failed[]`.

Codex can answer a trigger with nothing but its thumbs-up, and that reaction
alone completes the round — leaving no review, event or check for answeredAt
to find, so the `@codex review` comment was kept for ever. Tidy observes with
no round, so observe() never fetches reactions; they are read here instead,
once per candidate nothing else has answered.

And the README documented neither `crq tidy` nor `CRQ_TIDY`, so an upgrade
started deleting comments with no entry in the documented CLI contract.

* Tidy the triggers a force-push and a PR reaction retired

Three ways the tidy pass read the PR differently from the code it mirrors.

Adoption's cutoff is the head commit date raised to the last force-push,
because a force-push can point the PR at a commit object older than the
commands made for an earlier head. Tidy compared against the commit date
alone, so a rebase onto such a commit kept a trigger no round can ever
adopt again — for ever, once the PR merged and the closed-PR guard stopped
looking. It now asks for the same cutoff, and TidyInput.HeadAt is renamed
AdoptableFrom to say which one it is.

Codex answers a command in the PR description by reacting to the PR, and
observe() accepts that as the round's completion. Tidy only read reactions
on each recorded trigger, so a round that ended that way left no evidence
it could see and kept the spent "@codex review" comment. Both of observe's
sources count now; the PR's reactions are read at most once per pass, and
only when a candidate is still unanswered.

And a pump that changed nothing reports "waiting", which tidy treated as
progress: every poll of a long-running review bought a second full
observation of the PR the pump had just observed. Housekeeping does not
get to spend the REST quota the queue runs on. The one "waiting" that does
move a round parks it with its commands still live, so it has nothing of
its own to remove.

* Read the third place a Codex thumbs-up can be

A Codex-gated round completes on a +1 left on the trigger, on the PR, or on
the command the round fired on — observe() reads all three, and for a round
whose primary is CodeRabbit that last one is a different comment from the
"@codex review" crq posted beside it. Tidying now reads it too, at most once
per candidate nothing cheaper has answered, so a round that ended there stops
looking like a trigger nobody read.

The README and llms.txt said a comment is removed once it predates the
current head; it is the cutoff adoption uses, the head commit raised to the
last force-push.

* Take the reviewer configuration as a value, like the rest of crq

This branch was cut before #51, so it still read the reviewer
configuration off the Service: observe with no config argument, and
coCommandBodies as a Service method. Both are Config methods now, and the
branch stopped compiling the moment main moved under it — the tests here
passed only because CI builds the branch, not the merge.

Tidy takes a Config through the whole path now: which comments count as a
trigger depends on who reviews, so that has to be a value the caller
supplies. It reads the fleet configuration today, and per-repo reviewers
(#57) can substitute one there in a single line without threading
anything new through.

* Preserve review evidence when tidying commands

* Harden tidy command cleanup

* Preserve tidy history and throttle backoff

* Retain Codex reaction evidence during tidy

* Preserve tombstones after ambiguous deletes

* Address tidy review findings

---------

Co-authored-by: kristofferR <kristofferR@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant