You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Tracking issue for the v3 work: turning the agent-facing review protocol from prose into commands, and scoping the queue to the reviewer that actually meters it.
Why
crq's protocol lived in documentation. llms.txt, SKILL.md and crq help loop each described the same rules — drain findings before starting a round, hold the head while a reviewer is pending, pick a delay — and drifted apart. Nine of fifteen merged PRs before this changed that prose rather than any decision.
Agents then improvised the parts crq did not own, and the improvisations were uniform. Across 16 real driving sessions, every single one wrapped the tool the same way:
set +e; crq loop OWNER/REPO N > /tmp/out.json;echo"CRQ_EXIT:$?"
An exit code smuggled out through an echoed sentinel into a temp file. Several runs were SIGTERM'd mid-wait or orphaned at a session teardown, and restarting was wrong both ways: it either re-fired a review (spending account quota) or hit the dedupe and reported a converged round whose findings were never collected.
Guiding invariant: anything in the docs that tells an agent when to wait, hold, push, or resolve is a bug in crq next.
The sizing rule
#39 took four review rounds and 52 findings, and every round after the first found regressions introduced by the previous round's fixes. The reviewers were right each time. The cause was size — 24 files, a new command, a reordered decision path and changed decline semantics all interacting, so each correction moved something else.
So, for everything below:
One thesis per PR. If the description needs "and also", split it.
Converge in ≤2 review rounds. A third round that finds a regression from the second means land what is verified and move the rest out.
Verify before writing. Three of the first seven planned items turned out to be already fixed. Re-read scope against main before starting anything here.
Quota-free work never waits on the queue — Let the fire slot serialize the metered review and nothing else #47. The rescue scan claimed to cover "blocked or slot-busy" and the slot-busy half had never executed once: Pump returned before reaching it. The fire slot now serializes the metered review and nothing else.
Fail closed on an unknown schema version — Refuse state a newer binary wrote instead of erasing it #49. A NEWER payload is refused instead of reinitialized over; an older one still reinitializes. This is what makes a future bump possible.
Reviewer configuration is a value — Make the reviewer configuration a value, not a field #51. Pure refactor: policy, classifier lists, trigger lookups and the evidence set became functions of a Config, and observe takes the configuration it should use rather than reaching for the Service's own.
In review
Every finding has a way to stop being returned — Let an agent account for a finding GitHub cannot close #48. crq dismiss for a finding GitHub gives no thread to close. Only intrinsically threadless sources, only from a round that has progressed, and the reason is stored.
The threads a push leaves behind — List the threads a push leaves behind #50. After a push every previous-head thread is outdated and drops out of findings, so crq was forcing agents to the raw GitHub API — the one thing the skill forbids. Title parsing lives in dialect and is tested against the corpus.
Repo-local git — Give crq its own place on disk for a repository #53. A bare mirror per repository and a detached worktree per head, so the daemon can work in a repository it was not run inside. Credentials come from the same resolution the API client uses.
Act on a transition instead of logging it — Act on a transition instead of logging it #54. crq watch [--dispatch] drives every open PR through the same next oracle and starts a fix session for the ones that need one. Sessions run concurrently, off the decision loop; the decisions stay serial, which is what keeps the metered review in one queue.
Tidy spent trigger comments — Delete the trigger comments nothing needs any more #56. Deletes crq's own review requests once the round has progressed and the bot has answered. Never the bots' comments: an auto-reply can be a rate-limit or skipped-review notice crq reads as evidence.
Per-repo reviewer config — Choose which bots review which project #57. crq reviewers [set|clear] <repo>, stored in the state ref both the daemon and agents already read. The primary stays fleet-wide, because its markers are compiled into the classifiers.
Declined re-review recovery. CodeRabbit refusing to re-review a changed head ("does not re-review already reviewed commits") currently reports blocked and stops there.
Revalidate the reviewer override inside the fire CAS. A config change landing between the decision and the write can post a trigger for a co-reviewer just removed. Bounded — co-triggers spend no account quota — so it was declined on Choose which bots review which project #57 rather than widening that PR.
Gate holds against older fleet binaries.Choose which bots review which project #57 adds the per-process capability record; extending it to holds is a one-liner once both land.
Two things worth remembering about the work itself
Both cost several review rounds before being spotted:
When a claim keeps being wrong, consider deleting the claim. The queue's ordering was refined across four rounds — simulate it, fall back to Seq, drop positions while the slot is held — before it became clear that order past the front is not knowable at all, because slot release comes from acknowledgement or the in-flight timeout rather than pacing. Removing the prediction was less code than any of the refinements.
An exemption applied per-site will keep missing a site. "A co-only round is not governed by the queue" was fixed three times in three rounds — the account window, the ordering, the follower pass — before being made structural by partitioning those rounds out before any gate applies.
Ordering
The seven PRs in review are independent except for two stacks that have since
been flattened: #57 was rebased onto main after #51 merged, and #54 carries #53's workspace. Merge order is otherwise free.
What is left after them has no coupling at all — the behaviour lab, per-bot SeenActiveAt, declined re-review recovery, and the two small items split out
of #55 and #57 rather than widening either.
Tracking issue for the v3 work: turning the agent-facing review protocol from prose into commands, and scoping the queue to the reviewer that actually meters it.
Why
crq's protocol lived in documentation.
llms.txt,SKILL.mdandcrq help loopeach described the same rules — drain findings before starting a round, hold the head while a reviewer is pending, pick a delay — and drifted apart. Nine of fifteen merged PRs before this changed that prose rather than any decision.Agents then improvised the parts crq did not own, and the improvisations were uniform. Across 16 real driving sessions, every single one wrapped the tool the same way:
An exit code smuggled out through an echoed sentinel into a temp file. Several runs were SIGTERM'd mid-wait or orphaned at a session teardown, and restarting was wrong both ways: it either re-fired a review (spending account quota) or hit the dedupe and reported a converged round whose findings were never collected.
Guiding invariant: anything in the docs that tells an agent when to wait, hold, push, or resolve is a bug in
crq next.The sizing rule
#39 took four review rounds and 52 findings, and every round after the first found regressions introduced by the previous round's fixes. The reviewers were right each time. The cause was size — 24 files, a new command, a reordered decision path and changed
declinesemantics all interacting, so each correction moved something else.So, for everything below:
mainbefore starting anything here.Done
crq nextreturns one action fromfix · hold · push · wait · done · blocked, always exit 0.crq waitblocks until there is something to do and exits, so its exit is the wake event for an ephemeral agent; it holds no round, so being killed costs only the process. Ref loop: survive process death — resumable wait state, ideally daemon-owned loop execution #12.Reviewerkeyed onbudget: account | none; the four legacy lists became views of it. Ref Full support for Macroscope and Cursor Bugbot via a co-reviewer abstraction #34.crq nextfinds the PR from the checkout (every target-taking command, fork remotes included), andcrq status --linerenders the queue in one line.Pumpreturned before reaching it. The fire slot now serializes the metered review and nothing else.Config, andobservetakes the configuration it should use rather than reaching for the Service's own.In review
crq dismissfor a finding GitHub gives no thread to close. Only intrinsically threadless sources, only from a round that has progressed, and the reason is stored.crq watch [--dispatch]drives every open PR through the samenextoracle and starts a fix session for the ones that need one. Sessions run concurrently, off the decision loop; the decisions stay serial, which is what keeps the metered review in one queue.crq hold— Hold a PR in one write instead of two commands and a race #55. One write instead of a skip marker pluscrq canceland a race between them, rechecked in the CAS that reserves the round.crq reviewers [set|clear] <repo>, stored in the state ref both the daemon and agents already read. The primary stays fleet-wide, because its markers are compiled into the classifiers.Still open
SeenActiveAtacross supersede. Ref Self-heal cannot recover a co-reviewer whose last activity was a clean run on a previous head #36.blockedand stops there.Two things worth remembering about the work itself
Both cost several review rounds before being spotted:
Ordering
The seven PRs in review are independent except for two stacks that have since
been flattened: #57 was rebased onto
mainafter #51 merged, and #54 carries#53's workspace. Merge order is otherwise free.
What is left after them has no coupling at all — the behaviour lab, per-bot
SeenActiveAt, declined re-review recovery, and the two small items split outof #55 and #57 rather than widening either.