Skip to content

fix: End a sweep on an error that holds for the whole run - #180

Merged
mpaulosky merged 2 commits into
mainfrom
fix/179-run-wide-errors-end-sweep
Oct 10, 2026
Merged

mpaulosky merged 2 commits into
mainfrom
fix/179-run-wide-errors-end-sweep

Conversation

@mpaulosky

Copy link
Copy Markdown
Owner

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 GraphQL RATE_LIMITED error fails every later call too, and GitHub asks callers to stop on a rate limit.

What changed

Testing

test.sh passes (142 auto-merge tests).

🤖 Generated with Claude Code

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>
@mpaulosky mpaulosky added the review:claude Review with Claude label Oct 10, 2026

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

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.

Comment thread .github/workflows/pr-automerge.yml Outdated
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>

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

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. RequestError puts lower-cased string headers on error.response.headers. GitHub sends x-ratelimit-remaining: "0" and/or retry-after on 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 with errors[].type === "RATE_LIMITED", which GraphqlResponseError exposes as error.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. endsRun reads every field defensively (?., ??), so an error with no response or message won't throw a TypeError that would hide the original error.
  • The test helper's new try/catch doesn't hide anything. It only adds an observed property 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:

  • reads is 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 reach evaluate instead 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.

@mpaulosky
mpaulosky merged commit 9def49f into main Oct 10, 2026
5 checks passed
@mpaulosky
mpaulosky deleted the fix/179-run-wide-errors-end-sweep branch October 10, 2026 17:43
mpaulosky added a commit to mpaulosky/TicketManager that referenced this pull request Oct 10, 2026
## 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>
mpaulosky added a commit to mpaulosky/IssueTracker that referenced this pull request Oct 10, 2026
## 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>
mpaulosky added a commit to mpaulosky/IssueManager that referenced this pull request Oct 10, 2026
## 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>
mpaulosky added a commit that referenced this pull request Oct 10, 2026
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>
mpaulosky added a commit to mpaulosky/atelier-store that referenced this pull request Oct 10, 2026
## 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>
mpaulosky added a commit to mpaulosky/SuggestionApp that referenced this pull request Oct 10, 2026
## 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>
mpaulosky added a commit to mpaulosky/Blazor-Server that referenced this pull request Oct 10, 2026
## 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>
mpaulosky added a commit to mpaulosky/Articles that referenced this pull request Oct 10, 2026
## 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>
mpaulosky added a commit that referenced this pull request Oct 10, 2026
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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

review:claude Review with Claude

Projects

None yet

Development

Successfully merging this pull request may close these issues.

PR Auto-Merge: a run-wide API error (401, rate limit) shouldn't be skipped per PR

1 participant