Skip to content

Clarify local write status docs and pending sync contract#1652

Merged
KyleAMathews merged 6 commits into
mainfrom
docs-tests-write-status-contract
Jul 9, 2026
Merged

Clarify local write status docs and pending sync contract#1652
KyleAMathews merged 6 commits into
mainfrom
docs-tests-write-status-contract

Conversation

@KyleAMathews

@KyleAMathews KyleAMathews commented Jul 7, 2026

Copy link
Copy Markdown
Collaborator

Summary

Clarifies TanStack DB's existing local write status docs and tightens the core pending-sync contract around optimistic temp-key inserts. User-visible docs now distinguish local optimistic write state from backend upload/read-path confirmation, and the core test makes explicit that ambiguous server-key sync is not exposed while the local mutation is still pending.

Root cause

$synced and tx.isPersisted.promise were easy to read as backend confirmation APIs. In practice, they describe TanStack DB's local transaction/projection state: a row may have no pending local optimistic mutation without proving backend read-back, and a transaction may settle without representing a generic sync-observation guarantee.

Approach

  • Reword $synced JSDoc to describe whether a row currently has pending local optimistic mutations in the collection's visible projection.
  • Reword isPersisted.promise JSDoc to describe transaction settlement, including rollback/failure, while noting that non-empty commits normally settle through the mutation function.
  • Tighten the core collection test for an optimistic insert using a temporary key followed by synced data under a different server key. While the mutation is pending, the possible server-key echo stays queued and the collection does not expose both rows.
  • Add a changeset for @tanstack/db.

Key invariants

  • $synced is local write/projection status; it is not backend upload, confirmation, or read-path observation.
  • tx.isPersisted.promise is the promise to await for transaction settlement; callers should not await the deferred object itself.
  • Without explicit temp-key to server-key mapping, core must not expose both an optimistic temp row and a possible server-key echo while the mutation function is still pending.

Non-goals

  • No new public write status APIs in this PR.
  • No mutation log rewrite.
  • No generic immediate sync application while mutation functions are pending.
  • No temp-key/server-key mapping or mutation receipts.
  • No generated reference docs updates; this PR updates the source JSDoc that feeds them.

Verification

pnpm --filter @tanstack/db exec vitest run tests/collection.test.ts --pool-options.threads.maxThreads=2
pnpm --filter @tanstack/db exec tsc --noEmit

Files changed

  • .changeset/clarify-local-write-status.md — records the patch-level docs/test clarification for @tanstack/db.
  • packages/db/src/virtual-props.ts — clarifies $synced as local pending optimistic write state.
  • packages/db/src/transactions.ts — clarifies isPersisted.promise transaction settlement semantics.
  • packages/db/src/collection/state.ts — aligns an internal $synced helper comment with the new wording.
  • packages/db/tests/collection.test.ts — makes the ambiguous temp/server-key pending sync contract explicit.

Refs #20, #661, #1017, #1166, #1215, #1219, #1322, #1431, #1526.

Summary by CodeRabbit

  • Documentation
    • Clarified that local sync indicators (for $synced and row sync status) reflect pending local optimistic writes, not backend-confirmed state.
    • Expanded guidance on isPersisted.promise lifecycle semantics.
  • Bug Fixes
    • Ensured server-generated keys from ambiguous sync are not exposed until the related optimistic insert has finished persisting.
  • Tests
    • Updated and added coverage for the queued server-key sync scenario while a temp-key optimistic insert is still pending.

@coderabbitai

coderabbitai Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 4eaa4aa6-d2fd-4eda-b2de-36587418c4b8

📥 Commits

Reviewing files that changed from the base of the PR and between b5e76e0 and 4bbc268.

📒 Files selected for processing (2)
  • packages/db/src/collection/state.ts
  • packages/db/src/virtual-props.ts
✅ Files skipped from review due to trivial changes (2)
  • packages/db/src/collection/state.ts
  • packages/db/src/virtual-props.ts

📝 Walkthrough

Walkthrough

This PR clarifies documentation for $synced, isRowSynced, and isPersisted to specify that they reflect local optimistic mutation and settlement status rather than backend confirmation. It also updates a collection test to assert that server-generated keys remain hidden while a persist transaction is pending, and adds a changeset.

Changes

Write-status semantics clarification

Layer / File(s) Summary
Source JSDoc clarifications for isPersisted and isRowSynced
packages/db/src/transactions.ts, packages/db/src/collection/state.ts
Expands isPersisted JSDoc to describe promise settlement tied to mutationFn completion rather than backend confirmation; revises isRowSynced comment to describe pending local optimistic mutations.
Virtual $synced property documentation and examples
packages/db/src/virtual-props.ts
Rewrites $synced JSDoc and examples to describe local write/projection status, renames the example variable, and updates example log text accordingly.
Changeset and collection test for ambiguous server-key sync during pending insert
.changeset/clarify-local-write-status.md, packages/db/tests/collection.test.ts
Adds a changeset documenting the clarification; renames a test scenario and adds assertions that the server-generated key is not exposed while the persist transaction is pending, becoming visible only after settlement.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related PRs

  • TanStack/db#1547: Overlaps directly with handling and tests for replacing stale optimistic temp-key rows when txid sync confirms a server-generated key.

Suggested reviewers: samwillis

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and accurately summarizes the docs-focused local write status and pending sync clarification.
Description check ✅ Passed It covers the change, motivation, verification, and changeset impact, even though it uses custom section names instead of the template.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch docs-tests-write-status-contract

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@pkg-pr-new

pkg-pr-new Bot commented Jul 7, 2026

Copy link
Copy Markdown
More templates

@tanstack/angular-db

npm i https://pkg.pr.new/@tanstack/angular-db@1652

@tanstack/browser-db-sqlite-persistence

npm i https://pkg.pr.new/@tanstack/browser-db-sqlite-persistence@1652

@tanstack/capacitor-db-sqlite-persistence

npm i https://pkg.pr.new/@tanstack/capacitor-db-sqlite-persistence@1652

@tanstack/cloudflare-durable-objects-db-sqlite-persistence

npm i https://pkg.pr.new/@tanstack/cloudflare-durable-objects-db-sqlite-persistence@1652

@tanstack/db

npm i https://pkg.pr.new/@tanstack/db@1652

@tanstack/db-ivm

npm i https://pkg.pr.new/@tanstack/db-ivm@1652

@tanstack/db-sqlite-persistence-core

npm i https://pkg.pr.new/@tanstack/db-sqlite-persistence-core@1652

@tanstack/electric-db-collection

npm i https://pkg.pr.new/@tanstack/electric-db-collection@1652

@tanstack/electron-db-sqlite-persistence

npm i https://pkg.pr.new/@tanstack/electron-db-sqlite-persistence@1652

@tanstack/expo-db-sqlite-persistence

npm i https://pkg.pr.new/@tanstack/expo-db-sqlite-persistence@1652

@tanstack/node-db-sqlite-persistence

npm i https://pkg.pr.new/@tanstack/node-db-sqlite-persistence@1652

@tanstack/offline-transactions

npm i https://pkg.pr.new/@tanstack/offline-transactions@1652

@tanstack/powersync-db-collection

npm i https://pkg.pr.new/@tanstack/powersync-db-collection@1652

@tanstack/query-db-collection

npm i https://pkg.pr.new/@tanstack/query-db-collection@1652

@tanstack/react-db

npm i https://pkg.pr.new/@tanstack/react-db@1652

@tanstack/react-native-db-sqlite-persistence

npm i https://pkg.pr.new/@tanstack/react-native-db-sqlite-persistence@1652

@tanstack/rxdb-db-collection

npm i https://pkg.pr.new/@tanstack/rxdb-db-collection@1652

@tanstack/solid-db

npm i https://pkg.pr.new/@tanstack/solid-db@1652

@tanstack/svelte-db

npm i https://pkg.pr.new/@tanstack/svelte-db@1652

@tanstack/tauri-db-sqlite-persistence

npm i https://pkg.pr.new/@tanstack/tauri-db-sqlite-persistence@1652

@tanstack/trailbase-db-collection

npm i https://pkg.pr.new/@tanstack/trailbase-db-collection@1652

@tanstack/vue-db

npm i https://pkg.pr.new/@tanstack/vue-db@1652

commit: 4bbc268

@github-actions

github-actions Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Size Change: +80 B (+0.06%)

Total Size: 125 kB

📦 View Changed
Filename Size Change
packages/db/dist/esm/collection/state.js 5.48 kB +80 B (+1.48%)
ℹ️ View Unchanged
Filename Size
packages/db/dist/esm/collection/change-events.js 1.43 kB
packages/db/dist/esm/collection/changes.js 1.38 kB
packages/db/dist/esm/collection/cleanup-queue.js 810 B
packages/db/dist/esm/collection/events.js 434 B
packages/db/dist/esm/collection/index.js 3.62 kB
packages/db/dist/esm/collection/indexes.js 1.99 kB
packages/db/dist/esm/collection/lifecycle.js 1.69 kB
packages/db/dist/esm/collection/mutations.js 2.47 kB
packages/db/dist/esm/collection/subscription.js 3.74 kB
packages/db/dist/esm/collection/sync.js 2.88 kB
packages/db/dist/esm/collection/transaction-metadata.js 144 B
packages/db/dist/esm/deferred.js 207 B
packages/db/dist/esm/errors.js 5.1 kB
packages/db/dist/esm/event-emitter.js 748 B
packages/db/dist/esm/index.js 3.16 kB
packages/db/dist/esm/indexes/auto-index.js 829 B
packages/db/dist/esm/indexes/base-index.js 767 B
packages/db/dist/esm/indexes/basic-index.js 2.06 kB
packages/db/dist/esm/indexes/btree-index.js 2.19 kB
packages/db/dist/esm/indexes/index-registry.js 820 B
packages/db/dist/esm/indexes/reverse-index.js 557 B
packages/db/dist/esm/live-query-adapter.js 318 B
packages/db/dist/esm/local-only.js 916 B
packages/db/dist/esm/local-storage.js 2.12 kB
packages/db/dist/esm/optimistic-action.js 359 B
packages/db/dist/esm/paced-mutations.js 496 B
packages/db/dist/esm/proxy.js 3.75 kB
packages/db/dist/esm/query/builder/functions.js 1.47 kB
packages/db/dist/esm/query/builder/index.js 5.84 kB
packages/db/dist/esm/query/builder/ref-proxy.js 1.24 kB
packages/db/dist/esm/query/compiler/evaluators.js 1.89 kB
packages/db/dist/esm/query/compiler/expressions.js 430 B
packages/db/dist/esm/query/compiler/group-by.js 3.56 kB
packages/db/dist/esm/query/compiler/index.js 6.67 kB
packages/db/dist/esm/query/compiler/joins.js 2.5 kB
packages/db/dist/esm/query/compiler/lazy-targets.js 923 B
packages/db/dist/esm/query/compiler/order-by.js 1.74 kB
packages/db/dist/esm/query/compiler/select.js 1.53 kB
packages/db/dist/esm/query/effect.js 4.77 kB
packages/db/dist/esm/query/expression-helpers.js 1.43 kB
packages/db/dist/esm/query/ir.js 1.25 kB
packages/db/dist/esm/query/live-query-collection.js 360 B
packages/db/dist/esm/query/live/collection-config-builder.js 9.1 kB
packages/db/dist/esm/query/live/collection-registry.js 264 B
packages/db/dist/esm/query/live/collection-subscriber.js 1.93 kB
packages/db/dist/esm/query/live/internal.js 145 B
packages/db/dist/esm/query/live/utils.js 1.81 kB
packages/db/dist/esm/query/optimizer.js 2.92 kB
packages/db/dist/esm/query/predicate-utils.js 2.97 kB
packages/db/dist/esm/query/query-once.js 359 B
packages/db/dist/esm/query/subset-dedupe.js 960 B
packages/db/dist/esm/scheduler.js 1.3 kB
packages/db/dist/esm/SortedMap.js 1.3 kB
packages/db/dist/esm/strategies/debounceStrategy.js 247 B
packages/db/dist/esm/strategies/queueStrategy.js 428 B
packages/db/dist/esm/strategies/throttleStrategy.js 246 B
packages/db/dist/esm/transactions.js 3.04 kB
packages/db/dist/esm/utils.js 927 B
packages/db/dist/esm/utils/array-utils.js 273 B
packages/db/dist/esm/utils/browser-polyfills.js 304 B
packages/db/dist/esm/utils/btree.js 5.61 kB
packages/db/dist/esm/utils/comparison.js 1.11 kB
packages/db/dist/esm/utils/cursor.js 457 B
packages/db/dist/esm/utils/index-optimization.js 2.39 kB
packages/db/dist/esm/utils/type-guards.js 157 B
packages/db/dist/esm/utils/uuid.js 449 B
packages/db/dist/esm/virtual-props.js 360 B

compressed-size-action::db-package-size

@github-actions

github-actions Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Size Change: 0 B

Total Size: 4.22 kB

ℹ️ View Unchanged
Filename Size
packages/react-db/dist/esm/index.js 249 B
packages/react-db/dist/esm/useLiveInfiniteQuery.js 1.32 kB
packages/react-db/dist/esm/useLiveQuery.js 1.33 kB
packages/react-db/dist/esm/useLiveQueryEffect.js 355 B
packages/react-db/dist/esm/useLiveSuspenseQuery.js 567 B
packages/react-db/dist/esm/usePacedMutations.js 401 B

compressed-size-action::react-db-package-size

}

/**
* Checks if a row has pending optimistic mutations (not yet confirmed by sync).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I find "(not yet confirmed by sync)" clearer than "in the visible projection"

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One of the clarifications this PR is trying to make is that not all "confirmations by the collection" means that the write has been persisted to the backend e.g. powersync just confirms when the write is in the local sqlite. I pushed this commit which hopefully is clearer 4bbc268

@KyleAMathews KyleAMathews merged commit eabcea7 into main Jul 9, 2026
12 checks passed
@KyleAMathews KyleAMathews deleted the docs-tests-write-status-contract branch July 9, 2026 15:33
@github-actions github-actions Bot mentioned this pull request Jul 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants