Skip to content

fix(fr-gate): re-run the gate when a PR changes its base (backend#1945) - #338

Merged
LukasWodka merged 1 commit into
developfrom
fix/1945-fr-gate-edited-trigger
Aug 26, 2026
Merged

fix(fr-gate): re-run the gate when a PR changes its base (backend#1945)#338
LukasWodka merged 1 commit into
developfrom
fix/1945-fr-gate-edited-trigger

Conversation

@LukasWodka

@LukasWodkaLukasWodka commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

What

Adds edited to fr-gate-caller.yml's pull_request trigger types, plus a short comment
saying why it is there so it does not get "tidied" away later.

edited is the only event GitHub fires when a PR's base branch changes. Without it a
retargeted PR can never re-run its gate: synchronize needs a push, and a retarget has
nothing to push.

One file changed, +6/-1 — the types: 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 (developstaging/main/master) — fixed, and this is
the merge-blocking direction.
Today opened fires while the base is still develop, so
the branches: filter drops it and no gate / gate check run is ever created.
gate / gate is a required check on staging and main/master, so the PR sits at
"Expected — waiting for status to be reported" indefinitely. The only ways out are a push or
a gate-nudge label toggle, both of which need write access. With edited, the retarget
itself produces the run, with no manual action at all.

Retarget OUT of a gated branch (maindevelop) — NOT fixed by this change. This is
the direction backend#1945 measured on .github#237, so it matters that this PR does not
silently under-deliver. GitHub sends edited with the new base (develop); the
branches: filter is evaluated against that new base, does not match, and the workflow still
does 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:

  • I checked required_status_checks.contexts on develop for all 17 repos: gate / gate
    is required on none of them.
    (.github's develop lists a bare gate, which is
    conformance-gate.yml — on .github#237 that context was green while gate / gate was the
    red 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.
  • Closing it means widening or dropping branches: so the gate runs on the new base and
    reports the pass it already has a step for ("Target branch is not gated — nothing to
    enforce"). That would add a gate / gate run to every develop PR across 17 repos, which
    is a change to the check surface on the busiest branch and deserves its own decision.

Does the extra frequency cost anything?

edited also fires on title and body edits. Scope first: this workflow only runs on PRs whose
base is staging/main/master, so the population is release-train mirror PRs, hotfixes and
hotfix back-merges — machine-created, and rarely hand-edited. Ordinary develop PRs never
trigger 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 or
comment; 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 a
card 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/unlabeled already 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 edited also adds a
recovery 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 assumed

The ticket says caller-drift.py compares blob shas and therefore the fleet must merge every
other repo before .github. That does not apply to this file.caller-drift.py's design
rule 2 is "MATCH ON uses: CONTENT, NEVER ON FILENAME" — callers are parsed as YAML and their
resolved uses: values compared. Byte-for-byte comparison applies only to entries under
copies:, and copies: in repo-inventory.yml contains exactly one file, add-to-kanban.yml.
fr-gate.yml is listed under reusables/callers.

Adding a trigger type does not change the resolved uses: value, so the inventory needs no
edit and there is no merge-ordering constraint on this set of PRs.

Verification

  • python3 -c "import yaml, ..." parses each edited file, and the resolved types: list is
    asserted to be exactly [opened, reopened, synchronize, ready_for_review, labeled, unlabeled, edited] in all 17 repos. branches: is unchanged in every one.
  • actionlint clean on every edited file.
  • git diff --numstat is +6/-1 on the single path .github/workflows/fr-gate-caller.yml
    in every repo.
  • The 17-repo list was re-derived by enumerating all non-archived org repos and reading
    .github/workflows/fr-gate-caller.yml from each one's own default branch, not from a
    search index. claude-skills, release-train and rfcs carry 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 edited fires on a base change, and that
branches: is evaluated against the new base, is from GitHub's documented pull_request
behaviour — it is reasoning, not a measurement, and the second half is what the "NOT fixed"
section above turns on.

Closes tracebloc/backend#1945


Note

Low Risk
Workflow trigger-only change with no app logic; extra runs on title/body edits are limited to PRs targeting staging/main and only add read-only gate evaluations.

Overview
Adds edited to the pull_request trigger types in fr-gate-caller.yml so the FR gate re-runs when a PR is retargeted ontostaging or main. GitHub only emits edited on base-branch changes; without it, gate / gate could stay stale because synchronize never fires without a new push.

A short inline comment documents why edited must stay in the list. branches: is unchanged — retargets off gated branches still won’t run this workflow; this change targets the merge-blocking case where a PR moves onto a gated base.

Reviewed by Cursor Bugbot for commit da3f56f. Bugbot is set up for automated code reviews on this repo. Configure here.

`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>
@LukasWodkaLukasWodka self-assigned this Aug 26, 2026

@saadqbalsaadqbal left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

@LukasWodka
LukasWodka merged commit fd31ef4 into developAug 26, 2026
15 checks passed
@LukasWodka
LukasWodka deleted the fix/1945-fr-gate-edited-trigger branch August 26, 2026 08:15
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@LukasWodka@saadqbal