Uh oh!
There was an error while loading. Please reload this page.
fix(fr-gate): re-run the gate when a PR changes its base - #140
Conversation
`edited` is the only pull_request event GitHub fires on a base-branch change. Without it a retargeted PR can never re-run fr-gate: synchronize needs a push, and a retarget has nothing to push. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
saadqbal
left a comment
There was a problem hiding this comment.
Correct, and the reasoning is the part worth keeping. edited really is the only pull_request action that fires on a base change — synchronize needs a push and a retarget has nothing to push — so without it a retargeted PR carries its old base's verdict with no event able to clear it. Citing the four-hour stale check on .github#237 rather than asserting the mechanism is the right form.
Checked the sibling PRs rather than assuming a fleet change is uniform: this and docs#140 / e2e-test-agent#256 have three different patch hashes, but the difference is only hunk offsets plus docs carrying master in an unchanged context line. The change itself is identical in all three.
One thing to be aware of rather than fix: edited also fires on title and body edits, so the gate now re-runs on every description tweak. Harmless while the gate is idempotent, and much cheaper than the bug it fixes — just don't be surprised by the extra runs.
Uh oh!
There was an error while loading. Please reload this page.
What
Adds
editedtofr-gate-caller.yml'spull_requesttrigger types, plus a short commentsaying why it is there so it does not get "tidied" away later.
editedis the only event GitHub fires when a PR's base branch changes. Without it aretargeted PR can never re-run its gate:
synchronizeneeds a push, and a retarget hasnothing to push.
One file changed,
+6/-1— thetypes:line and its five-line comment. Nothing else.What this fixes, and what it does not
The two retarget directions behave differently, because the caller also carries
branches: [staging, main(, master)]. I want that stated here rather than discovered later.Retarget INTO a gated branch (
develop→staging/main/master) — fixed, and this isthe merge-blocking direction. Today
openedfires while the base is stilldevelop, sothe
branches:filter drops it and nogate / gatecheck run is ever created.gate / gateis a required check onstagingandmain/master, so the PR sits at"Expected — waiting for status to be reported" indefinitely. The only ways out are a push or
a
gate-nudgelabel toggle, both of which need write access. Withedited, the retargetitself produces the run, with no manual action at all.
Retarget OUT of a gated branch (
main→develop) — NOT fixed by this change. This isthe direction backend#1945 measured on .github#237, so it matters that this PR does not
silently under-deliver. GitHub sends
editedwith the new base (develop); thebranches:filter is evaluated against that new base, does not match, and the workflow stilldoes not run — so the stale verdict from the old base survives.
Two things make that a follow-up rather than a blocker for this PR:
required_status_checks.contextsondevelopfor all 17 repos:gate / gateis required on none of them. (
.github's develop lists a baregate, which isconformance-gate.yml— on .github#237 that context was green whilegate / gatewas thered one.) So a stale red left by this direction is reviewer confusion and wasted time —
the real cost the ticket documents — but it does not block a merge.
branches:so the gate runs on the new base andreports the pass it already has a step for ("Target branch is not gated — nothing to
enforce"). That would add a
gate / gaterun to everydevelopPR across 17 repos, whichis a change to the check surface on the busiest branch and deserves its own decision.
Does the extra frequency cost anything?
editedalso fires on title and body edits. Scope first: this workflow only runs on PRs whosebase is
staging/main/master, so the population is release-train mirror PRs, hotfixes andhotfix back-merges — machine-created, and rarely hand-edited. Ordinary
developPRs nevertrigger it at all.
The job itself is read-only. It mints a short-lived scoped App token and reads
commits/{sha}/pulls,compare/...and the ProjectV2 board. It writes no card, label orcomment; its only output is its own conclusion. So the cost is runner minutes and nothing else.
Can a re-run turn a passing gate red?
Yes, by two mechanisms, and they deserve different answers.
1. The board moved — and that red is correct, not false. The verdict is a live read of each
attributed item's
Status. Automation is monotonic and never demotes, but a human can drag acard backward or remove it from the board, and either would flip a green gate red on the next
run. That is the gate reporting current truth. GitHub evaluates the merge button against the
latest check run, so a stale green on a required gate is precisely the failure this check
exists to prevent — evaluating more often makes it more accurate, not less. It is also not new
exposure:
labeled/unlabeledalready re-trigger on every label change.The item set itself is stable for a PR nobody pushes to. It is derived from
origin/$BASE_REF..HEAD; a base that advances can only shrink that range, never add items.2. Transient infrastructure — and this is the only genuine cost. The gate fails closed by
design: an App-token mint failure, a GraphQL 5xx, or an unattributable commit after three
retries all produce a red. A body edit could therefore turn a green promotion PR red for
reasons that have nothing to do with the PR.
I judge that acceptable, and mildly positive on balance, because
editedalso adds arecovery lever for exactly that case. Today clearing a bricked gate needs
gh run rerun(admin) or a label toggle (write) — which is why .github#237 sat red: the person who diagnosed
it had
read. Editing the PR body is available to the PR author. This makes the class of"required check stuck on a verdict nothing can update" strictly smaller.
repo-inventory.yml— no change needed, confirmed rather than assumedThe ticket says
caller-drift.pycompares blob shas and therefore the fleet must merge everyother repo before
.github. That does not apply to this file.caller-drift.py's designrule 2 is "MATCH ON
uses:CONTENT, NEVER ON FILENAME" — callers are parsed as YAML and theirresolved
uses:values compared. Byte-for-byte comparison applies only to entries undercopies:, andcopies:inrepo-inventory.ymlcontains exactly one file,add-to-kanban.yml.fr-gate.ymlis listed underreusables/callers.Adding a trigger type does not change the resolved
uses:value, so the inventory needs noedit and there is no merge-ordering constraint on this set of PRs.
Verification
python3 -c "import yaml, ..."parses each edited file, and the resolvedtypes:list isasserted to be exactly
[opened, reopened, synchronize, ready_for_review, labeled, unlabeled, edited]in all 17 repos.branches:is unchanged in every one.actionlintclean on every edited file.git diff --numstatis+6/-1on the single path.github/workflows/fr-gate-caller.ymlin every repo.
.github/workflows/fr-gate-caller.ymlfrom each one's own default branch, not from asearch index.
claude-skills,release-trainandrfcscarry no caller and are untouched.Not proven: the retarget path itself. Confirming it needs a PR to actually be retargeted,
which cannot be done from the diff. The claim that
editedfires on a base change, and thatbranches:is evaluated against the new base, is from GitHub's documentedpull_requestbehaviour — it is reasoning, not a measurement, and the second half is what the "NOT fixed"
section above turns on.
Refs tracebloc/backend#1945
Note
Low Risk
Single workflow trigger change with no application or secrets logic; main effect is more CI runs on PR metadata edits and correct re-runs when retargeting into gated branches.
Overview
Adds the
editedpull request event tofr-gate-caller.ymlso the reusable gate / gate check can run again when someone retargets a PR ontostaging,main, ormaster. GitHub only emitseditedfor a base-branch change; without it the gate never re-runs (no push → nosynchronize), which left required checks stuck at “waiting for status” after retargets (e.g. backend#1945).A short inline comment documents why
editedmust stay in the list so it is not removed as noise.branches:is unchanged, so retargeting off a gated branch still does not trigger this workflow; the PR description treats that as a separate follow-up becausegate / gateis not required ondevelop.editedalso fires on title/body edits, which can add extra read-only gate runs on release-train-style PRs and occasionally re-evaluate or fail closed on transient API errors—the author argues that tradeoff is acceptable and gives authors a way to nudge a stuck check without write access.Reviewed by Cursor Bugbot for commit 157a834. Bugbot is set up for automated code reviews on this repo. Configure here.