.
C The\sclone\sthat\scould\snot\ssign\sits\sfirst\srequest
D 2026-09-18T02:25:04.293
E 2026-09-18T02:25:04.293 16a4a2f9b5679325fa35d420ae9e753e21dc959b
N text/x-markdown
U dmestas
W 2220
# The clone that could not sign its first request
A login card is signed with a secret derived from the password and the
project code. A clone does not know the project code; learning it is what
the first reply is for. So a clone cannot sign its first request, and
fossil's client does not try: on a clone's round zero it sends no login at
all.
That leaves a read-gated repository with a puzzle. The server must refuse an
anonymous read, and it does, with an error card. But fossil's server puts
one more card in front of that refusal: `push SERVERCODE PROJECTCODE`. It
teaches the project code in the same breath as it refuses. And fossil's
client, on a clone's first round only, discards the error card, derives the
secret from the code it was just taught, and sends the clone card again with
a login. The refusal is the handshake.
zit's `clone` and `pull` sent no login at all, on any round. Only `push` and
`sync` did. A private repository on a forge that gates reads was unreadable
by the account that owned it, and the forge's deliberate 404, which reveals
nothing about whether the repository exists, pointed at nothing. A login
stored by an earlier push sat on disk while the next pull read anonymously.
0.3.22 resolves the login the same way for all four verbs: `--user`, then
the `user@` in the remote URL, then the stored login. A clone holds the name
and password until round zero names the project code, then signs every
later round, and a refused round zero that taught the code is the retry
point rather than a failure. The login the peer accepted is stored in the
new clone, so the next pull authenticates unasked.
Two things the shape decided. A user named only by the URL is a hint: with
no password to be had, the round goes anonymous and says which credential
it wanted, so the 404 finally points somewhere; an explicit `--user` with no
password is an error. And the prompt asks nothing off a terminal, because a
script or an autosync cannot answer it.
The proof runs against a real fossil with read stripped from `nobody` and
`anonymous`: an anonymous zit clone is refused, a clone with `--user` is
served through the round-zero retry, and a bare pull from that clone reuses
the stored login.
Z 75bc03f377867dbe776d11af9982cf6e