Skip to content
zit Artifact [0dfbe9f28c]
Login

Artifact [0dfbe9f28c]

Artifact 0dfbe9f28c2a668616a152b6a7d6b10048cc1f28f3479c04edf4d751f4c95000:

Instance of technote [1ca5ef35af] - The refusal a fossil client could not read by dmestas on 2026-09-17 16:01:45.
C The\srefusal\sa\sfossil\sclient\scould\snot\sread
D 2026-09-17T16:01:45.725
E 2026-09-17T16:01:45.725 1ca5ef35afd9aa93aacc2aad4a39610a15f546e8
N text/x-markdown
U dmestas
W 1995
# The refusal a fossil client could not read

A zit server that rejects a request card resets its response and answers
with one error card. The sync draft writes two of those answers as prose,
`error bad command: LINE` and `error malformed CARD line`, and zit emitted
that prose word for word: real spaces between the words. The other refusals,
auth, clone sequence, sparse origin, content policy, went through the
encoder and arrived as the protocol's two tokens. These two did not.

A fossil client tokenizes an error card on the space. Two tokens is an error;
four is `error malformed` followed by two cards it does not know. It reports
them as unknown commands, discards the lot, and prints its success summary.
On a forge that ran for fifteen hours: every push said `Artifacts sent: 94`,
every push sent the same 94 again, and a fresh clone held none of them. `zit
push` against the same server said "the peer refused" in the same minute,
because zit's own client tolerates the malformed card, which is how the
bug hid from every test that used zit on both ends.

Fossil's server encodes the text before it writes the card; its source says
so in a comment on the emitter. The draft's card grammar says TEXT is
encoded too. The prose in two sections describes the text and was read as
describing the wire. That is an erratum against the draft's wording; the
meaning was never in doubt.

0.3.20 assembles every server error card at one point with its text encoded.
The wire texts the draft pins are unchanged; their spaces are `\s`. A test
drives every refusal variant through the emitter and fails on a raw space
after the operator, so a new fault cannot reintroduce it. And a stock fossil
that hits a zit policy refusal now stops, says why, and exits non-zero,
which is the whole point of refusing.

The same release closes a smaller trap: `zit remote list` saved the word
`list` as the remote. The parser now holds the argument to the http:// or
https:// address the help always promised.

Z 760d6f042cc36e68c395e32bdcf34d97