A mutation reported success whenever the server answered OK. IMAP answers OK
for a UID command that matched nothing (RFC 3501 6.4.8), so a mutation that
lost a race to another client -- the message already moved, already deleted --
was recorded as completed having done nothing. The user's intent was silently
dropped and the outbox row was marked done.
Two states cannot express this. "Succeeded" and "failed" leave out the case
that actually occurs: the server accepted the command and its response does not
establish what happened. Collapsing that into either neighbour is the bug, so
mutations now return Applied, Conflict, or Unknown.
Applied requires positive evidence. A COPYUID naming destination UIDs proves a
move; a removal report proves a delete; an echoed FETCH proves a flag change.
Conflict requires positive evidence too -- a MODIFIED response code -- because
MODIFIED means "changed by someone else", never "gone". Everything else is
Unknown, which is the honest reading of an absent COPYUID: only SHOULD for MOVE
(RFC 6851 4.3), legitimately omitted for a UIDNOTSTICKY destination, and
indistinguishable from a UID set that matched nothing.
The outbox treats Unknown as retryable. A mutation that did apply and is
re-attempted is a no-op; one that did not and is recorded complete is
unrecoverable, so the asymmetry decides it. Conflict is terminal and visible
instead: the intent was formed against state that no longer exists, and
re-issuing it would either do nothing or overwrite someone else's change.
The delete path now reads its proof through the collecting layer, because a
QRESYNC-enabled server reports VANISHED rather than EXPUNGE (RFC 6851 4.4) and
the typed expunge stream only yields the latter -- reading it alone reports
nothing removed on every successful delete.
Refs #391