Commits
The repository now has three homes carrying the same history, and a Radicle
repository is findable only by its ID, so a README that leaves it out has left
out the one thing a reader needs in order to seed or clone it.
The clone command stays the https form. Documentation is read by people with
no account on the server and no key registered with it, and for them the ssh
URL fails with a permission error before it reaches the repository; the remote
itself stays ssh, because that is what pushes. `git ls-remote` over https
answers with no credentials, so the URL written here is one that works.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016LJuBzNgYqy1qhVusk5VZY
A maildir is a directory of three directories and one idea: a message is a
file whose name carries everything mutable about it. Delivery is an exclusive
create in `tmp` and a rename into `new`, so it needs no lock and is safe over
NFS; changing a flag is a rename, so a message file is written once and never
modified, which is what lets the `,S=` size in its name be trusted.
The library is that convention and nothing else. `Name` and `Flags` are pure
functions over bytes, `Maildir` is one mailbox, and `Store` is a Maildir++
tree with the `maildirsize` quota ledger covering it. Message content is
zig-mime's: `Message.parse` hands the bytes over and this library has no
opinion about what is in them, which is what lets it file a message it cannot
parse -- a message that has already arrived has to be filed whatever is in its
headers.
Two decisions are worth singling out. Flags keep every letter they were given,
not just the six that are defined, because Dovecot stores IMAP keywords as the
letters `a` to `z` and a library that dropped them would silently delete
labels a user applied. And `Name.parse` cannot fail: a name it does not
understand keeps its info verbatim and is written back byte for byte, because
refusing to list a message written in a dialect this library has not heard of
loses mail that is sitting right there.
A NixOS test runs a real Dovecot against a maildir this library wrote and
found two things worth knowing. Dovecot leaves a flagged message in `new`,
renaming it in place to `new/...,S=121:2,S`, which the specification says
should only ever happen in `cur` -- so a reader that took the rule literally
would show that message as unread forever. And a keyword survives a move
between folders only half way: the letter is part of the flags and travels,
but what the letter means lives in a `dovecot-keywords` file inside each
mailbox and does not, which is a limit of the format rather than of this code.
62 million fuzz inputs across the name, flag, folder and quota parsers, with
no findings. The name target asks that writing a parsed name twice changes
nothing and never touches `base`, because the name is the message's identity
and a round trip that is not a fixed point makes a message drift into a
different message.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016LJuBzNgYqy1qhVusk5VZY
The repository now has three homes carrying the same history, and a Radicle
repository is findable only by its ID, so a README that leaves it out has left
out the one thing a reader needs in order to seed or clone it.
The clone command stays the https form. Documentation is read by people with
no account on the server and no key registered with it, and for them the ssh
URL fails with a permission error before it reaches the repository; the remote
itself stays ssh, because that is what pushes. `git ls-remote` over https
answers with no credentials, so the URL written here is one that works.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016LJuBzNgYqy1qhVusk5VZY
A maildir is a directory of three directories and one idea: a message is a
file whose name carries everything mutable about it. Delivery is an exclusive
create in `tmp` and a rename into `new`, so it needs no lock and is safe over
NFS; changing a flag is a rename, so a message file is written once and never
modified, which is what lets the `,S=` size in its name be trusted.
The library is that convention and nothing else. `Name` and `Flags` are pure
functions over bytes, `Maildir` is one mailbox, and `Store` is a Maildir++
tree with the `maildirsize` quota ledger covering it. Message content is
zig-mime's: `Message.parse` hands the bytes over and this library has no
opinion about what is in them, which is what lets it file a message it cannot
parse -- a message that has already arrived has to be filed whatever is in its
headers.
Two decisions are worth singling out. Flags keep every letter they were given,
not just the six that are defined, because Dovecot stores IMAP keywords as the
letters `a` to `z` and a library that dropped them would silently delete
labels a user applied. And `Name.parse` cannot fail: a name it does not
understand keeps its info verbatim and is written back byte for byte, because
refusing to list a message written in a dialect this library has not heard of
loses mail that is sitting right there.
A NixOS test runs a real Dovecot against a maildir this library wrote and
found two things worth knowing. Dovecot leaves a flagged message in `new`,
renaming it in place to `new/...,S=121:2,S`, which the specification says
should only ever happen in `cur` -- so a reader that took the rule literally
would show that message as unread forever. And a keyword survives a move
between folders only half way: the letter is part of the flags and travels,
but what the letter means lives in a `dovecot-keywords` file inside each
mailbox and does not, which is a limit of the format rather than of this code.
62 million fuzz inputs across the name, flag, folder and quota parsers, with
no findings. The name target asks that writing a parsed name twice changes
nothing and never touches `base`, because the name is the message's identity
and a round trip that is not a fixed point makes a message drift into a
different message.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016LJuBzNgYqy1qhVusk5VZY