mirror of
https://github.com/karatektus/pl_mail.git
synced 2026-10-25 10:04:18 +00:00
Calendar/get was the last method answering with the constant "fixed", left that way when CalendarEvent/changes landed on the argument that the gap was small: a user has a handful of calendars, Calendar/get returns all of them by default, so re-running it is cheap. True about cost, and beside the point. A state that never moves is a promise that nothing changed, and a client is entitled to believe it — so renaming a calendar left the old name in the sidebar until something unrelated forced a reload. calendar_change_log now records the collections as well. event_id and event_uid become nullable and their absence is what marks a row as being about the calendar itself — one discriminator, because an explicit target column beside a nullable id is a second thing to keep true and the two would eventually disagree in silence. A sibling table was the alternative and was rejected for costing a second sequence, a second repository and a second copy of the token arithmetic, which is the part with the subtle guards in it and therefore the last part worth having two of. Every reader filters, and that filter is load-bearing. sync-collection and CalendarEvent/changes take the rows with an event; Calendar/changes takes the rest. A reader that forgot would report a renamed calendar as a changed event and send a CalDAV client after an href built from a null UID, so both directions are asserted rather than only the happy one. App\Jmap\Calendar\CalendarState is deleted. Nothing answers with a constant any more, so the class explaining why anything did has no subject; the history it carried is folded into CalendarChangeLog and the listener, where someone meeting the design will actually be standing. ifInState is honoured rather than refused, and that reversal is the point rather than a side effect. The refusal was correct while the state was a constant — a guard that can never fail is worse than no guard, because a client relies on it — and with a real token the promise is one the server can keep. A client that read at one state and writes expecting it to still hold now gets stateMismatch instead of being allowed to overwrite what it never saw. Same protection If-Match gives a CalDAV client, from the same number. One bug fell out, and it is the event tombstone's mirror image. queueCollection deferred the calendar id to postFlush for every kind of change, which is right for an insert that has not got one yet and wrong for a delete: Doctrine clears the identifier once the row is gone, so the row recording a removal was the one silently dropped. Taken eagerly now wherever there is one. Also updates src/Jmap/README.md — 29 methods, and a note on why calendars count in their own log. No deployment change. One migration, relaxing two columns to nullable. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>