CelinQ Insights · No. 02

When two architects touch the same model: merging without losing work

Last-write-wins is data loss with good manners. This is what real merging looks like.

A NILUS perspective on collaborative modelling for Sparx Enterprise Architect

Two architects spend a morning working on the same area of a model. One of them refines a set of business capabilities, adjusting names, tightening definitions, adding a couple of relationships that had been missing. The other, in parallel, works through the application layer that realises those capabilities, correcting some assignments and adding documentation to a handful of components. Neither is aware in any detail of what the other is doing, which is normal and healthy; that is what dividing the work means. At lunchtime they both save. And here is the question that decides whether collaborative modelling is trustworthy or merely convenient: what happens to the two mornings of work when they meet?

In too many setups, the answer is that one of them quietly wins and the other quietly disappears. Not with an error, not with a warning, not with anything you could later point to and say "that is where it went wrong." The system simply takes the more recent save, or the save that happened to land last, and treats it as the truth. The earlier work is gone, and the person who did it may not discover the loss for days, until they go looking for a relationship they know they drew and find an empty space where it used to be. By then the trail is cold. They cannot even be sure they are not misremembering.

The polite face of data loss

The industry has a reassuringly neutral name for this behaviour. It is called "last-write-wins," and the name is doing a lot of quiet work to make an unacceptable outcome sound like a reasonable policy. Strip the phrasing away and what it describes is a rule that resolves every disagreement by discarding one side of it without looking. It is not a merge. It is a coin toss where the coin is weighted toward whoever saved most recently, and the prize is that your colleague's morning survives and yours does not.

What makes last-write-wins particularly corrosive is that it usually works. Most of the time, two people are not editing the exact same thing, and so the last write happens to contain everything anyone did, and no harm is visible. This is the trap. The behaviour is fine right up until the moment it silently destroys something, and because it fails silently, the team develops a false confidence in it. They come to believe that saving over each other is safe, because they have done it a hundred times without noticing a problem. The hundred-and-first time, when the two mornings genuinely overlapped, the loss is invisible against a background of a hundred saves that were fine. Nobody is watching for it, because nothing has ever taught them to.

A system that loses work loudly is annoying. A system that loses work silently is dangerous, because it trains the people using it to trust it right up until the day it costs them something they cannot get back.

The response many teams reach for is to avoid the situation entirely, which brings us back to locking and taking turns, and to the queue that creates. So the field seems to offer a grim choice. Either you serialise everyone so that overlaps cannot happen, and you pay for it in waiting, or you let people work in parallel and accept that sometimes work will vanish. Presented that way, it is not much of a choice. But the choice is false, and it is false because it treats the model as a file to be overwritten rather than as a structured thing made of individual facts.

Why files are the wrong unit

The reason merging feels dangerous is that we tend to imagine it happening at the wrong level of granularity. If you picture two whole versions of a model arriving at the server, the only questions you can ask are crude ones: which version is newer, which is bigger, which do we keep. At that resolution there is no way to combine them, because the unit you are combining is far too large. Everything one person did is bound together into a single lump, and everything the other person did into another lump, and the two lumps cannot be interleaved because you never broke them down into their parts.

But a model is not really one thing. It is thousands of small facts. This element exists and has this name. This relationship connects that element to this other one. This diagram shows these elements at these positions. This tagged value holds this string. This element has this documentation. When an architect spends a morning working, they are not producing "a version." They are producing a set of changes to individual facts: renaming this, connecting that, documenting the other. And once you see the morning's work as a set of fact-level changes rather than as a monolithic version, the whole problem transforms. The question is no longer "which version wins," which has no good answer, but "what did each person change, fact by fact, and do any of those individual changes actually conflict." That question has a good answer almost all of the time.

Two people renaming different elements do not conflict, whatever else they were doing. One person adding a relationship while another edits an unrelated component's documentation do not conflict. In fact, the overwhelming majority of parallel work in a model touches disjoint sets of facts, even when it happens in the same package, even when it feels like people are working "in the same area." The area is shared but the facts are not. When you merge at the level of facts, all of that parallel work simply combines, because there was never any genuine disagreement to resolve. Both people's changes are real, both are kept, and no coin is tossed.

The idea of a three-way merge

Combining two sets of changes correctly requires one more ingredient, and it is the ingredient that separates a real merge from a hopeful guess. You cannot merge two states well by looking only at the two of them, because you have no way of knowing what changed. If I show you two versions of an element's name, "Payment Handler" and "Payment Service," you cannot tell which one is the change and which is the original, or whether both were changed from some third thing. You are reduced to guessing, and guessing is how work gets lost.

The way out is to remember where both people started. A three-way merge looks at three states rather than two: your version, your colleague's version, and the common ancestor both of you began from before either of you made a change. With the ancestor in hand, the reasoning becomes precise instead of speculative. For each individual fact, the engine can see whether you changed it relative to the ancestor, whether your colleague changed it, or whether neither of you did. If only one of you touched a given fact, that person's change is the intended one and it is applied. If neither of you touched it, it stays as it was. The only case that requires any further thought is the case where both of you changed the same fact to different values, and that case, the genuine conflict, is both rare and important.

The common ancestor is what turns merging from guesswork into arithmetic. Without it you are comparing two states and hoping. With it you can say, fact by fact, exactly who changed what and whether they actually disagreed.

This is the principle behind CelinQ Fusion, the merge engine at the centre of the platform. It is deterministic and reproducible, which are not decorative adjectives. Deterministic means that the same three inputs always produce the same result; the merge does not depend on timing, on which save happened to arrive first, on the order the network delivered things in, or on any other accident of the moment. Reproducible means you can run it again and get the same answer, and that anyone auditing what happened can reconstruct exactly why the model ended up as it did. These two properties are what make the merge something you can trust rather than something you have to hope about, and they are the direct opposite of last-write-wins, whose entire logic is an accident of timing.

Why determinism is not a technicality

It is tempting to treat determinism as an implementation detail, a property that matters to the people who build the engine but not to the architects who use it. That would be a mistake, because determinism is precisely the property that makes the difference between a merge you can defend and a merge you can only hope about. Imagine having to explain to a colleague, or to a client, why the model ended up in a particular state after two people's work combined. If the answer depends on which save happened to arrive first, on the vagaries of network timing, on the order the system happened to process things in, then there is no explanation to give; there is only an account of an accident. If the answer is that the same three inputs always produce the same result by a fixed and inspectable rule, then there is a real explanation, and the model's state is something you can stand behind rather than something you merely inherited from chance.

This is also what makes the behaviour testable and therefore trustworthy over time. A non-deterministic merge cannot really be verified, because you can never be sure the case you tested is the case you will get, given that the same inputs might produce different outputs depending on timing. A deterministic merge can be checked, exercised against difficult scenarios, and relied upon to behave the same way in production as it did under examination. When the correctness of your model's history depends on a piece of machinery, you want that machinery to be the kind you can pin down and confirm, not the kind that behaves differently depending on the weather. Determinism is what moves the merge from the category of things you tolerate to the category of things you rely on.

Deletions, which are their own kind of trap

Additions and edits are the easy part of merging. Deletions are where naive systems quietly go wrong, and it is worth understanding why, because the failure is subtle. Suppose you delete an element because it is obsolete, while your colleague, working from the same starting point, edits that same element's documentation because they did not know it was on its way out. What should happen? If the engine merely compares end states, it faces two versions of the model, one where the element is gone and one where it has new documentation, and it has no principled way to reconcile them. A common shortcut is to treat "absent" as just another value, which tends to mean the deletion gets lost and the element quietly returns, resurrected by the merge, which is its own form of silent corruption.

Fusion handles this by recording deletions explicitly rather than treating them as the mere absence of a fact. A deletion leaves a marker, a tombstone, that says this fact was deliberately removed, as opposed to simply not being present. With that marker in place, the three-way reasoning works cleanly even for removals. The engine can see that you deleted the element and that your colleague edited it, recognise that this is a genuine conflict between a deletion and an edit, and surface it for a person to decide, rather than silently resurrecting the element or silently discarding the documentation. The distinction between "removed on purpose" and "never here" is small to state and enormous in its consequences, and getting it right is a large part of what makes a merge trustworthy over the long life of a model.

The conflicts that are real

All of this careful machinery exists to shrink the set of things a human has to look at down to the genuine conflicts, and then to treat those genuine conflicts with the seriousness they deserve. When two architects really have changed the same fact to two incompatible values, that is not a problem for software to resolve, because the software has no way of knowing which of two legitimate human intentions is the right one. If you named an element "Payment Service" and your colleague named the same element "Payment Handler," neither of you is wrong in a way an algorithm could detect. There is a real decision to be made, and it belongs to a person.

The mistake that last-write-wins makes is not that it fails to resolve these conflicts automatically. No system can resolve them correctly without understanding intent. The mistake is that it pretends there is no conflict at all, resolves it by timing, and tells no one. The right behaviour is the opposite: to notice the genuine conflict, to isolate it so it does not contaminate everything around it, and to preserve both sides so that a person can see exactly what each contributor intended and make a real decision with full information. In CelinQ that decision happens with both versions in front of you and with the surrounding, non-conflicting work already safely merged, so that the human judgement is applied only where human judgement is actually needed and nowhere else. Conflicts become small, contained, and honest, rather than large, hidden, and lossy.

This is also why the platform keeps a complete, ordered history for each workspace. The merge being deterministic tells you the result is principled; the history tells you what actually happened over time and lets you go back and look. If a question ever arises about how the model came to be in a particular state, the answer is recorded rather than reconstructed from memory. That record is part of what replaces the false comfort of a lock with the real comfort of being able to see, after the fact, exactly what everyone did and how it combined.

The diagram problem, briefly

One place where fact-level thinking earns its keep in a way that surprises people is in diagrams. A diagram is not the model; it is a view onto the model, a particular arrangement of particular elements at particular positions. Two architects can open the same diagram and do quite different things to it: one repositions elements to make the layout clearer, the other adds an element that was missing and draws a couple of relationships. If you think of the diagram as a single object to be overwritten, these two pieces of work are in direct competition, and one of them loses. If you think of the diagram as a collection of facts, the position of this element, the presence of that one, the relationship between these two, then the repositioning and the addition are changes to different facts, and both survive. The layout improvement and the content addition combine, because there was never any genuine conflict between moving something and adding something else.

This is the general shape of why fact-level merging feels almost uncannily good in practice. So much of what looks like a collision at the level of whole objects turns out, at the level of individual facts, to be no collision at all. The apparent overlap is an artefact of the coarse unit, not a real disagreement. Refine the unit down to the fact and most of the collisions simply dissolve, leaving only the genuine ones, which are exactly the ones worth a person's attention.

What it does not do, and should not

It would be dishonest to suggest that fact-level three-way merging makes conflict disappear. It does not, and a system that claimed to would be a system that was quietly resolving genuine disagreements by guessing, which is the very thing we are trying to escape. What it does is separate the two things that last-write-wins collapses together. The vast bulk of parallel work does not conflict at all, and that work should merge cleanly and automatically with no ceremony, because there is genuinely nothing to decide. The small residue of real conflicts should be preserved, isolated, and handed to a person, because there is genuinely something to decide and only a person can decide it. The engine's job is to sort the first case from the second correctly and never to confuse them.

There is a modelling discipline that helps this work well, and it is worth being honest about it. Merging is cleaner when a team divides work along sensible lines and communicates about the genuinely shared parts, just as it always has been. The engine removes the accidental conflicts, the ones caused by two people happening to save near the same moment, or by a lock reaching further than the work it was protecting. It cannot remove the substantive ones caused by two people genuinely disagreeing about what an element should be, nor should it try, because those disagreements are real architectural questions that deserve to be resolved by architects. The tool makes the mechanical part reliable so that the human part can get the attention it deserves.

And, as with everything CelinQ does, it works alongside Enterprise Architect rather than replacing it. Each architect keeps modelling in the tool they know, in their own local repository, at full speed. The merge happens underneath, when the background service brings each person's saved work into the shared workspace. The architect experiences it as their work simply arriving intact and their colleague's work being there too, with the rare genuine conflict raised clearly for a decision rather than buried.

The standard worth holding

The phrase last-write-wins should be heard for what it is: a confession that the system does not merge, told in language designed to make that sound acceptable. A shared modelling environment that can lose an afternoon's work without saying so has not solved collaboration; it has postponed the moment you find out it did not. The standard worth holding is simple to state and demanding to build. Parallel work that does not truly conflict should always combine, with nothing lost and nothing to negotiate. Deletions should be honoured as deliberate acts rather than treated as accidental gaps. Genuine conflicts should be preserved and surfaced for a person, never silently resolved by the accident of who saved last. And the whole process should be deterministic, reproducible, and recorded, so that it is something a skeptical architect can inspect and come to trust rather than something they are asked to take on faith.

That is what real merging looks like, and it is the difference between a collaborative model you can rely on and one that is merely convenient until the day it quietly costs you a morning you cannot get back.