# zit 0.3.22

zit 0.3.22 reads a private repository. `clone` and `pull` authenticate the
way `push` and `sync` already did, and a clone learns to sign its login the
way fossil's does.

No artifact, tag namespace, sync message, or on-disk repository format
changed. Two verbs gained `--user` and `--password`; a `user@` in a remote
URL now counts for every verb that syncs.

## `clone` and `pull` send a login card

Only `push` and `sync` derived a shared secret and signed a login card.
`clone` and `pull` sent nothing, so a private repository on a forge that
gates reads was unreadable by the account that owned it. The forge's answer
to an anonymous read of a private repository is a deliberate 404, since a
403 would confirm the repository exists, so the operator saw "not found" for
a repository they administer, with nothing pointing at credentials. A stored
login from an earlier push sat on disk while the next pull read anonymously.

The login is now resolved the same way for all four verbs, in this order:
`--user`, the `user@` component of the remote URL (given or saved), then the
login a previous authenticated round stored in the repository. None of the
three means anonymous, as before. The password comes from `--password`,
`$ZIT_PASSWORD`, or a no-echo prompt on a terminal; a stored login needs
none. A freshly derived secret is stored only after the peer accepted it.

## A clone signs from round one, after a refusal

A clone cannot sign its first request: the shared secret is derived from the
project code, and the project code is what the first reply teaches. fossil's
client therefore sends no login on a clone's first round, and its server,
refusing an anonymous read, still answers with the project code and an
error card. The fossil client discards that error on round zero, derives the
secret from the code it was just taught, and sends the clone card again with
a login.

zit's clone now does the same. It holds the name and password until the
round-zero reply names the project code, then signs every later round. A
refused round zero that taught the project code is the retry point rather
than a failure; a refused round zero with no login to retry with is still
the failure it was, reported as the peer's words. The login the peer
accepted is stored in the new repository, so the next `pull` or `push` from
that clone authenticates without being told.

## Verification

- Parser tests for `--user` and `--password` on `pull` and `clone`, and for
  the `user@` extraction, which never yields a URL password.
- Sync-core tests: a clone with a pending login sends no round-zero card and
  a login card on the next round; a refused anonymous round zero that taught
  the project code is retried with the login, and without a login it aborts.
- A new fossil interop smoke scenario: a fossil repository with read
  stripped from `nobody` and `anonymous` refuses an anonymous zit clone,
  serves one with `--user`, and a bare `zit pull` from that clone reuses the
  stored login. Seventeen scenarios now run against a real fossil.

## Compatibility

- No on-disk repository or wire format changed; Fossil RFC revision 00
  remains the target.
- A repository that stores a login is written owner-only, as a push already
  did.
- Anonymous clone and pull behave exactly as before when no user is given,
  no `user@` is in the URL, and no login is stored.

## Qualification

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