getCausalHistory
getCausalHistory(doc)
Every change in the document's full history, topologically sorted by its deps.
CRDTs guarantee your data converges, not that you can see why it converged to what it did. Today the only way to know a conflict happened is manually calling getConflicts() at the exact path you suspect -- nothing walks a whole document for you.
automerge-lens answers one question: which value won this conflict, who wrote it, and did the merge actually converge?
explainConflicts recursively walks the entire document -- not just one path you already suspect -- and for every key with a live conflict reports every candidate value, which actor wrote it, and which one Automerge currently presents.
import { explainConflicts, checkConvergence } from "automerge-lens";
const reports = explainConflicts(doc);
console.log(reports[0].winner, reports[0].candidates);
const result = checkConvergence(changes, { orderings: 50 });
if (!result.converged) throw new Error("non-deterministic change() callback");
getCausalHistory(doc)
Every change in the document's full history, topologically sorted by its deps.
explainConflicts(doc)
Walks the entire document and reports every candidate value and author for each live conflict.
checkConvergence(changes, options)
Applies changes in many random orders and asserts they all converge to identical heads. Seeded, reproducible.
Local-first/CRDT tooling matured fast (Automerge, Yjs, Loro, PowerSync, ElectricSQL, Zero) but debugging lagged behind on purpose. historyToMermaid/conflictsToMermaid render output as Mermaid diagrams, pasteable straight into GitHub markdown -- an actual picture instead of a wall of hashes.
replica A: title "Draft v1"
replica B: title "Draft v2"
explainConflicts() → winner: "Draft v2" (replica B)
lost: "Draft v1" (replica A)