# Pylon: Sync Semantics This document describes what Pylon syncs, what converges as a CRDT, and where the server is still authoritative. ## The honest one-liner **Pylon is a server-backed realtime sync system with a CRDT row substrate.** Each CRDT-mode entity row is backed by a Loro document, projected into the normal SQLite/Postgres row shape for queries and indexes, and broadcast to clients over the same WebSocket used by live queries. The important nuance: not every field has the same merge behavior. `richtext` and fields marked `crdt: "text"` use `LoroText` and merge concurrent text edits. Most scalar fields use LWW registers inside the row doc because names, emails, statuses, slugs, and timestamps do not benefit from character-level merge. ## Two sync layers ### 1. JSON live-query projection The React `db.useQuery(...)` path consumes ordinary JSON row changes: 1. Client opens a WebSocket to the Pylon server. 2. `useQuery` subscribes to an entity/filter pair. 3. The server runs the query once and sends the current matching rows. 4. Writes append to the change log. 5. Matching subscribers receive row diffs. 6. The client applies diffs to an IndexedDB-backed local replica. This layer is what powers live dashboards, lists, search results, policies, pagination, and the normal `db.insert/update/delete` APIs. JSON mutations are optimistic. The client applies them locally, stores pending work in the IndexedDB mutation queue, and retries with an `op_id` so server replays are idempotent. Deletes use tombstones so stale replay cannot resurrect a row. ### 2. Loro row documents For CRDT-mode entities, the persisted row is also represented as one Loro doc: ```text LoroDoc map "row" fieldName -> LWW scalar, LoroText, or another CRDT container ``` The Rust runtime owns the canonical server copy. On insert/update, Pylon applies the patch to the Loro doc, projects the doc back to a flat JSON object, stores that projection in the database, appends a normal change-log event, and sends a binary CRDT snapshot to subscribed clients. Clients that need raw CRDT behavior use `@pylonsync/loro`: ```tsx import { useCollabText } from "@pylonsync/loro"; export function Editor({ noteId }: { noteId: string }) { const [body, setBody] = useCollabText("Note", noteId, "body"); return