JsonNode
A node in a JsonCrdt document.
The three variants compose existing CRDTs directly:
Object — an observed-remove map keyed by String, values are JsonNodes. Concurrent adds win over removes (add-wins, ORMap semantics).
Array — an RGA sequence of JsonNodes. Position-stable: concurrent inserts are ordered by the RGA tiebreak.
Leaf — a multi-value register holding one or more JsonValues. Concurrent writes from different replicas are all retained until a later write observes and supersedes them.
Merge semantics for cross-type conflicts. When the same key in a parent Object holds an Object on one side and an Array or Leaf on the other (a concurrent type-change), the richer type wins deterministically: Object > Array > Leaf. This rule is a total order, so piece is commutative and associative on the type dimension — convergence holds. However the losing node's entire subtree is silently and permanently discarded: unlike scalar conflicts (where MVRegister surfaces both values), a cross-type conflict has no observable indication that data was lost. This is a v1 simplification; a future version may surface these conflicts as multi-valued entries.
Serialization. Use JsonNode.serializer to obtain a KSerializer that handles the recursive structure correctly. The compiler-generated serializer falls back to PolymorphicSerializer(Any::class) for the element types of the inner Rga and ORMap, which fails on CBOR transport.
Wire format: { "t": Int, "o": ORMap?, "a": Rga?, "l": MVRegister? } where t is 0 for Object, 1 for Array, 2 for Leaf, and only the field matching the variant is present.