compacted method
Returns a copy with every tombstone purged.
Deleted elements normally stay as tombstones so concurrent inserts anchored to them keep their position; over the life of a document they accumulate without bound. Compaction rebuilds the sequence as a linear chain of only the visible elements — element ids are preserved, so cursor anchors (elementIdAt/indexOfId) stay valid, order is exactly the current visible order, and the Lamport counter continues from where it was (new local inserts cannot collide). The rewrite is a pure function of the synced state, so replicas compacting the same state produce identical results.
⚠️ Coordination contract: compact only at a synchronization barrier (all replicas have merged this state — e.g. when persisting a checkpoint or when a single writer holds the document). Merging a compacted list with a stale replica that never observed a deletion resurrects that element (its tombstone is gone), and elements whose anchors were rewritten reconcile through merge's deterministic same-id resolution — convergent on every replica, but the visible order around the stale edits may shift once.
Implementation
RgaList<T> compacted() {
final nodes = <String, RgaNode<T>>{};
String? origin;
for (final node in _visible()) {
nodes[node.id] = RgaNode<T>(
replicaId: node.replicaId,
counter: node.counter,
origin: origin,
value: node.value,
);
origin = node.id;
}
return RgaList._(replicaId, nodes, _counter);
}