Skip to content

feat(edges): sync demo + React binding seat (DAN-1044, DAN-1047) - #27

Draft
Danny-Devs wants to merge 2 commits into
mainfrom
et3rnald/dan-1044-e1-the-sync-story-touchable-honest-minimum-colada-db-demo
Draft

feat(edges): sync demo + React binding seat (DAN-1044, DAN-1047)#27
Danny-Devs wants to merge 2 commits into
mainfrom
et3rnald/dan-1044-e1-the-sync-story-touchable-honest-minimum-colada-db-demo

Conversation

@Danny-Devs

Copy link
Copy Markdown
Owner

What

Two private workspace packages under packages/* (ADR-008 §2 edge packages; neither is published):

  • packages/sync-demo — the E1 "sync story, touchable" demo. Two panes, each its own createEntityStore(), synced through one in-page server-authoritative hub that passes runSyncAdapterContract with every hook supplied. Labeled per-pane network: on/off with a visible queued count. Engine switcher: memory · idb · sqlite-OPFS.
  • packages/react — the seat for the React binding. useStoreVersion implemented; useEntity / useEntities are documented stubs with 7 red tests as the spec (DAN-1047 — the hook body is written by hand, on purpose).

Honest limits (stated on the page and in the READMEs)

No backend — ADR-023's reference server is still open. The demo reaches enableSync through a @core/* source alias because sync is deliberately off the public entry. The network toggle parks requests rather than failing them (no flushNow() on the coordinator yet). outboxEngine is not wired.

Gates

typecheck · build · lint green. check:publish-surface · check:api-report · check:pack-manifest unchanged — no ADR-022 line touched. pnpm -r test is red only in packages/react (7 intentional stubs), so the gate job will stay red until DAN-1047's hook lands. Draft until then.

🤖 Generated with Claude Code

https://claude.ai/code/session_01843ZqF1T2DFizb4Zbrmwsb

…044, DAN-1047)

Two private workspace packages under packages/*, per ADR-008 §2 (core knows
nothing about them) and §4 (React ships only after the boundary is frozen by
two real consumers — the demo is consumer #2 in the making).

packages/sync-demo — the sync story, touchable, at the honest minimum:
- Two panes, each its own createEntityStore() + engine + enableSync, both
  synced through ONE in-page, in-memory, server-authoritative hub that
  implements SyncAdapter directly (LWW by arrival, tombstones not omissions,
  confirmedMutations on every pull, poke-first live channel).
- hub.spec.ts runs runSyncAdapterContract with every hook supplied — zero
  skipped blocks — plus five hub-specific tests. 27/27.
- Labeled network: on/off per pane parks that pane's push/pull; the outbox
  count is shown and drains on reconnect. Parking (not throwing) is
  explained: the coordinator has no "retry now", so a fail-fast offline
  would drain at a random point in D9's backoff.
- Engine switcher per pane: memory / idb / sqlite-OPFS (bring-your-own
  worker, exactly as playground/). Labels say what each honestly does;
  the sqlite pane shows engine.persistent because sahpool is
  single-connection.
- Writes go through createOptimisticUpdates(store).transaction(), the layer
  that stamps origin "local-mutation" — the only origin the outbox accepts.
- Panes read via useStoreVersion + boundary.getEntities() in render, marked
  TEMP until useEntities lands. No memoized entity hook inlined here.
- Banner + README name what it does NOT do: no backend, no network, no
  durable outbox, no rebase; ADR-023 artifacts 2 and 3 still open. Static
  dist/ via vite build; deploy is a human decision (GitHub Pages likely).
- Observed headless in Chromium against the built bundle: add / offline
  queue / reconnect drain / rename / delete / idb switch / sqlite-OPFS
  (persistent: true on the first pane, false on the second) all behaved.

packages/react (@colada-db/react, private):
- useStoreVersion implemented — useSyncExternalStore over the boundary's
  global tier; the snapshot is a primitive so there is no identity problem.
- useEntity / useEntities are DOCUMENTED STUBS that throw. Their JSDoc
  states the contract (subscribeEntity / subscribeType; getEntity /
  getEntities; the referential-identity law that getEntities()'s
  fresh-array-per-call violates). README §Snapshot identity lays out the
  version-keyed memo vs structural sharing without choosing.
  Decision: Danny, DAN-1047.
- index.spec.tsx is real (not todo, not skipped): 3 green for
  useStoreVersion, 7 red against the stubs by design — the work order.
  `pnpm -r test` is therefore red on this branch until the hooks land.

Both packages reach enableSync, the sync types and the conformance kit via
a @core/* SOURCE alias because those are deliberately off the public entry
(ADR-022 lines 1-2). The root's publish surface, API report and pack
manifest are unchanged — all three check:* gates green.

Gates (worktree root): pnpm -r typecheck / build / lint green;
CI=true pnpm -r test: root 650 passed (2 skipped, pre-existing), mcp 29,
sync-demo 27, react 3 passed / 7 failed (by design);
check:publish-surface / check:api-report / check:pack-manifest green.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01843ZqF1T2DFizb4Zbrmwsb
@coderabbitai

coderabbitai Bot commented Sep 3, 2026

Copy link
Copy Markdown

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true

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.

…on the store version (DAN-1047)

useEntities keeps one { version, snapshot } per (boundary, type) in a
WeakMap; unchanged version → cached array, no store access. Moved version →
recompute and diff by id + data reference, reusing surviving EntityEntry
objects and returning the OLD array when every row held. useEntity passes
getEntity through — its reference is stable between changes, which test (2)
now verifies.

Suite: 10/10 green, typecheck + lint clean. README §Snapshot identity records
the decision; the 'red by design' framing is retired.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C4XCwFzDxpG7fuseukFQ6j
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.

1 participant