Repository navigation
fix(sqlite): stop holding a savepoint across local write authorization - #284
Draft
marcus-pousette wants to merge 2 commits into
Draft
marcus-pousette wants to merge 2 commits into
marcus-pousette wants to merge 2 commits into
Conversation
This was referenced Oct 30, 2026
marcus-pousette
force-pushed
the
fix/auth-local-write-interleaving
branch
from
November 1, 2026 19:50
751302a to
c7432c4
Compare
Auth-checked local writes opened a savepoint, minted the op, awaited authorizeLocalOps and released it as separate runner calls. Other calls on the same connection (crossTab tabs, sync appends, other auth writes) ran inside that savepoint: a denied write rolled them back, readers saw the unauthorized op, and a second auth write failed after committing. The local op SQL functions now take an optional authorized token. They mint the op and write it only if the token still matches the op and the materialized head; otherwise they return the op unwritten with a new token. The writer authorizes before writing, lets auth writes of a replica take turns, and gives up after four authorizations.
Main now opens OPFS databases in WAL mode (#283), so the summary includes journalMode.
marcus-pousette
force-pushed
the
fix/auth-local-write-interleaving
branch
from
November 2, 2026 11:40
c7432c4 to
5c8942a
Compare
This branch has not been deployed
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.
Auth-checked local writes held a savepoint across
await authorizeLocalOps, as separate runner calls. Anything else on the same connection could land inside it: anothercrossTabtab, sync appends, or a second auth write. On main:no such savepointafter its op committedFix
The op is authorized before anything is written, and no transaction spans the await.
treecrdt_local_insert/move/delete/payloadtake an optional trailing token. With a token, the function writes only if minting again gives the same op with no op applied in between (blake3 of the op JSON and the materializedhead_seq). Otherwise it writes nothing and returns the op with a newtokenandoutcome: null. PassingNULLonly mints.createTreecrdtSqliteWritermints, authorizes, then writes if unchanged, re-authorizing at most 4 times. Auth writes from the same replica take turns, and byte params are copied up front.API change: only the SQL functions change; the adapter and extension must update together.
LocalWriteOptionsis unchanged, butauthorizeLocalOpsnow sees the tree without the op, as peers and postgres-napi do, and may run more than once per write. A move from outside a scoped subtree is now denied locally, matching peers.This is the mechanism from the legacy drafts #193 and #195, without proof storage. Storing op auth atomically with the op is still #256: rows the auth session writes during authorization are not tied to the commit.
Tests
These fail on main:
crossTabtab keeps another tab's writeNew coverage for the token check (including a late remote op that leaves the op unchanged), the retry cap, and the payload copy.