# zit 0.3.21

zit 0.3.21 accepts a stock fossil push that carries more than one check-in,
and accepts the request type fossil sends under `--httptrace`.

No artifact, tag namespace, or on-disk repository format changed. One
server error card is new, and one request media type is no longer refused.

## A multi-check-in push lands

fossil sends a batch of check-ins as one round, with each manifest a delta
against the previous one. The server scans the round before it stores
anything, so a rejected request leaves no trace, and the scan reconstructed
each pushed delta against the committed store. A manifest delivered earlier
in the same round is not committed yet. The lookup failed, and the failure
was reported as a malformed file card.

The consequence was that any push of two or more check-ins from a stock
fossil client was refused, and the only workaround was pushing one check-in
at a time, which nobody would guess. Single-check-in rounds, including ones
with several file cards, were unaffected, which is why every existing
interop test passed. It cost a tester two days, most of them spent on card
syntax because the refusal said "malformed".

The scan now parks a delta whose basis is not held and settles it once the
whole round has been seen. A basis is either committed or was delivered by
this round, possibly as another parked delta, so resolution runs to a
fixpoint and the sender's order within the round does not matter. Whatever
is still unresolved names a basis the round never carried and the store
never held, and that refusal now says so:

```
error delta basis not held: TARGET against BASIS
```

Two unit tests push a delta against a basis delivered earlier and later in
the same round, the second through a chain of two deltas. A new fossil
interop smoke scenario clones a served zit repository with stock fossil,
commits three times offline, pushes once, and checks all three check-ins
are in the served store. It fails against 0.3.20.

## `--httptrace` reaches a zit server

fossil's `--httptrace` sends its request uncompressed under the media type
`application/x-fossil-debug`. The server refused that type with a bare 415,
on the stated premise that the reference client never sends it. It does,
and it is the first thing anyone reaches for when a sync misbehaves, so the
diagnostic was refused in the one situation it exists for.

The type is accepted. The exchange tells the request handler whether the
body is a zlib container or plain cards, and the handler decodes or copies
accordingly. The reply is framed as before; fossil picks the reply's framing
off the reply's own content type. `application/x-fossil-uncompressed`
remains reply-only and is still refused on a request.

## Compatibility

- No on-disk repository or wire format changed; Fossil RFC revision 00
  remains the target.
- A pushed delta with no basis anywhere is refused with a new named error
  card in place of "malformed file line". The draft's own rule for this case
  is to park the delta and create a phantom; a stateless server cannot park
  it across requests, so the refusal stays, and now says why.
- Any client's `application/x-fossil-debug` request is answered rather than
  refused.

## Qualification

`zig fmt --check`, `zig build test`, `e2e`, `smoke` (Fossil interop against
a real `fossil`, now sixteen scenarios), `muscle`, `git-import-e2e`,
`git-export-e2e`, `dst`, and `cross`, plus the three-runner CI battery.
