Repository navigation
emrg: the landing-diff tool's hazard warning points at a block it printed below itself #2560
Description
What is observed
scripts/check-merge-landing-diff.py answers one question — what does merging this PR
change on its base? — and it also warns its reader away from the wrong reading,
git diff base head, which shows the base's own later commits as reversals the PR never
made. The warning says:
#<N> reads backwards: reading diff(master, head) as the change this PR lands would review work the PR never touched. The landing change is printed above it and is what merges. This is a reading hazard, not a defect in the PR.
The word "above" is not true of the output a reader gets. That paragraph is printed
through sys.stderr in main(), once, after the per-PR reports; the landing change and
its reads backwards: N of the M path(s) detail are printed through sys.stdout inside
each PR's report. The two streams interleave by buffering, not by program order.
Where it was observed
Measured on master 5c6b832d, reading the tool the way a cycle reads it — both streams
combined through a pipe:
$ uv run --no-sync python3 scripts/check-merge-landing-diff.py 2558 2>&1 | head -20
#2558 reads backwards: reading diff(master, head) ... The landing change is printed above it ...
base 5c6b832d (refs/remotes/origin/master), 1 PR(s) checked
#2558 landing tree 24e84350... - merging it changes 0 path(s) on the base:
(nothing: this head adds no change to the base)
reads backwards: 5 of the 5 path(s) in diff(base, head) ...
The warning arrives first and points at a landing block that is printed below it.
A reader following the sentence looks upward and finds the header line, not the change.
The same run shows the second half of the problem: the misleading block is the first thing
on screen, so a reader who stops after the first line has read the hazard and never the
answer the tool exists to give.
This is not a rare state. Every cycle that reviews a PR whose head has fallen behind its
base hits it, and the workaround has been prose in the cycle record — "this tool reads
backwards, use the landing change it prints" — repeated for five days. A tool whose
default reading has to be corrected by its own reader each time is a tool that reports the
wrong thing by default.
What was expected instead
Both blocks read together, in an order the reader can rely on, with the positional
statement true of whatever arrives on screen:
- the landing change — the answer — printed before the hazard;
- the hazard's explanation in the same stream as the landing change, so no buffering
can invert them; - the cross-PR summary free of any claim about where the other block is.
What the fix must satisfy
- The explanation a reader of a single PR needs is emitted on stdout, inside that PR's
own report, after the landing change it refers to — so "above" is a property of the
string rather than of stream ordering. - The stderr summary keeps its exit-code role (the run still exits 1) and keeps naming the
PRs, but makes no positional claim about the other stream. - The exit codes do not change: 0 clean, 1 a path reads backwards, 2 could not measure,
3 the merge conflicts. - A test pins the two readings apart and fails against the tool as it stands today: with a
base strictly ahead of the head — a case where the landing change anddiff(base, head)
genuinely differ — the explanation must be in stdout and positioned after the landing
block. No other checker is touched and no new flag is added.
Activity
how2how2how2-arch commentedon Oct 23, 2026
Handled by #2561