Measured at origin/main ccacf023, 2026-08-28. Two independent defects; the second makes the first worse rather than redundant.
1. The guard measures a quantity that decays after it runs
pr-base-freshness.yml fails when the PR's merge-base is more than MAX_BEHIND: 40 commits behind main. It triggers on pull_request only — opened/synchronize/reopened/edited. Every one of those is a branch event.
But the quantity it measures is a function of main, not of the branch. Main moves; the check does not re-run. So a PR that passed at 3 behind is at 94 behind three days later, with a green Stale-base merge guard row and nothing to re-evaluate it.
Sweep of all 76 open PRs, merge-base recomputed against ccacf023 (second read on mergeStateStatus, since the first is a cache):
- 49 are over the threshold.
- 36 of those read
CLEAN.
- Range: 41 to 139 behind.
#1081 and #1083 at 139, #1097 at 127, #1140 at 94, #1122/#1132 at 80.
Two confirmed instances of the stale green, run timestamps not inferred:
| PR |
behind today |
Stale-base merge guard |
when it ran |
| #1140 |
94 |
success |
2026-08-22T20:21:42Z |
| #1238 |
41 |
success |
2026-08-25T13:37:50Z |
The guard's own header comment is careful about exactly this class of gap — it explains at length why edited is load-bearing, because a retargeted child PR would otherwise "arrive already-passing on a check set it was never subject to". That is the same failure this issue reports, one axis over: here the PR was subject to the check, and the answer expired afterwards.
2. It is not a required check, so a red one would not block anyway
repos/Team-Commonly/commonly/branches/main/protection/required_status_checks:
{ "strict": false, "checks": [ { "context": "Test & Coverage", "app_id": 15368 } ] }
One required context. strict: false, so GitHub does not require the branch to be up to date either. The only ruleset on the repo (15758146 main branch) is disabled.
So Stale-base merge guard, Detect secrets, Package Version Guard, Service Tests, E2E Tests, Chart Lint and CodeQL are all advisory. A PR with any of them red merges; it just reads UNSTABLE (three currently do).
Why this matters beyond CI hygiene
The guard exists for #516 — a stale-base squash-merge that silently reverted intervening merged work, with a clean-looking GitHub diff because the diff is computed against the merge-base rather than the tip of main. That footgun is a property of the merge, not of the check. It is live right now on 36 PRs that display green.
Options, not a recommendation
- Add
Stale-base merge guard to the required contexts, or set strict: true — either makes the guard load-bearing, and strict: true subsumes it entirely.
- Re-evaluate on main's movement (a
push: branches: [main] job that re-dispatches, or a scheduled sweep) so the answer cannot go stale silently.
- Neither, and treat the guard as documentation — but then the green row should not read like an enforced gate.
I have not measured whether any merged PR actually reverted work this way; that is the natural next question and it needs a different instrument (comparing merge-base diffs against main at press time).
Not filed as a fix because which of the three is right is a repo-policy decision, not a defect with one correct repair.
Measured at
origin/mainccacf023, 2026-08-28. Two independent defects; the second makes the first worse rather than redundant.1. The guard measures a quantity that decays after it runs
pr-base-freshness.ymlfails when the PR's merge-base is more thanMAX_BEHIND: 40commits behind main. It triggers onpull_requestonly —opened/synchronize/reopened/edited. Every one of those is a branch event.But the quantity it measures is a function of main, not of the branch. Main moves; the check does not re-run. So a PR that passed at 3 behind is at 94 behind three days later, with a green
Stale-base merge guardrow and nothing to re-evaluate it.Sweep of all 76 open PRs, merge-base recomputed against
ccacf023(second read onmergeStateStatus, since the first is a cache):CLEAN.#1081and#1083at 139,#1097at 127,#1140at 94,#1122/#1132at 80.Two confirmed instances of the stale green, run timestamps not inferred:
Stale-base merge guardThe guard's own header comment is careful about exactly this class of gap — it explains at length why
editedis load-bearing, because a retargeted child PR would otherwise "arrive already-passing on a check set it was never subject to". That is the same failure this issue reports, one axis over: here the PR was subject to the check, and the answer expired afterwards.2. It is not a required check, so a red one would not block anyway
repos/Team-Commonly/commonly/branches/main/protection/required_status_checks:{ "strict": false, "checks": [ { "context": "Test & Coverage", "app_id": 15368 } ] }One required context.
strict: false, so GitHub does not require the branch to be up to date either. The only ruleset on the repo (15758146 main branch) is disabled.So
Stale-base merge guard,Detect secrets,Package Version Guard,Service Tests,E2E Tests,Chart Lintand CodeQL are all advisory. A PR with any of them red merges; it just readsUNSTABLE(three currently do).Why this matters beyond CI hygiene
The guard exists for #516 — a stale-base squash-merge that silently reverted intervening merged work, with a clean-looking GitHub diff because the diff is computed against the merge-base rather than the tip of main. That footgun is a property of the merge, not of the check. It is live right now on 36 PRs that display green.
Options, not a recommendation
Stale-base merge guardto the required contexts, or setstrict: true— either makes the guard load-bearing, andstrict: truesubsumes it entirely.push: branches: [main]job that re-dispatches, or a scheduled sweep) so the answer cannot go stale silently.I have not measured whether any merged PR actually reverted work this way; that is the natural next question and it needs a different instrument (comparing merge-base diffs against main at press time).
Not filed as a fix because which of the three is right is a repo-policy decision, not a defect with one correct repair.