BoltArchiveFormat
How one op-log CRDT's operations are classified and encoded into an archive.
Every Bolt takes one of these. It binds three things a bolt cannot know for itself: which ops are content and which are records of forgetting (classifyOp), which causal dot an id belongs to (dotOf), and how an op turns into bytes (encode / decode).
Why it holds a CRDT instance
OpLogCrdt.classify and dotOf are instance methods, so classification needs a live CRDT in hand. classifier is that hand — a witness, used only for its three contract methods and never read for content. The companion factories construct an empty one, so there is no state to leak even in principle. (If a future replay-side validator wants free-standing classification, OpLogCrdt can grow it source-compatibly; this parameter is why that is worth doing.)
Why the serializer is not a parameter
You pass the element serializer; the op serializer comes from OpLogCrdt.opSerializer(vSerializer) and cannot be overridden. That is deliberate. The compiler-generated sealed serializer for RgaOp/FugueOp writes a different wire format — class-discriminator polymorphism instead of the canonical leading t tag — and defaults its element type to PolymorphicSerializer(Any::class), which CBOR cannot encode at all. Bytes written that way sit outside the golden vectors that pin this format across versions, and an archive exists precisely to be read by a later build. FugueOpSerializer is internal besides, so opSerializer is the only way to canonically encode a FugueOp.
Type Parameters
the element-identity type (RgaId / FugueId).
the element type carried by inserts.
the operation type (RgaOp<V> / FugueOp<V>).
Samples
val server = ReplicaId("server-uuid-abc123")
// You pass the ELEMENT serializer. The op serializer comes from the CRDT's own
// `opSerializer` and cannot be overridden — the compiler-generated one for `RgaOp`
// writes a different wire format, and an archive exists to be read by a later build.
val format = BoltArchiveFormat.rga(String.serializer())
val bolt = InMemoryBolt(format, Clock.System)
// Feed it the OPERATIONS a replica applied, never a state fragment. A `Compact` among
// them is dropped and the ops it suppresses are kept — which is what lets this archive
// outlive the replica that fed it.
var live = Rga.empty<String>()
val ops = List(3) { index ->
val (next, op) = live.insertAt(server, live.size, "record-$index")
live = next
op
}
bolt.append(ops)