Is there a rule which can be easily understood by the user of a Y.Map, which entry will overwrite the other in the case of a merge conflict between two Y.Maps?
In my experiments, it is somewhat random which side wins (although both Y.Maps will be equal afterwards - and that’s definitely the more important part)
As you noticed, the eventual consistency is the important part.
I’m not sure what the internal rule is, but it might be something like whomever has the lower clientID or clock. It should be considered an implementation detail and not relied upon for business logic, since clients can manipulate these values.
I cannot be the clock which decides who wins as I waited for 100ms between filling my two Y.Maps - and that’s why I also developed my LWWMap which follows a “last-write-wins” strategy.
I am trying to do the exact same thing (write unit tests on a YMap with conflicts) and trying to predict the result. It does feel a little random, but I believe ClientID is used somehow…I am just not sure. Maybe @dmonad can point us to some code or give us a little more detail?
// create a task and add it to one document (first edit)
const { yTask, key } = createYTask();
const yTasks = Converter.getYTasks(yDocClient);
yTasks.set(key, yTask);
const task = yTask.toJSON() as TaskData;
// Gotta be careful here and clone your memory. YJS will just pass an object through. This changes the original task and slightly modifies it
task.meta = {
...task.meta,
creator: 9090089,
};
// Add the slightly modified task to a second document (first edit)
const yTasks2 = Converter.getYTasks(yDocClient2);
const { yTask: yTask2 } = createYTask(task);
yTasks2.set(key, yTask2);
// Looks like higher client ID wins.
const expectedTask = yDocClient.clientID > yDocClient2.clientID
? yTask
: yTask2;
// This function validates the expected final state
await validateApplyUpdatesForSave({
upserts: {
[key]: expectedTask.toJSON() as TaskData,
},
deletes: [],
});