Summary
59% of all update_branch failures are a permission error that retrying can never fix, and the engine retries them anyway — up to 9 times on a single PR. The GitHub App cannot push a branch update to any PR that touches .github/workflows/**, but nothing detects this, so every wake re-attempts it.
Production evidence (edge-nl-01, 7 days to 2026-07-27)
agent.action.update_branch: 159 events — 77 completed, 71 error, 11 denied (45% failure rate). The failure breakdown:
| Outcome |
Failure class |
Count |
Distinct PRs |
| error |
workflow-permission — unfixable by retry |
48 |
14 |
| error |
merge conflict |
17 |
8 |
| denied |
head moved (self-race) |
6 |
2 |
| denied |
PR no longer open |
5 |
5 |
| error |
no new commits on base |
5 |
1 |
| error |
GitHub timeout |
1 |
1 |
The dominant class is:
refusing to allow a GitHub App to create or update workflow '.github/workflows/…'
Worst repeat offenders — attempts against the same PR:
JSONbored/loopover#8499 9
JSONbored/loopover#8497 7
JSONbored/loopover#8400 6
JSONbored/loopover#7736 5
JSONbored/loopover#8030 4
Each attempt is a wasted GitHub API call, an audit row, and a retry cycle, on an operation that is structurally impossible for that PR until its diff stops touching workflow files.
This corrects an earlier characterisation: the 45% failure rate is not primarily the engine racing its own pushes. Self-race accounts for 6 of 82 failures; missing App permission accounts for 48.
Why it matters beyond the waste
Requirements
- A rebase that cannot succeed for a structural reason must not be attempted repeatedly.
- A PR touching workflow files must still be reviewable — the inability to rebase it must not become an inability to process it.
Deliverables
Tests (must fail against current main)
Related
Summary
59% of all
update_branchfailures are a permission error that retrying can never fix, and the engine retries them anyway — up to 9 times on a single PR. The GitHub App cannot push a branch update to any PR that touches.github/workflows/**, but nothing detects this, so every wake re-attempts it.Production evidence (
edge-nl-01, 7 days to 2026-07-27)agent.action.update_branch: 159 events — 77 completed, 71 error, 11 denied (45% failure rate). The failure breakdown:The dominant class is:
Worst repeat offenders — attempts against the same PR:
Each attempt is a wasted GitHub API call, an audit row, and a retry cycle, on an operation that is structurally impossible for that PR until its diff stops touching workflow files.
This corrects an earlier characterisation: the 45% failure rate is not primarily the engine racing its own pushes. Self-race accounts for 6 of 82 failures; missing App permission accounts for 48.
Why it matters beyond the waste
Requirements
Deliverables
.github/workflows/**. The changed-file list is already fetched (pull_request_files), so this is a cheap pre-check rather than a failed API round trip.strict: false, so being behind blocks nothing), or hold with a named reason. Silently retrying forever is the one option that should be off the table.workflowspermission at all. If it should not, document that so this is understood as intended rather than as a gap.update_branchoutcome by failure class, so the next regression here is visible without a database query.Tests (must fail against current main)
.github/workflows/**does not attempt a staleness rebase.Related