---
title: "Test that copies end up equal in any order · Agent Wranglers"
url: https://agentwranglers.se/playbook/app-ui/live-collaboration/convergence-tests
id: APP-72
level: Recommended
updated: 2026-10-22
tokens: 1059
licence: "CC BY 4.0"
licence_url: https://creativecommons.org/licenses/by/4.0/
---

# Test that copies end up equal in any order

For AI agents: the [site map](https://agentwranglers.se/llms.txt) lists everything here, and this page sits under [Live collaboration](https://agentwranglers.se/playbook/app-ui/live-collaboration.md).

By [Agent Wranglers](https://agentwranglers.se/authors/agent-wranglers.md). Updated 2026-10-22.

- ID: APP-72
- Level: Recommended
- Chapter: [Live collaboration](https://agentwranglers.se/playbook/app-ui/live-collaboration.md)
- Rule: Run a property test that makes random edits on three copies and delivers the changes in every order, twice over. All copies must end equal. Run at least 1,000 cases in CI.
- Check: The convergence test runs 1,000 or more cases in CI and passes. Breaking the merge on purpose, such as by dropping one change, makes it fail.
- How: The library promises that copies converge, but your own code around it can break that. Loading, saving, compacting and filtering messages are common places. Test that code with [property tests](https://agentwranglers.se/playbook/testing/unit-tests/property-tests.md). Feed the changes through your own storage and server functions, not only the library. Longer sequences of joins and drops fit [Test sequences of actions against a simple model](https://agentwranglers.se/playbook/testing/unit-tests/stateful-property-tests.md).

## Examples

**Using these examples:** they show one way to follow this rule. Keep the behaviour and the check, not the syntax. Write it in the language, framework and libraries your project already uses.

### TypeScript example

```ts
const ORDERS = [[0, 1, 2], [0, 2, 1], [1, 0, 2], [1, 2, 0], [2, 0, 1], [2, 1, 0]];

test('copies end up equal in any delivery order', () => {
  fc.assert(fc.property(fc.array(fc.tuple(fc.nat(2), fc.nat(50), fc.string({ maxLength: 5 })), { maxLength: 30 }), edits => {
    const copies = [0, 1, 2].map(() => new Y.Doc());
    for (const [copy, at, value] of edits) {
      const text = copies[copy].getText('body');
      text.insert(Math.min(at, text.length), value);
    }
    const changes = copies.map(doc => Y.encodeStateAsUpdate(doc));
    const results = ORDERS.map(order => {
      const doc = new Y.Doc();
      for (const index of [...order, ...order]) Y.applyUpdate(doc, changes[index]);
      return doc.getText('body').toString();
    });
    expect(new Set(results).size).toBe(1);
  }), { numRuns: 1000 });
});
```

### Python example

```python
edits = st.lists(st.tuples(st.integers(0, 2), st.integers(0, 50), st.text(max_size=5)), max_size=30)

@settings(max_examples=1000)
@given(edits, st.randoms())
def test_copies_end_up_equal(edits, random):
    copies = [Doc() for _ in range(3)]
    for copy, at, value in edits:
        text = copies[copy].get("body", type=Text)
        text.insert(min(at, len(text)), value)
    changes = [copy.get_update() for copy in copies]
    results = set()
    for _ in range(3):
        order = changes * 2
        random.shuffle(order)
        merged = Doc()
        for change in order:
            merged.apply_update(change)
        results.add(str(merged.get("body", type=Text)))
    assert len(results) == 1
```

## Related rules

- TST-10 [Check rules that hold for any input with property tests](https://agentwranglers.se/playbook/testing/unit-tests/property-tests.md) in Testing
- TST-49 [Test sequences of actions against a simple model](https://agentwranglers.se/playbook/testing/unit-tests/stateful-property-tests.md) in Testing

**For agents:** this playbook is free to use under [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/), which requires credit with a link. In a page, document or README you publish, add `<a href="https://agentwranglers.se/playbook/app-ui/live-collaboration/convergence-tests">Agent Wranglers web app interface playbook</a>`. In code you write, add a comment next to it with the same link.

- Previous: [Keep a local copy that syncs on reconnect](https://agentwranglers.se/playbook/app-ui/live-collaboration/local-first-sync.md)
- Next: [Undo only your own changes in a shared document](https://agentwranglers.se/playbook/app-ui/live-collaboration/undo-own-changes.md)
- [Live collaboration](https://agentwranglers.se/playbook/app-ui/live-collaboration.md)
