Repository navigation
emrg: check-pr-base.py without --repo reads a fork and never says which repository answered #2629
Description
scripts/check-pr-base.py answers one question - can a merge into this PR's base still reach master - and when it is run without --repo it asks that question of whichever repository gh resolves from the remotes of the directory it runs in. On a checkout whose only GitHub remote is a fork, that is the fork, and nothing in the output names it: the per-PR lines, the summary line and the exit code all read as if they were about the repository the caller is merging into.
What was observed
On master 7e76668, in a checkout whose origin is a local directory and whose only GitHub remote is fork = pm25coder/emrg:
$ gh api "repos/{owner}/{repo}" -> pm25coder/emrg
The tool's own helpers were then asked the same question under both spellings:
_ref_is_on_master(<upstream master head 7e766683...>, None) -> False
_ref_is_on_master(<the same commit>, "argszero/emrg") -> True
One commit, one question, two answers, because master was read in two different repositories. The branch sets the verdict is classified against differ the same way: 50 branches resolved by default against 1159 upstream, so 1158 upstream branches are reported as
base branch 'chore/one-bounded-read-helper' no longer exists on the remote, so a merge
would have nowhere to land and could never reach master
- a fact about the fork, stated as a fact about the branch. The same base classified against the upstream reads differently ("is not on master and is not the head of any open PR"), i.e. the verdict is decidable only once you know which repository answered, and the output never said.
The exit code does not distinguish the two: with no open PRs in either repository the run printed nothing and exited 0 - a clean bill, about an unnamed repository.
What the fix must satisfy
- Without
--repo, when the resolved repository is a fork: refuse to measure (exit 2), naming the repository it read and the one that repository is a fork of, and saying that--repois how to name the repository to measure. - Without
--repo, when the resolved repository is not a fork: measure it as before, and print which repository that was, so an ordinary clone keeps working. - With
--repo: every existing reading is unchanged - same per-PR lines, same summary line, same exit codes - and the repository is printed before any verdict. {owner}/{repo}never reachesghas a path: resolution produces a concreteowner/name, or nothing is measured.- The sibling gates that already read the correct repository without
--repoare untouched.
Why it costs something
This is a merge gate: rc 0 is read as "every base reaches master", and a Committer merges on that reading. A gate that answers about a different repository - and does not say which - is worse than a missing gate, because the failure it hides is exactly the silent one. No sibling gate's green will ever expose it: each of them resolves the repository correctly on its own, so this tool's wrong reading is not downstream of anything another gate checks.
The shape is also the one a reader is least likely to question: rc 2 here currently means "the PR is closed, merged or nonexistent", and it in fact means "I read another repository". The reading that names the repository is the only one that separates those two sentences.
Activity
pm25coder commentedon Oct 29, 2026
Handled by #2630