roll back optimistic create on remote conflict (0.5.0 / 0.4.0) - #22
Merged
Merged
Conversation
This was referenced Aug 28, 2026
This was referenced Aug 29, 2026
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
Store::createoptimistically wrote to memory + persistence + the offline queue, then on a live connection calledsync_create. A broker 409 Conflict (e.g. a unique-constraint collision) fell into a catch-all that only logged a warning and returnedOk(id); a 403 Ownership removed the queued insert but kept the local row and also returnedOk(id). Either way a client racing for an exclusive key (a seat/hold) gotOkplus a phantom local row — and because resync skips and re-creates ids with a pending queue entry, the phantom survived reconnect. The offline-queue flush additionally converted a losing insert into a blindsync_update(a latent overwrite of the winner).Fix
Store::createrolls back memory + persistence + the queued Insert and returnsErronConflict/Ownership; transient failures still queue and returnOk(id). OnlyOrigin::Localreaches this path, so mirror/resync/load writes are untouched.FlushSummary.conflicted_inserts).flush_loop/on_connectedthen roll the losing local row back, so a create that returnedOk(id)after a transient error and later lost the race converges to not-holding while continuously connected (previously it healed only on the next reconnect).Error::is_permanent_mutationnow classifies mqdbUniqueViolationas permanent.stitch-harnessgains.unique_constraint(entity, fields), registering a brokerSchema+ unique constraint so tests exercise a real 409.Versioning
Minor bump —
OfflineQueue::flushis public (pub mod queue) and its signature changed fromResult<usize>toResult<FlushSummary>, andcreatenow returnsErrwhere it returnedOk:stitch-sync0.4.0 → 0.5.0stitch-wasm0.3.0 → 0.4.0Verification
wasm32compile clean.Consumer note
A 409 only arises when the broker enforces the uniqueness.
mqdb-agenthas no primary-key collision onid(a duplicateidis a silent last-writer-wins overwrite), so an exclusive key must be a UNIQUE constraint on a non-idfield (e.g. a hold keyed by a randomidwithunique(seatId)).