A --repo selector that matches no repository in the manifest is treated as an empty success rather than as a user error.
Reproduction
$ gr pr merge --method merge --skip-gate approval --repo recall -y
Merging pull requests...
No open PRs found for any repository.
Repositories checked: 0
$ echo $?
0
There was an open, mergeable PR at that moment. It was not merged. The manifest name for that repository is synapt; recall is its name on GitHub, and the two differ. So the selector matched zero repos, and "merged every selected PR" is vacuously true over an empty set.
Why this is worse than a plain no-op
The output is success-shaped. The only honest signal is Repositories checked: 0, printed below the summary line and easy to read past — and any caller reading $? gets 0, which is the same value a real merge returns.
That matters because "check the exit code, not stdout" is the standard remedy when a tool's output is ambiguous. Here the exit code is the thing that is wrong, so the remedy does not help. An automated caller cannot distinguish merged your PR from matched nothing and stopped.
Expected
A selector names something the caller believes exists. Matching nothing is a user error:
- exit non-zero
- say what did not match, and offer the near miss:
no repo named 'recall' in the manifest; did you mean 'synapt' (./synapt)?
The near-miss hint matters here specifically because manifest names and GitHub repo names are allowed to differ, so this is a mistake the tool's own data model invites.
Scope
Same treatment belongs on every selector that can match empty, in every subcommand — this issue is filed from one measured instance in pr merge, not from a sweep. See also the sibling issue on gr pr merge returning 0 when a readiness gate refuses the merge; same root class (the exit code does not carry whether the intended act occurred), different fix.
A
--reposelector that matches no repository in the manifest is treated as an empty success rather than as a user error.Reproduction
There was an open, mergeable PR at that moment. It was not merged. The manifest name for that repository is
synapt;recallis its name on GitHub, and the two differ. So the selector matched zero repos, and "merged every selected PR" is vacuously true over an empty set.Why this is worse than a plain no-op
The output is success-shaped. The only honest signal is
Repositories checked: 0, printed below the summary line and easy to read past — and any caller reading$?gets0, which is the same value a real merge returns.That matters because "check the exit code, not stdout" is the standard remedy when a tool's output is ambiguous. Here the exit code is the thing that is wrong, so the remedy does not help. An automated caller cannot distinguish merged your PR from matched nothing and stopped.
Expected
A selector names something the caller believes exists. Matching nothing is a user error:
no repo named 'recall' in the manifest; did you mean 'synapt' (./synapt)?The near-miss hint matters here specifically because manifest names and GitHub repo names are allowed to differ, so this is a mistake the tool's own data model invites.
Scope
Same treatment belongs on every selector that can match empty, in every subcommand — this issue is filed from one measured instance in
pr merge, not from a sweep. See also the sibling issue ongr pr mergereturning 0 when a readiness gate refuses the merge; same root class (the exit code does not carry whether the intended act occurred), different fix.