CelinQ Insights · No. 41
Offline Enterprise Architecture Is a Consistency Problem, Not a File-Copy Problem
Copying a repository is easy. Knowing which copy is right, and how to fold two divergent copies back into one, is the actual work.
There is a workaround that almost every Enterprise Architect team has reached for at least once, usually under deadline pressure. Someone is going offline for a week — a client engagement with no network access, a long flight, a secure facility that will not permit a VPN connection — and they need to keep modelling. So a colleague zips up the repository file, or copies the underlying database, and hands it over. The offline architect works against their private copy for a week, makes real progress, and then comes back to the harder half of the problem: getting that week of work back into the shared repository without erasing what everyone else did while they were away. Usually this is handled by hand. Someone opens both versions side by side, compares packages, and tries to reconstruct which elements are genuinely new, which were changed, and which were touched by both sides in ways that need a judgement call. It is slow, it is stressful, and it is exactly the kind of task where a tired person at the end of a long week makes exactly the mistake they were trying to avoid.
The instinct behind the workaround is not wrong. Copying the file is, in fact, the only way to get a working repository onto a laptop that will not be reachable. What is wrong is the assumption that follows from it: that because copying the file was easy, reconciling two copies afterwards will also be manageable. It will not be, and the reason has nothing to do with EA specifically. It is a property of what a model actually is.
Why copying the file is not collaboration
An Enterprise Architect repository, whether it is stored as a Jet-based .eap, a SQLite-based .qea, or a server-hosted .qeax, looks from the outside like a single file, and it is tempting to treat it the way you would treat a spreadsheet or a Word document: copy it, edit the copy, copy it back. But underneath that single file sits a dense web of interconnected rows — elements, connectors, diagram objects, tagged values, package hierarchies — each one referring to others by internal identifier. A model is not a document with sequential content that two people can each add a paragraph to. It is a graph, and every edit to a graph potentially touches the shape of the whole thing, not just the corner you were looking at.
When you copy that file, you get two complete, independent graphs that happen to be identical at the moment of copying. From that instant onward, they are simply two different repositories that no longer know about each other. Neither copy has any record that the other exists, let alone what happens to it. If both people create a new element, both new elements get their own local identifier and neither one knows the other was created. If one person renames a package and the other reorganises its children, there is no shared record of either action having happened — there is just a before-state and two different after-states, with nothing connecting them except a human memory of "this used to be the same file."
This is the crux of it: file copying solves the availability problem — you have a repository you can work in without a network — and does nothing at all for the consistency problem, which is how to know, later, exactly what changed, in what order, relative to what starting point, so that two sets of changes can be combined without one side quietly overwriting or contradicting the other. Consistency is not a property of a single file. It is a property of the relationship between two histories, and a plain file copy carries no history at all — just a snapshot.
What a snapshot is missing
It helps to be specific about exactly what a bare copy lacks, because each missing piece corresponds to a real failure mode that architects have all seen, usually described afterwards as "the merge went wrong" without much more precision than that.
The first missing piece is stable identity that survives structural change. Inside a single repository, EA gives every element, connector, package and diagram object an internal identifier, and as long as you never leave that one repository, renames and moves are cheap and safe because the identifier never changes — only the label or the position does. The trouble starts the moment two copies diverge and are later compared. If the comparison is done by looking at names and package paths rather than the underlying stable identifier, a rename on one side looks indistinguishable from a delete-and-recreate, and a move looks indistinguishable from two entirely different objects that happen to share a name. A merge process that cannot see past the visible label will systematically misclassify exactly the operations — renaming, reorganising — that architects do constantly and that have nothing wrong with them at all.
The second missing piece is a revision base: a record of what the shared state actually was at the moment the two copies split apart. Without a base to compare against, any reconciliation process is reduced to a two-way diff — comparing the offline copy directly against whatever the shared repository has become — and a two-way diff cannot distinguish "I changed this" from "someone else changed this while I was away" from "we both happened to arrive at the same value independently." All three look identical: a difference between two states. A genuine three-way comparison needs the common ancestor, the version both sides started from, so that each side's changes can be isolated and reasoned about on their own terms rather than lumped together as one undifferentiated pile of differences.
The third missing piece is causal history — not just what the base state was, but the ordered sequence of individual changes that led away from it on each side. A snapshot tells you the destination. It tells you nothing about the route, and the route matters. Two changes that happened in a particular order might be a coherent, intentional sequence — create an element, then immediately give it a tagged value — that should be treated as one logical unit of work. Compared purely as end states, that sequence is indistinguishable from an element that always had the tagged value. Most of the time this distinction does not matter. Occasionally — when reconciling a partially-applied sequence, or explaining an audit trail — it matters a great deal, and a bare file copy has already thrown the information away by the time anyone goes looking for it.
A file copy answers the question "what does the model look like now." Collaboration requires answering a completely different question: "what changed, by whom, from what starting point, and does it still hold together when combined with everyone else's changes." A copy was never designed to answer that second question, and no amount of careful manual comparison fully recovers the information that was never captured in the first place.
Identity, kept stable on purpose
CelinQ's answer to the identity problem starts before any conflict occurs: every entity synchronised through a workspace carries a stable identifier that is independent of its name, its position in the package tree, and its diagram coordinates. Renaming an element does not create a new identity; it is recorded as a change to one field — Name — on an identity that persists. Moving a package to a different parent does not create a new identity either; it is recorded as a change to the tree-parent field on the same persistent entity. This sounds almost too obvious to be worth stating, and that is precisely the point: it is obvious once you say it, and it is exactly the property that a naive file-diff approach, working from visible labels and paths rather than internal identity, cannot reliably provide.
The practical payoff shows up whenever the two things architects do constantly — renaming and reorganising — happen to coincide with someone else's work on the same entity. If one architect renames an element while another, working offline against an older copy, adds a tagged value to that same element, a system without stable identity has no principled way to know these are the same entity at all once the label has changed. A system built on stable identity sees exactly what happened: one field changed on one side, a different field changed on the other, and because they are different fields on the same identity, there is no real conflict to resolve. This is the foundation the rest of the merge machinery is built on, and it is discussed in more depth in the piece on semantic synchronisation, which walks through what changes when you move from comparing rows to comparing entities.
A revision base for every entity
Stable identity tells you that two changes are about the same thing. It does not, on its own, tell you whether those two changes are compatible. For that, CelinQ keeps a genuine revision base: every entity carries a version number, and every proposed change declares the base version it was made against. When a change arrives at the server and its declared base matches the entity's current version — base equals head, in the internal shorthand — the change is sequential. Nothing else happened to that entity in the meantime, and the change is simply applied. When the declared base is older than the current version — base is behind head — genuine concurrency has occurred: something else happened to that entity after the change's author last saw it, and a proper three-way comparison is needed, using the stored base version as the common ancestor.
This causality is tracked using the server's own revision sequence rather than the wall-clock time on anyone's laptop, which matters more than it sounds like it should. Client clocks drift, they are set to different time zones, and — critically for anyone who has spent a week offline — a laptop's clock tells you nothing reliable about what order two changes actually happened in relative to a shared history that the laptop was disconnected from the whole time. A merge system that trusted timestamps to decide "who wins" would be vulnerable to exactly the architect who has been offline the longest simply overwriting everyone else on reconnection, purely because their laptop's clock reads a later moment. CelinQ never resolves anything on that basis. The only clock that matters is the sequence of revisions actually recorded on the server, and that sequence is what supplies the base for every three-way comparison.
The operation journal, and why replay has to be exact
Underneath the revision numbers sits the mechanism that makes offline work safe to bring home at all: a durable operation journal. While an architect is disconnected, every save they make locally is captured as a discrete, ordered change and queued, rather than being folded silently into some final "current state" that loses the sequence. When the connection returns, that queue is replayed against the server in order, change by change, each one declaring the base it was made against, exactly as if the architect had been online the entire time and each save had gone straight up to the server the moment it happened. The offline period does not produce a special, degraded kind of synchronisation. It produces exactly the same ChangeSets that online work produces, merely queued and delivered later.
This matters because it collapses two problems that would otherwise have to be solved separately into one problem solved once. There is no "offline merge algorithm" that is different from the "online merge algorithm." There is one deterministic reconciliation engine — Fusion, covered in depth in the article on conflict resolution — and offline replay is simply a delayed delivery of the same kind of ChangeSets it always processes. The consistency guarantees do not weaken the longer someone has been disconnected. A ChangeSet that has been sitting in a queue for six hours behaves identically, on arrival, to one sent thirty seconds after it was created.
Duplicate delivery and why idempotency is not optional
A queue that survives disconnection has to survive an uglier problem too: a network that comes back intermittently, drops mid-transmission, and forces retries. If an architect's laptop sends a ChangeSet, the connection drops before an acknowledgement arrives, and the client — reasonably — retries once the connection returns, the server may now receive the same ChangeSet twice. A naive system would apply it twice, and applying a rename twice is harmless, but applying "add one to the version counter" twice, or "create a new tagged value" twice, is not harmless at all. It corrupts the very state the reconciliation is supposed to protect.
Every ChangeSet CelinQ accepts carries an identifier, and the server tracks which identifiers it has already committed. A retransmitted ChangeSet with an identifier the server has already seen is recognised and discarded rather than reapplied — the client gets back the same acknowledgement it would have gotten the first time, and the model state is untouched by the repeat. This property, idempotency, is unglamorous and rarely gets a slide of its own in a product demo, but it is one of the load-bearing guarantees underneath the entire offline story. Without it, "just retry on reconnect," which is the obvious and necessary behaviour for any client on a flaky network, would be actively dangerous. With it, the client can retry as aggressively as it needs to and the worst outcome is a wasted network round trip, never a corrupted model.
Put the three pieces together and offline work stops being a special case that has to be handled gingerly. Stable identity means a rename or a move never gets mistaken for a different entity. A recorded revision base means every change can be classified as sequential or genuinely concurrent, never guessed at. Idempotent replay means a flaky reconnect can retry freely without risk of double-applying anything. None of the three, alone, solves offline consistency. Together, they are the whole of what solves it.
What convergence actually promises
The property teams actually care about, once all the mechanics are in place, is convergence: after every offline queue has been replayed and every concurrent change has been reconciled, do all the copies of the model — the one that stayed online, the one that was offline for an hour, the one that was offline for a week — end up agreeing? This is not a rhetorical question, and CelinQ does not answer it by assertion. The Fusion engine was exercised through a seeded, reproducible benchmark of 100,000 operations pushed by five concurrent simulated clients through the real storage and merge pipeline — not a simplified model of it — and the result was checked the only way that means anything: every client's resulting state was replayed from its own cursor and compared, entity by entity, against the canonical state on the server. All five converged. Zero operations were silently lost. Zero deleted elements came back to life. Roughly seven in ten of the operations that genuinely collided were resolved automatically under a deterministic rule the system can name; the rest were correctly recognised as needing a person and were surfaced rather than guessed at. The full methodology and numbers are worth reading in their own right, because a benchmark that cannot be reproduced or inspected is not much better than a marketing claim, and that reasoning is developed further in the piece on performance benchmarking done honestly.
Convergence is a promise about the destination, not about comfort along the way. It says that if you replay every change from every client's perspective, you arrive at the same place the canonical server did — not that the journey there was invisible or effortless. Genuine conflicts, where two people changed the same fact in incompatible ways, still exist and still need a human decision; convergence simply means that decision is the only place where anyone's judgement is required, rather than a silent guess made on someone's behalf.
What this changes for the offline architect
Go back to the scenario this piece opened with — a week away, no network, real modelling work to get done. The mechanics described here do not remove the offline period. Nobody has found a way to make a plane cabin, a client site with no external network access, or a genuinely air-gapped facility grow an internet connection out of thin air, and nothing here pretends otherwise. What changes is what happens on either side of that gap. Going offline is not a special mode that has to be switched into deliberately, and coming back online is not a manual reconciliation exercise that eats the rest of the day. The architect opens their local local repository and works exactly as they would with a live connection, because the connection was never part of the critical path for editing in the first place. Every save is captured with the identity, the base version and the ordering it needs. When the connection returns, the queue empties itself against the server, each change classified correctly as sequential or concurrent, each genuine collision surfaced rather than silently resolved either way.
The person who used to spend the first morning back comparing two zipped repositories by eye spends that morning, instead, reviewing a short and specific list of the handful of decisions that genuinely needed a human, if there are any at all. Everything else — the vast majority of a week's honest modelling work — has already folded itself in.
Where this still asks something of you
None of this is free, and it would be dishonest to present it as though the hard problem had simply disappeared. The reconciliation described here depends on every client actually going through the same pipeline: a repository that was never connected to a workspace in the first place, or one whose connection was set up after a great deal of independent offline editing had already accumulated without any recorded base, cannot retroactively be given a causal history it never captured. CelinQ's own migration path for repositories predating this machinery treats such changes conservatively — flagging them for a human to look at rather than guessing at a base that was never recorded — precisely because guessing would be worse than admitting the limit honestly. The lesson is straightforward: the earlier a repository is connected to a shared workspace, the more of its history is available to reason about later, and a copy made entirely outside that mechanism is, once again, just a copy.
It is also true that convergence at scale has been proven with five concurrent clients pushing through a shared server, not fifty, and that concurrent pushes are currently reconciled pairwise against the latest canonical head rather than as one simultaneous many-way comparison — the ordering still guarantees no loss and no resurrection, but a true N-way visual diff across many simultaneous authors is a harder visualisation problem than a correctness one, and it remains future work rather than a shipped capability. Teams considering this approach should ask any vendor, CelinQ included, to publish the methodology behind convergence claims rather than accept the headline figure alone — what was measured, how large the test was, and whether the result can be reproduced independently. A number without a method attached is a slogan wearing a decimal point, not evidence.
The honest summary is this: copying a file was always going to be the easy ninety percent of working offline, because copying is a solved problem and has been for decades. The consistency problem — knowing what changed, from what shared starting point, in what order, and how to fold two divergent histories back into one without a human quietly getting overruled by machinery they cannot see — was always the actual hard part, and it does not get easier by ignoring it or by hoping a careful manual comparison will catch everything. It gets easier by building the identity, the causal base and the replay discipline in from the start, so that offline is not an exception the system tolerates but a delay the system was designed to absorb.