.
C The\stip\sthat\swas\schecked\sis\sthe\stip\sthat\slands
D 2026-09-26T18:59:29.955
E 2026-09-26T18:58:57 f995375dc68d148ef1785f9fa6976bc3b303a730
N text/x-markdown
U dmestas
W 2231
# The tip that was checked is the tip that lands
0.3.31 changes what `zit landing accept` merges. It is one line of intent
and it closes two windows, only one of which anybody had asked about.
The one that was asked about sits between a forge and zit. A forge runs its
checks against a landing — CI, a preflight probe — and each check is about
one particular check-in at the branch's tip. Then it calls
`zit landing accept`. If somebody pushes to the branch in between, the
accept merges the new tip, and nothing ever checked that. The forge had
narrowed the gap by re-reading the tip immediately before the call, but a
read in one process and a merge in another is still two moments.
The fix for that half is a name. `--expect-tip HASH` says which check-in the
caller checked; if the branch has moved, the accept is refused with nothing
written, and the message says where the branch is now. It exits 6, its own
status, because the right response is neither of the two that existed: exit
5 means the merge conflicts and a human has to resolve it, exit 1 means
something went wrong. Exit 6 means *check the new tip and ask again*, which
a forge can do without anyone looking.
The second window was inside zit, and it is why the flag alone would not
have been enough. `accept` read the branch tip three times: to see whether
the branch was already in the target, to probe whether it merged cleanly,
and once more when the merge itself resolved the branch by name. A push
landing between the probe and the merge was merged without having been
probed — and a forge that had re-read the tip, and passed it in, would have
been checking against the first read while the merge used the third.
So the tip is now read once, at the start, and every later step uses that
check-in's hash, never the branch's name: the probe, the merge from a
checkout, the merge on a bare store. Anything pushed during the accept stays
on the branch, unlanded, for the next one. The expected-tip comparison is
against that single read, which is what makes it mean something. This holds
for every caller, flag or not.
`zit merge` needed no such flag. It already takes an exact hash as the thing
to merge, which is what `accept` now does internally.
Z 09c2a17553fbeaa6c98dc2b4d623f35b