- the webmail's Send no longer files its own Sent copy: it asks Submit to
(FileSentCopy), the same path SMTP clients use, so the rule exists once
- every operation now locks the folders first (lowest id first) and the message
after. Opposite moves, and a move racing a flag change, deadlocked (SQLSTATE
40P01) because they took those locks in different orders; the new test
reproduces it (10-19 s of retries, errors) and passes in ~1 s with the order
- TestOneMailboxEverywhere drives SMTP, IMAP and the webmail on one mailbox,
mixing them, and checks after each step that every view agrees with the others
and with the rows. It fails on the previous code and passes now.
Flags, expunge, move, copy and folder deletion each existed twice: once for IMAP
(FlagRepository, ExpungeRepository, CopyRepository) and once for the webmail
(WebmailRepository). They kept the cached numbers true on their own and drifted:
- reading a message over IMAP never moved the folder's unread counter
- deleting in the webmail, or deleting a folder, never gave the quota back
- an IMAP expunge could push a counter below zero
MailStore now holds each state change once, in one transaction, with the same
rules everywhere: counters never go negative, a change that alters what a client
can observe raises the folder's modseq (one that alters nothing does not), the
quota follows the bytes, and a message is located by folder. The four repositories
are thin adapters that only translate how each path names a message.
The contract test added before this change (which failed on 8 of its cases)
now passes, as does the full suite.