# zit 0.3.31

zit 0.3.31 makes `landing accept` merge exactly one branch tip, and lets a
caller refuse the accept if that tip isn't the one it checked.

No artifact, tag namespace, sync message, or on-disk repository format
changed.

## `landing accept` merges the tip it read, once

A forge checks a landing — CI, a preflight — against a particular branch tip
and then calls `zit landing accept`. If someone pushes to the branch in
between, the accept merged the new tip, which nothing had checked.

That window was wider than the caller's side of it. `accept` read the branch
tip up to three times: once to see whether it was already landed, once to
probe whether it merged cleanly, and once more when the merge itself resolved
the branch by name. So even a caller that re-read the tip immediately before
calling could have a push arrive mid-accept and be merged without having been
probed.

`accept` now reads the tip once, at the start, and merges that exact
check-in by hash — from a checkout and on a bare store with `-R` alike.
Later pushes stay on the branch, unlanded. This protects every caller,
whether or not it uses the new flag.

## `--expect-tip HASH`

A caller that checked a tip names it:

```
zit landing accept ID -R store --user NAME --expect-tip HASH
```

If the branch isn't at HASH, the accept is refused with **exit status 6**
and nothing is written:

```
zit landing: branch feat/x is at CURRENT, not HASH; nothing was written
```

Exit 6 is its own status so a caller can tell "the branch moved; check the
new tip and ask again" apart from exit 5 (conflicts, which need a human) and
exit 1 (an error). The flag is refused on the other `landing` subcommands.
Without it, `accept` behaves as before, except that it now merges a single
tip read.

`zit merge` needs no such flag: it already accepts an exact hash as NAME.

## Compatibility

- No on-disk repository or wire format changed; Fossil RFC revision 00
  remains the target.
- `zit landing accept` gains `--expect-tip HASH` and exit status 6.
- A push that lands on a branch while it is being accepted is no longer
  merged by that accept; it stays on the branch.

## Qualification

`zig fmt --check`, `zig build test`, `e2e`, `smoke`, `git-import-e2e`,
`git-export-e2e`, and `dst`, plus the three-runner CI battery.
