Skip to content

feat(sync): add a race-safe outbound controller#137

Open
marcus-pousette wants to merge 1 commit into
cybersemics:mainfrom
marcus-pousette:sync/app-facing-controller
Open

feat(sync): add a race-safe outbound controller#137
marcus-pousette wants to merge 1 commit into
cybersemics:mainfrom
marcus-pousette:sync/app-facing-controller

Conversation

@marcus-pousette

@marcus-pousette marcus-pousette commented May 5, 2026

Copy link
Copy Markdown
Collaborator

What this does

Adds createOutboundSync, an application-facing controller for publishing exact committed local operations through one SyncPeer and one or more outbound transports.

Applications report a local edit once with queueOps(...). The controller wakes low-level live subscriptions, deduplicates pending TreeCRDT operations by operation ID, and keeps exact outbound upload queued until a target is available and online.

Transport discovery, websocket UI, inbound subscription filters, and playground adoption are intentionally outside this PR.

Correctness guarantees

  • A push timeout aborts the logical SyncPeer.pushOps operation; it cannot continue signing or sending later chunks after the controller retries.
  • Replacing/removing targets aborts the active snapshot and replays its operations against the current target set.
  • flush() is a shared drain barrier: concurrent callers receive the same promise and wait for work queued during the active run.
  • Repeated attachTarget(id, sameTransport) calls share one peer attachment and use reference-counted, idempotent cleanup. Stale cleanup cannot detach a replacement transport.
  • Push failures restore the exact batch ahead of newly queued work without creating an unconditional retry loop.
  • onStatus, onError, and rejected local-update notifications cannot corrupt queue state or create unhandled rejections.
  • close() aborts active work, clears queued operations, and detaches targets without restoring the cleared snapshot later.

Fast paths and limits

  • Empty batches are ignored.
  • Duplicate queued TreeCRDT operations coalesce by meta.id; custom op shapes may provide opKey.
  • Offline/no-target flushes retain work without network activity or error callbacks.
  • Calls without a push timeout or abort signal keep the existing protocol path and wire format.
  • Cancellation cannot retract one transport frame whose send() has already begun. It prevents later frames and session continuation; a late valid frame remains safe because operation IDs are idempotent.

Debloated from the original PR

  • 8 files instead of 15.
  • Removes playground adoption, lockfile/package churn, create-sync edits, in-memory cleanup, and unrelated op-ref behavior.
  • The remaining +973/-30 is cohesive: roughly half is implementation/docs and 448 lines are focused race/protocol tests.
  • Playground adoption remains the final UI-only PR in the stack.

Validation

  • Sync protocol TypeScript build and tests: 24/24
  • @treecrdt/sync TypeScript build and tests: 19/19
  • Outbound controller: 12/12 focused tests
  • Regressions cover timeout cancellation, topology replacement, drain barriers, attachment lifetime, offline retry, failed push recovery, observer failures, custom keys, and close cleanup.

@marcus-pousette marcus-pousette changed the title Add app-facing sync controller Add outbound sync API May 5, 2026
@marcus-pousette marcus-pousette force-pushed the sync/app-facing-controller branch from d7c5bb6 to edcaec2 Compare May 5, 2026 12:07
@marcus-pousette marcus-pousette changed the base branch from runtime-storage-api-cross-tab to main May 5, 2026 12:07
@marcus-pousette marcus-pousette marked this pull request as ready for review May 5, 2026 12:07
@marcus-pousette marcus-pousette marked this pull request as draft June 1, 2026 20:46
@marcus-pousette marcus-pousette marked this pull request as ready for review June 2, 2026 19:20
@marcus-pousette marcus-pousette added enhancement New feature or request area:sync Sync protocol, reconciliation, transport, discovery, and sync servers area:api Public interfaces, bindings, events, and cross-backend contracts labels Jul 12, 2026
@marcus-pousette marcus-pousette force-pushed the sync/app-facing-controller branch from 7821011 to b1b50a2 Compare July 12, 2026 15:23
@marcus-pousette marcus-pousette changed the title Add outbound sync API feat(sync): add a race-safe outbound controller Jul 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:api Public interfaces, bindings, events, and cross-backend contracts area:sync Sync protocol, reconciliation, transport, discovery, and sync servers enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant