fix(calendar): stop EditEvent writing stale fields over concurrent edits - #11011
Closed
clayrisser wants to merge 1 commit into
Closed
fix(calendar): stop EditEvent writing stale fields over concurrent edits#11011clayrisser wants to merge 1 commit into
clayrisser wants to merge 1 commit into
Conversation
EditEvent seeds its editor state (title, description, dates, participants, ...) from `object` once, at component init. `object` is a live prop that the object-editor query re-assigns whenever the event changes on the server. saveEvent then diffs the one-time snapshot against the *live* document, so any field another client changed while the panel was open reads as "the user edited this" and is written back with the mount-time value. Capture the seed document and diff against that instead: a field the user did not touch now compares equal and is left out of the update, so the concurrent write survives. Co-authored-by: Cursor <cursoragent@cursor.com> Signed-off-by: Clay Risser <clayrisser@gmail.com> Co-authored-by: Cursor <cursoragent@cursor.com>
clayrisser
force-pushed
the
fix/edit-event-initial-snapshot
branch
from
August 13, 2026 06:47
fb0ea2c to
2123b18
Compare
Author
|
Closing — this was opened by an automated agent without my intent. Apologies for the noise. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
EditEvent.svelteseeds its editor state fromobjectonce, at component initialisation:But
objectis a live prop. The surrounding object-editor query re-assigns it whenever the event changes on the server.saveEventthen diffs the editor state against that live document rather than against the snapshot it was seeded from (EditEvent.svelte:81-123):So if another writer changes a field while the panel is open, that field now differs from the mount-time value the editor is still holding — which reads as "the user edited this" — and the stale mount-time value is written back over the newer one on the next Save.
The user gets no warning and sees no error. The save does exactly what it was asked to do.
All thirteen fields are affected:
title,description,visibility,calendar,location,timeZone,allDay,date,dueDate,participants,externalParticipants,reminders, and a recurring event'srules.Reproduction
title.location, and Save.Any concurrent writer reaches this: a second user, a second tab, or a sync pod writing back from an external calendar.
Fix
Capture the seed document, and diff against that:
and then
object.→initial.in the thirteen comparisons insidesaveEvent. A field the user did not touch now compares equal, stays out ofupdateentirely, and the concurrent write survives.The rest of the component is untouched:
objectremains the live prop everywhere else it is used, includingreadOnly.Scope and residual risk
update, so they are not written at all — which is the correct outcome and also reduces the size of the update transaction.saveEvent's comparison operands change; no new state, no new subscriptions, no lifecycle changes.One narrow sub-case worth naming: if a field was empty at mount and another writer set it since, the fix keeps it out of
updateentirely, so the newer value survives. Under the current code it would be written back asundefined. Whether thatundefinedcurrently unsets the field or is dropped by the ops layer, I have not tested — and the fix makes the question moot in both directions, because an untouched field never entersupdateat all.Verification
Verified against
develop@1be6047c8: all thirteen comparisons insaveEventstill diff against the liveobject, andobjectis still a live prop.git applyis clean.No automated test is offered, and I want to be straight about why:
plugins/calendar-resourceshas no jest project, and reproducing this needs a mounted Svelte component with a concurrently-mutating prop. The change is mechanical — one added line plus a rename of the comparison operand in thirteen places — and the reproduction above is the evidence. If you would like a test and can point me at the harness you would want it in, I am happy to add one.Provenance
Found while auditing write paths on a self-hosted deployment that has a second writer to calendar events. Reported as a code-reading result plus the manual reproduction above; I have not measured how often it fires in normal use.