Repository navigation
fix: End a sweep on an error that holds for the whole run - #180
Conversation
A 401, a 403 or 429 rate limit, or a GraphQL RATE_LIMITED error fails every later call too, so the sweep stops instead of trying each PR. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
Claude Review
The PR changes the sweep in pr-automerge.yml (the repo copy and the template copy are identical). Errors that hold for the whole run now end the sweep straight away: a 401, 403 or 429 status, or a GraphQL RATE_LIMITED error. Any other error from one PR is still logged, and the sweep goes on to its update. It also adds a test for each of the four error kinds and a line in automerge.md.
Verdict: the idea is sound, but endsRun counts every 403 as a rate limit. GitHub also returns 403 for problems that affect only one PR. When that happens, the sweep is cut short before its update, which is the stall #178 fixed. The tests only cover a rate-limit 403, so they don't catch this.
I read the INDEX and the single piece, 001.diff, which holds all four files. There is no AGENTS.md or CLAUDE.md in the repo. I didn't read any unchanged code: mergeIfReady and the code that ends a sweep are not covered. So which per-PR calls can return 403 is based on how the GitHub REST API behaves, not on this repo's code. I also didn't check line numbers against the checked-out files. They come from the diff's hunk headers, and 001.diff gives both workflow copies the same blob hashes, so 1007 applies to both.
Most 403s belong to one PR (a locked PR, a branch restriction), so they stay per-PR errors and the sweep still reaches its update. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
Claude Review
What the PR changes: PR #180 changes when an error ends an automerge sweep early. A 403 now ends the run only when it's a rate limit: x-ratelimit-remaining: 0, a retry-after header, or "rate limit" in the error message. 401, 429 and GraphQL RATE_LIMITED errors still end the run at once. Any other 403 (a locked PR, a branch restriction) counts as that one PR's error, so the sweep logs it, carries on to its update, and then fails the run.
The change is made the same way in .github/workflows/pr-automerge.yml and in the template copy, which have the same blob hashes, so the two stay in sync. It comes with parameterised tests (each run-ending error stops the sweep before PR 9 is read and makes no update; a plain 403 still lets the update for PR 7 happen) and a docs note in references/automerge.md.
What I checked:
- The rate-limit test fits how Octokit reports errors.
RequestErrorputs lower-cased string headers onerror.response.headers. GitHub sendsx-ratelimit-remaining: "0"and/orretry-afteron primary and secondary rate-limit 403s. Both of its usual messages ("API rate limit exceeded…", "You have exceeded a secondary rate limit…") match/rate limit/i. A GraphQL rate limit comes back as HTTP 200 witherrors[].type === "RATE_LIMITED", whichGraphqlResponseErrorexposes aserror.errors. - Narrowing the 403 check costs nothing. Every 403 left out of
endsRun(for example "Resource not accessible by integration") goes back to the earlier per-PR handling: the sweep continues and the run still fails at the end. - Missing fields don't cause errors.
endsRunreads every field defensively (?.,??), so an error with noresponseormessagewon't throw aTypeErrorthat would hide the original error. - The test helper's new
try/catchdoesn't hide anything. It only adds anobservedproperty and rethrows the same error object, so existing tests that expect a rejection keep the same error.
Not verified: I didn't open the unchanged code around the change, so these points rest on what the diff shows:
readsis in scope in the test helper (the diff uses it, but the helper's return statement doesn't include it).mergeIfReady, and the step that evaluates the candidate again before the update, let errors reachevaluateinstead of handling them internally.
The PR's own tests would catch a problem with the first point.
Coverage: I read the single piece, 001.diff, in full. It holds all 4 files and none were excluded. The repository has no CLAUDE.md or AGENTS.md.
Verdict: I found nothing that should block the merge; the change looks correct and is well tested.
No findings.
## Why Re-Apply the repo-ci-baseline Template so this repo carries the Template changes from mpaulosky/dotfiles#176, mpaulosky/dotfiles#178 and mpaulosky/dotfiles#180. ## What changed - `2a18002` Apply commit, `apply.sh` output alone: brings mpaulosky/dotfiles#176, mpaulosky/dotfiles#178 and mpaulosky/dotfiles#180. - `.github/scripts/tests/pr-automerge.test.mjs` - `.github/workflows/pr-automerge.yml` ## Verification - The Apply commit is exactly `apply.sh`'s output on a branch up to date with `main`. - The pre-push gate (`scripts/gate.sh`) passed on `2a18002`. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: T <t@e.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
## Why Re-Apply the repo-ci-baseline Template so this repo carries the Template changes from mpaulosky/dotfiles#176, mpaulosky/dotfiles#178 and mpaulosky/dotfiles#180. ## What changed - `58619ee` Apply commit, `apply.sh` output alone: brings mpaulosky/dotfiles#176, mpaulosky/dotfiles#178 and mpaulosky/dotfiles#180. - `.github/scripts/tests/pr-automerge.test.mjs` - `.github/workflows/pr-automerge.yml` ## Verification - The Apply commit is exactly `apply.sh`'s output on a branch up to date with `main`. - The pre-push gate (`scripts/gate.sh`) passed on `58619ee`. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: T <t@e.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
## Why Re-Apply the repo-ci-baseline Template so this repo carries the Template changes from mpaulosky/dotfiles#176, mpaulosky/dotfiles#178 and mpaulosky/dotfiles#180. ## What changed - `225fc8f` Apply commit, `apply.sh` output alone: brings mpaulosky/dotfiles#176, mpaulosky/dotfiles#178 and mpaulosky/dotfiles#180. - `.github/scripts/tests/pr-automerge.test.mjs` - `.github/workflows/pr-automerge.yml` ## Verification - The Apply commit is exactly `apply.sh`'s output on a branch up to date with `main`. - The pre-push gate (`scripts/gate.sh`) passed on `225fc8f`. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: T <t@e.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Closes #181. ## Why Claude Review on mpaulosky/atelier-store#142 (the #180 re-Apply): `updateBranchOf` caught every non-422 error as a warning, so a rate limit or 401 from `updateBranch` (or the Dependabot comment) never reached `endsRun`, and the sweep went on to the next candidate. ## What changed - `pr-automerge.yml` (Template and dotfiles' copy): `endsRun` moves above `updateBranchOf`, which rethrows such an error during a sweep. On a PR event it stays a warning: there's no other PR to try, and ADR 0005 keeps update errors from failing a PR's check. - Tests: a sweep's rate-limited update ends the run without trying the next candidate; a PR event's is a warning. - `references/automerge.md` notes it. ## Testing `test.sh` passes (146 auto-merge tests). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: T <t@e.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
## Why Re-Apply the repo-ci-baseline Template so this repo carries the Template changes from mpaulosky/dotfiles#176, mpaulosky/dotfiles#178 and mpaulosky/dotfiles#180. ## What changed - `a685976` Apply commit, `apply.sh` output alone: brings mpaulosky/dotfiles#176, mpaulosky/dotfiles#178 and mpaulosky/dotfiles#180. - `.github/scripts/tests/pr-automerge.test.mjs` - `.github/workflows/pr-automerge.yml` ## Verification - The Apply commit is exactly `apply.sh`'s output on a branch up to date with `main`. - The pre-push gate (`scripts/gate.sh`) passed on `a685976`. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: T <t@e.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
## Why Re-Apply the repo-ci-baseline Template so this repo carries the Template changes from mpaulosky/dotfiles#176, mpaulosky/dotfiles#178 and mpaulosky/dotfiles#180. ## What changed - `adeb234` Apply commit, `apply.sh` output alone: brings mpaulosky/dotfiles#176, mpaulosky/dotfiles#178 and mpaulosky/dotfiles#180. - `.github/scripts/tests/pr-automerge.test.mjs` - `.github/workflows/pr-automerge.yml` ## Verification - The Apply commit is exactly `apply.sh`'s output on a branch up to date with `main`. - The pre-push gate (`scripts/gate.sh`) passed on `adeb234`. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: T <t@e.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
## Why Re-Apply the repo-ci-baseline Template so this repo carries the Template changes from mpaulosky/dotfiles#176, mpaulosky/dotfiles#178 and mpaulosky/dotfiles#180. ## What changed - `5b0ccbb` Apply commit, `apply.sh` output alone: brings mpaulosky/dotfiles#176, mpaulosky/dotfiles#178 and mpaulosky/dotfiles#180. - `.github/scripts/tests/pr-automerge.test.mjs` - `.github/workflows/pr-automerge.yml` ## Verification - The Apply commit is exactly `apply.sh`'s output on a branch up to date with `main`. - The pre-push gate (`scripts/gate.sh`) passed on `5b0ccbb`. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: T <t@e.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
## Why Re-Apply the repo-ci-baseline Template so this repo carries the Template changes from mpaulosky/dotfiles#176, mpaulosky/dotfiles#178 and mpaulosky/dotfiles#180. ## What changed - `b9cb0c9` Apply commit, `apply.sh` output alone: brings mpaulosky/dotfiles#176, mpaulosky/dotfiles#178 and mpaulosky/dotfiles#180. - `.github/scripts/tests/pr-automerge.test.mjs` - `.github/workflows/pr-automerge.yml` ## Verification - The Apply commit is exactly `apply.sh`'s output on a branch up to date with `main`. - The pre-push gate (`scripts/gate.sh`) passed on `b9cb0c9`. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Teqslamer <teqslamer@gmail.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Refs #181; follows #182. ## Why Claude Review on mpaulosky/SuggestionApp#21 (the #180 re-Apply): besides the rate limit #182 fixed, a sweep's update that failed any other way (a 5xx, a 403 for a missing permission) only logged a warning, so the sweep ended green. A read error on one PR already fails the run once the sweep is done (#178); an update error now does too. ## What changed - `pr-automerge.yml` (Template and dotfiles' copy): `updateBranchOf` records the PR in the run's `failedPrs` during a sweep, and the sweep still tries the next candidate. On a PR event it stays a warning only, as ADR 0005 requires. `failedPrs` moves up with the other sweep state (renamed from `failed`, which `bringUpToDate` also uses for a PR's failed checks). - Tests: a sweep whose update fails tries the next candidate, then fails the run; a PR event's rate-limited update doesn't fail it. - `references/automerge.md` notes it. ## Testing `test.sh` passes (147 auto-merge tests). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: T <t@e.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Closes #179.
Why
Claude Review on mpaulosky/TicketManager#193 (the #178 re-Apply): #178 made a sweep catch each PR's error and carry on. That's right for a 5xx on one read, but a 401 (revoked
RELEASE_PR_PAT), a 403/429 rate limit or a GraphQLRATE_LIMITEDerror fails every later call too, and GitHub asks callers to stop on a rate limit.What changed
pr-automerge.yml(Template and dotfiles' copy):evaluaterethrows those errors, which ends the run as before fix: Make a sweep's one update after its merges, and only if it merged none #178. Other errors are still logged per PR and fail the run once the sweep is done.references/automerge.mdnotes the split.Testing
test.shpasses (142 auto-merge tests).🤖 Generated with Claude Code