Raxx · internal docs

internal · gated

RCA — stale-branch-guard read a promote/* PR head's own parents as (base, head), failing every release promotion

Incident ID: 2026-10-31-ci-pr-stale-branch-guard-promote-head-read-as-merge-ref Date: 2026-10-31 Severity: SEV-3 (single required check false-red on release promotion PRs; no production impact) Duration: Latent since the resolver shipped (#4611). First observed on #4855 (promote/release-2026.10.30-to-main, opened 2026-10-30 13:04 UTC); reproduced on #4885, pipeline 20072, 2026-10-31 04:11 UTC. Blast radius: Every promote/* PR into main, and any PR whose branch has the base merged into it. Feature PRs were unaffected. Five other gates that share the resolver ran against the wrong base on those PRs. Author: sre-agent

Summary

scripts/ci/resolve_pr_base_sha.sh decided that HEAD was GitHub's merge ref whenever the event was pull_request and HEAD had two or more parents, then returned HEAD^1 as the base and HEAD^2 as the head. Woodpecker does not check out the merge ref: its clone step resets to CI_COMMIT_SHA, so HEAD is the PR head. A promote branch is origin/release with origin/main merged in, so its own parents are (release tip, main tip). The guard therefore compared the release tip against the main tip and reported "24 commits behind main" on a branch that fully contains main. Fixed by classifying the checkout by identity (HEAD vs CI_COMMIT_SHA) and taking the base from origin/<target> when HEAD is the PR head.

Timeline (all times UTC)

Impact

What went well

What didn't go well

Root cause analysis

Detection

Resolution

Action items

Not filed as GitHub issues (standing instruction); tracked here. | # | Action | Owner | Due | Issue | |---|---|---|---|---| | 1 | Get the fix onto release, then onto each open promote/* branch (the PR pipeline runs the scripts of the branch under test, so #4885 keeps the old resolver until its branch contains this change) | operator | next promotion | n/a | | 2 | Add a nightly or post-merge assertion that the stale-branch guard exits 0 on the most recent promote-shaped head (release with main merged in), so this class is caught before a promotion | sre-agent | 2026-11-14 | n/a | | 3 | Audit the remaining gates that compute base..HEAD for the same "HEAD has two parents" assumption (grep for HEAD^1, HEAD^2, rev-list --parents) | sre-agent | 2026-11-14 | n/a |

References