i 0
random operations at agent: 0
Operation { loc: RangeRev { span: T 0..1, fwd: true }, kind: Ins, content: Some("a") }
random operations at agent: 2
Operation { loc: RangeRev { span: T 0..1, fwd: true }, kind: Ins, content: Some("a") }
syncing agents: 0 ↔ 2
diamond types (before): a
diamond types (before): a
diamond types (after): aa
otto (before): a
otto (before): a
otto (after): aa
i 1
random operations at agent: 1
Operation { loc: RangeRev { span: T 0..1, fwd: true }, kind: Ins, content: Some("a") }
random operations at agent: 0
Operation { loc: RangeRev { span: T 1..2, fwd: true }, kind: Del, content: Some("a") }
syncing agents: 1 ↔ 2
diamond types (before): a
diamond types (before): aa
diamond types (after): aaa
otto (before): a
otto (before): aa
otto (after): aaa
i 2
random operations at agent: 2
Operation { loc: RangeRev { span: T 0..2, fwd: true }, kind: Del, content: Some("aa") }
random operations at agent: 1
Operation { loc: RangeRev { span: T 2..3, fwd: true }, kind: Del, content: Some("a") }
syncing agents: 0 ↔ 2
diamond types (before): a
diamond types (before): a
diamond types (after):
otto (before): a
otto (before): a
otto (after): a
Diagrams showing otto's behaviour:
┌────0────┐ ┌────1────┐ ┌────2────┐
└────∅────┘ └────∅────┘ └────∅────┘
random operations at agent: 0
┌────0────┐ ┌────1────┐ ┌────2────┐
│ 0 ins a │ └────∅────┘ └────∅────┘
└────a────┘
random operations at agent: 2
┌────0────┐ ┌────1────┐ ┌────2────┐
│ 0 ins a │ └────∅────┘ │ 2 ins a │
└────a────┘ └────a────┘
syncing agents: 0 ↔ 2
┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐
| ▼
┌────0────┐ ┌────1────┐ ┌────2────┐
│ 0 ins a │ └────∅────┘ │ 2 ins a │
│ 2 ins a │ │ 0 ins a │
└────aa───┘ └────aa───┘
▲ |
└ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┘
random operations at agent: 1
┌────0────┐ ┌────1────┐ ┌────2────┐
│ 0 ins a │ │ 1 ins a │ │ 2 ins a │
│ 2 ins a │ └────a────┘ │ 0 ins a │
└────aa───┘ └────aa───┘
random operations at agent: 0
┌────0────┐ ┌────1────┐ ┌────2────┐
│ 0 ins a │ │ 1 ins a │ │ 2 ins a │
│ 2 ins a │ └────a────┘ │ 0 ins a │
│ 0 del a │ └────aa───┘
└────a────┘
syncing agents: 1 ↔ 2
┌ ─ ─ ─ ─ ─ ─ ─┐
| ▼
┌────0────┐ ┌────1────┐ ┌────2────┐
│ 0 ins a │ │ 1 ins a │ │ 2 ins a │
│ 2 ins a │ │ 2 ins a │ │ 0 ins a │
│ 0 del a │ │ 0 ins a │ │ 1 ins a │
└────a────┘ └───aaa───┘ └───aaa───┘
▲ |
└─ ─ ─ ─ ─ ─ ─ ┘
random operations at agent: 2
┌────0────┐ ┌────1────┐ ┌────2────┐
│ 0 ins a │ │ 1 ins a │ │ 2 ins a │
│ 2 ins a │ │ 2 ins a │ │ 0 ins a │
│ 0 del a │ │ 0 ins a │ │ 1 ins a │
└────a────┘ └───aaa───┘ │ 2 del aa│
└────a────┘
random operations at agent: 1
┌────0────┐ ┌────1────┐ ┌────2────┐
│ 0 ins a │ │ 1 ins a │ │ 2 ins a │
│ 2 ins a │ │ 2 ins a │ │ 0 ins a │
│ 0 del a │ │ 0 ins a │ │ 1 ins a │
└────a────┘ │ 1 del a │ │ 2 del aa│
└────aa───┘ └────a────┘
syncing agents: 0 ↔ 2
┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐
| ▼
┌────0────┐ ┌────1────┐ ┌────2────┐
│ 0 ins a │ │ 1 ins a │ │ 2 ins a │
│ 2 ins a │ │ 2 ins a │ │ 0 ins a │
│ 0 del a │ │ 0 ins a │ │ 1 ins a │
│ 1 ins a │ │ 1 del a │ │ 2 del aa│
│ 2 del aa│ └────aa───┘ │ 0 del a │
└────∅────┘ └────∅────┘
▲ |
└ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┘
We have run diamond types' fuzzing test, comparing otto and diamond types side-by-side.
Otto agents converge to a common state. Diamond types agents converge to a common state.
In some cases, however, this common state isn't the same for otto and diamond types.
Even on unordered document contents – i.e. excluding cases where the changes appear in reverse order.
It would be interesting to see if we can tweak otto's behaviour to match diamond types' exactly.
Test case:
https://github.com/tablyinc/otto-test/blob/a986dd31ba1bf0574b2893f4e1fc5f441e795614/tests/oplog_merge_fuzzer.rs#L196-L199
Raw dump:
Diagrams showing otto's behaviour: