OPER-159
OPER: pr-size workflow crashes on update-branch race (git symmetric-difference)
Band
SMALL
Suggested
Justin Cooke
Body
---
feature_id: FEAT-studio-dispatcher
filing_template_version: v1
decision_memo: docs/pdt/2026.09.09-observation-pr-size-race.md
blocked_by:
---
## Context
On 2026.09.09 during the OPER-146/OPER-151 drain, calling `PUT /pulls/{n}/update-branch` on PR #437 (agent/oper-146-pr2) advanced the head SHA with a merge commit bringing main into the branch. The `Check PR size` workflow re-fired on `synchronize`, but the runner's checkout had not yet fetched the newly-recorded base SHA that GitHub captured on the pull_request event, and the size step aborted with:
```
fatal: Invalid symmetric difference expression 86c251d090fa8b74a90a1c3b505b4e5eb5cc08d6...2ad32e694f2acfa233303c5e22426e7a8cf5a627
```
The git error trips a required status check to `failure` even though the underlying diff is well-formed and would compute a valid size. A human had to re-run the workflow after GitHub caught up. This is a race between GitHub's event dispatch and the runner's fetch step, and it will happen every time OPER-157's auto-update-behind gate lands and starts firing regularly.
## Root cause
`git diff --numstat "$BASE_SHA"..."$HEAD_SHA"` requires both SHAs to be reachable from local refs. `actions/checkout@v4` with `fetch-depth: 0` fetches the default branch fully, but when the pull_request event fires immediately after an update-branch merge, the newly-authored base commit may not be in the runner's fetched history yet, since GitHub's own ref-sync is eventually consistent.
## Acceptance Criteria
1. `pr-size.yml` computes the diff without crashing on a missing base SHA. Choose one:
a. Explicitly `git fetch origin "$BASE_SHA"` before the diff, with a retry loop bounded to 3 attempts and 10 seconds each, and fail the job only if the fetch itself fails.
b. Replace local `git diff` with GitHub's REST `/repos/{o}/{r}/compare/{base}...{head}` (or `/pulls/{n}/files`) which is always consistent with the event payload.
2. On a genuine size violation the workflow still fails with the current sticky-comment error (regression test: seed a synthetic 1200-LOC diff, confirm `size/XL` label + failure).
3. On a transient fetch failure (network flake) the job retries and, if still failing after 3 attempts, exits with a clear message rather than `Invalid symmetric difference expression`.
4. Self-test script `scripts/pr-size-selftest.sh` (KNUCK-A032 pattern) drives the size-decision function with synthetic diffs to prove: (a) missing-base-SHA path fetches and succeeds, (b) size/XL is still enforced, (c) size-override + `Size override:` line is still honored.
5. `.claude/rules/pr-size-budget.md` records the new post-update-branch fetch step so future workflow edits do not regress.
## Verification
- `bash scripts/pr-size-selftest.sh` passes locally and in CI.
- Reproduce the crash on a test PR by force-pushing a merge commit while artificially delaying the fetch, and confirm the new workflow retries cleanly.
- On PR #437's SHA `2ad32e694f2acfa233303c5e22426e7a8cf5a627`, `Check PR size` completes without `Invalid symmetric difference expression`.
## Notes
- Class: `Post-Update-Branch-Diff-Crash`. Pair with OPER-157 (auto-update-behind) since that gate will multiply the exposure.
- Do not weaken the size budget while fixing this; the fix is about correctness, not lenience.
---
<!-- admission-rejected -->
**Admission rejected (map_drift):** feature-map.md content sha256 does not match Product.featureMapChecksum for slug=studio; DB and repo have drifted
Attachments
Loading attachments…
Comments
Loading comments…