Repository navigation
feat(crdt): grove_crdt Dart client, and x-forge-sync on the extension's sync routes - #34
Merged
Merged
Conversation
…rogates as U+FFFD
…hash and RawJson docs
… runes, tighten jsonEquivalent
… on a shuffled tree
…document order limits
…and skip-and-report loads
…, seed clock, keep raw removes
… new tag, fix minors
…ingQueueFullError
…lock skew, validate HTTP dates
…ng, quiet sse idle recycle
…s, check presence sends
… phrases, document seed
…ge failing with 500
…g merge hooks twice
…announce on reconnect
…d runner orphans nothing
This was referenced Oct 7, 2026
fix(crdt): accept old offline edits, merge nothing on a hook rejection, stop pulls skipping rows
#35
Merged
Selects the conformance tests by suite path and fails when none ran, one failed, or one skipped for anything but the documented late-stamp limit.
The conformance server compiles grove/hook, so a hook change now runs the workflow. The assertion lists the files under test/conformance/ and fails when one of them ran no passing test.
MIN_CONFORMANCE_SUITES is the count of files under test/conformance/ today. Adding a suite needs no edit, and removing one means lowering the number on purpose.
juicycleff
marked this pull request as ready for review
October 8, 2026 13:30
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This adds
grove_crdt, a pure Dart port of the CRDT client, incrdt-dart/. It also marks the extension's sync routes withx-forge-sync, so forge's client generators can find them. Forge's Dart client (forge_client_grove) is built on top of it.Trying it
You'll need the Flutter 3.47 toolchain (Dart 3.13). From
crdt-dart/:The conformance and convergence tests under
test/conformance/build a real Go server from this repo'scrdtpackage and run Dart clients against it, so they need Go 1.26 as well. They build withGOWORK=offon purpose: the server is its own module incrdt-dart/tool/conformance_server, which keepsmodernc.org/sqliteandgorilla/websocketout of grove's rootgo.mod.What's in it
The package covers what crdt-js covers: the HLC, every CRDT type (register, counter, set, list, document, text), merge and apply, compaction, the store with its pending queue and undo, plugins, presence and rooms, HTTP, SSE and WebSocket transports, and a sync engine. Where crdt-js and the Go server disagree, the Go server wins.
crdt-dart/doc/go-parity.mdlists every place that matters, and why.Four checks hold it to Go:
crdtstructs (cmd/golden).json.Marshal, lone surrogates included.The sync engine adds the things an offline device needs and crdt-js doesn't have:
In total there are about 1,500 tests on the VM and on node.
On the Go side,
WithCRDTEntitymaps tables to entities, and every sync route (/sync/pull,/sync/push,/sync/stream,/sync/ws) now carriesforge.WithSyncwith its role. The SSE stream also sends a keep-alive comment every 15 seconds while it's idle. Without it, a quiet stream got dropped every 45 seconds, and each drop wiped the node's presence.Before this can merge
Nothing's blocking it now. The extension needed a forge release with
forge.WithSync, and v1.12.2 has it.extension/go.modandkv/extension/go.modboth require forge v1.12.2, and the extension builds without ago.work.Nothing in
crdt/changes. #35 has merged intomainsince this was opened, and this branch still merges cleanly on top of it.One thing the tests found in the server
A change pushed with an older HLC than a peer has already pulled past never reaches that peer, when the merge changes state (counters, sets, lists, text).
ReadChangesSincepages by the row's stored HLC (crdt/metadata.go:208), and a state-changing merge keeps the older one. A device that was offline for a while loses its counter increments on every other device. There's a skipped test intest/conformance/convergence_test.dartthat asserts the right behaviour. The fix belongs in the server: bump the row HLC to the server clock on a state-changing merge. It's left out here socrdt/stays untouched. #37 fixes it on the server. Once that merges, un-skip the test and drop theLATE_STAMP_SKIPexemption from the CRDT Dart workflow in the same commit.While we were in there, we noticed
streamKeepAliveincrdt/server.gois set but never read. The extension now sends its own keep-alive, so nothing here depends on it.