toMap method
Converts the CRDT state to a map for serialization.
Implementation
@override
Map<String, dynamic> toMap() {
// Canonical node order (counter, then replicaId): two CONVERGED replicas
// must serialize byte-identically. Iterating map-insertion order made
// each replica serialize its own nodes first, so order-sensitive deep
// equality in conflict detection re-flagged converged documents as
// conflicting on every sync cycle, ping-ponging resolution pushes.
final ordered = _nodes.values.toList()
..sort((a, b) {
final byCounter = a.counter.compareTo(b.counter);
if (byCounter != 0) return byCounter;
return a.replicaId.compareTo(b.replicaId);
});
// `replicaId` is deliberately NOT serialized: it is per-DEVICE identity,
// not document state. Serializing it (the old format) made converged
// replicas serialize differently AND handed deserializing devices the
// CREATOR's identity as a default — two devices then minted colliding
// node ids and silently destroyed each other's concurrent edits.
return {
'counter': _counter,
'nodes': [
for (final n in ordered)
{
'r': n.replicaId,
'c': n.counter,
'o': n.origin,
'v': n.value,
'd': n.deleted,
},
],
};
}