Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .changeset/cold-electric-mutation-admission.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"@tanstack/db": patch
"@tanstack/db-sqlite-persistence-core": patch
"@tanstack/electric-db-collection": patch
---

Establish on-demand Electric stream positions before dispatching optimistic mutation handlers, including explicit multi-collection transactions. Revalidate positions after resets and prevent dispatch after cancellation or source retirement without preloading rows or retrying backend writes.
15 changes: 15 additions & 0 deletions docs/collections/electric-collection.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,21 @@ Each handler should call `await collection.utils.awaitTxId(txid)` to wait for sy

Handlers persist mutations to the backend and wait for Electric to sync the changes back. This prevents UI glitches where optimistic updates would be removed and then re-added. TanStack DB blocks sync data until the mutation is confirmed, ensuring smooth user experience.

For on-demand collections, optimistic changes appear immediately, but the
mutation handler waits until each participating Electric stream has established
its continuation position. You do not need to query or preload a collection
before inserting into it. This also applies to explicit transactions spanning
several collections. A stream reset before dispatch requires a fresh position;
rollback or a terminal source failure before dispatch prevents the write.

This preparation waits for stream evidence, not for source rows to become
visible. A handler must still await its transaction ID or match, and must not
wait for an on-demand query whose publication is held by its own transaction.
Persisted collections also wait for persistence startup to finish before
dispatch. This does not wait for row visibility. Cold writes require sync
connectivity. If confirmation fails after the handler has sent a write, the backend may already have committed it; the library does
not automatically repeat the handler.

### 1. Using Txid (Recommended)

The recommended approach uses PostgreSQL transaction IDs (txids) for precise matching. The backend returns a txid, and the client waits for that specific txid to appear in the Electric stream.
Expand Down
31 changes: 31 additions & 0 deletions docs/contributing/oracle-coverage.md
Original file line number Diff line number Diff line change
Expand Up @@ -6627,6 +6627,37 @@ retains exact source/evidence hashes and all ORC outcomes. Actual production
bundle erasure, Typedoc generation, tooling GREEN and restored-old-tooling
mutants remain required receiving checks. Generated docs remain CI-owned.

### Electric cold mutation admission

The `electric.sdk-mutation-startup` property in
`packages/electric-db-collection/tests/electric-sdk-delivery-oracle.property.test.ts`
checks the proposed stream-position admission contract through the installed
Electric SDK and controlled HTTP. Every generated history exercises direct and
manual inserts, a derived materialized descriptor after its original owner
retires, two participating collections in either release order, cancellation
before readiness, external abort, a prepared participant that resets while its
sibling waits, and retirement of a prepared participant. Three receiving paths
cross the real persistence wrapper with controlled managed storage: held startup
metadata followed by success, rejection with the same storage error, and cleanup
before the source enters. A twelfth path retires the run from its readiness
callback after an active batch was accepted: its transaction evidence remains
available, but its optimistic write is never dispatched. This is distinct from
a callback entering after retirement, which has no publication authority.
Every history reaches all thirteen declared paths, including a coordinator
index held after metadata and the Electric baseline arrive. Mutation dispatch
waits for that remaining persistence startup work to settle.
At each held baseline the mutation handler has not run; after all live source
positions are established it runs once and stays persisting until its txid echo.
The payload and release order vary in equal fixed/random campaigns. This owner
does not establish offline delivery, automatic write retries, native SQLite I/O,
prompt cancellation of held storage I/O, GC ownership, or arbitrary delayed
callback/restart interleavings. The persisted cleanup observation follows storage
release and cleanup completion; it promises no subsequent backend dispatch.
The same persisted-cleanup path records cache-claim requests and live claims,
plus coordinator subscriptions. Late metadata settlement cannot restart storage
or retain either resource. The generated release-order flag also varies whether
cleanup settles before metadata is released. This is controlled managed storage;
it does not establish native SQLite claim release or timer behavior.

### Replay successful-retirement ownership, October 30

Expand Down
Loading