Skip to content
Client login

Free Audit

Artificial intelligence

Two systems that never quite agree

An integration that runs is not an integration that is correct. What to put in place the day the two sides start to diverge.

Published on 24 July 2026 — Algeria Agency

An integration is declared finished the day data passes from one system to the other. That is a real milestone and it is not the end: two connected systems begin to diverge, slowly, and nobody notices until somebody compares two screens.

Divergence is not a bug in the usual sense. Nothing breaks, no error is logged, both pieces of software display figures consistent with their own contents. They simply no longer tell the same story, and the day the difference is found, nobody knows how long it has been going on.

This article is about the life of a running integration: who is right when two systems contradict each other, how often to reconcile, what to do with a duplicate, how to replay without duplicating, what happens when a field is renamed, and how far back into the past you can go. The companion article covers feasibility — the inventory before the quotation, what comes out of a piece of software, the till that exposes nothing — and none of that is repeated here.

It carries no chart, and the reason is more interesting than usual: what it is about has never been counted by anybody, because neither of the two systems records it as an error.

An integration that runs is not an integration that is correct

The acceptance test for an integration is almost always the same: create a record on one side, check it appears on the other, sign. That test proves the pipe exists. It proves nothing about what will flow through it for the next three years.

The difference is that the acceptance test uses a clean case, created deliberately, in daylight, by somebody who knows what they are doing. Production brings the cases nobody wrote: the order cancelled then recreated, the customer whose name contains an apostrophe, the change made while the synchronisation was running.

Two questions therefore have to be separated that are asked as one. “Does it work” is checked once and answered yes. “Is it correct” is not checked once: it is a property that is either maintained or lost, and it is lost silently.

The practical consequence is that an integration needs continuous monitoring rather than an acceptance test. The monitoring is modest — a count on both sides, at a regular interval, with an acceptable gap declared in advance — and its absence is the most common cause of unpleasant discoveries at stocktaking or year end.

Who is right on Tuesday morning

When two systems show two different values for the same thing, the question asked is “which one is right”. That is the wrong question, and it has no answer at the level of the system. It has one at the level of the field.

The formulation that works is dull to write and settles almost every dispute in advance: for each field that moves, only one of the two systems is the source, and the other receives a copy it has no right to change. Stock is sourced from the till; the address is sourced from the customer file; the price is sourced from the catalogue.

That document fits on one page and is almost always missing. Its absence is invisible at first because both sides agree, and becomes brutally visible the day somebody corrects an address in the system that is not the source: the correction is overwritten at the next synchronisation, the person does it again, and the business concludes that “the tool wipes changes”.

You have to accept that the answer is sometimes uncomfortable. Declaring the till the source of stock means a correction made in the management software will not hold, and therefore that it has to be made in the till. That is a change of habit, it costs a conversation, and it is cheaper than the divergence it prevents.

The gap that appears after three weeks

Divergence always starts small and with a special case. An order cancelled while the synchronisation was running. A record changed twice in the same minute. A forty-second network outage in the middle of a transfer. Each of those produces a one-line gap, and one line is not noticed.

What makes the phenomenon dangerous is that it accumulates without announcing itself. After three weeks the gap is a few dozen lines, after a year it is structural, and it is discovered by a physical stocktake or by a customer insisting they paid for something the system has never heard of.

At that point the question asked is “since when”, and it is the most expensive question to answer after the fact. With no regular count kept, there is no way to date the start of the drift, and the only option is to redo the entire period.

We cannot say how often this happens, and the explanation is worth giving rather than working around. There is no published statistic on divergence rates between systems, not because it is confidential, but because nobody has ever been able to measure it: as far as the two pieces of software are concerned, the operation succeeded. The send succeeded, the write succeeded. The event is recorded nowhere as a failure, so there is no population of errors to sample. That is the only figure on this page, and nobody has ever counted it.

Reconciliation, and how often

The control that answers the previous section is a reconciliation: count the same thing on both sides and compare the two numbers. It is far simpler than its accounting name suggests, and it does not need to be fine-grained to be useful.

Counting is enough in the great majority of cases. How many records on each side over the period, and what total for the field that matters — an amount, a quantity. Two numbers per side, taken at the same moment, written somewhere they are kept. Line-by-line comparison is a different exercise, more expensive, and it is only triggered once the count has said there is a problem.

The frequency follows from the cost of putting things right, not from a general good practice. If tracing the origin of a one-day gap costs an hour and a one-month gap costs a week, then reconciliation is daily. For low volume and modest stakes, once a week is amply sufficient.

The point that decides whether any of this is useful is keeping it. A reconciliation done and thrown away does not answer “since when”; one done and kept turns that question into a three-minute read. Four numbers a day in a file is the entire mechanism, and it is what separates an incident from a complete redo.

The duplicate, and why it is created twice

The duplicate is the most visible symptom of an integration and the one handled worst. Two records for the same customer, two identical orders, two products with the same name: the reflex is to delete one of them, which fixes the display and fixes nothing.

The cause is almost always the absence of a shared identifier. System A creates a customer and sends it; system B records it with its own number. Nothing keeps the link between the two numbers, so at the next send B does not recognise the customer and creates it again. The duplicate is not a typing error, it is the mechanical consequence of a missing link.

The repair is to store the correspondence: for every record transmitted, the originating identifier and the receiving identifier, kept somewhere. It is a two-column table, it is dull, and it is what makes an integration repairable — without it you cannot replay a send without risking recreating everything.

Cleaning up existing duplicates comes afterwards and never before. Merging records in a system whose integration is still producing duplicates is bailing out water: the work is redone the following week, which durably discourages the team that did it and creates the impression that the problem is insoluble.

When the other system does not answer

The system at the other end will be unavailable, and not rarely: maintenance, network outage, quota reached, a server saturated on a busy day. The question is not how to avoid it but what your side does meanwhile.

There are three possible behaviours and only one is acceptable. Losing the send, which produces the divergence of section 2 and is invisible. Blocking and waiting, which turns an outage at their end into an outage at yours. Or setting aside and retrying, which is the only response that preserves both service and accuracy.

The holding queue must have a limit and a voice. A queue that grows indefinitely is a deferred loss: at some point somebody empties it to unblock the situation, and nobody will ever know what was in it. A queue that speaks up when it passes a threshold turns an outage into information.

Retries also have to space themselves out. Retrying every second against a system already in difficulty adds load to an outage, and some suppliers treat that insistence as abuse and cut access. Spacing retries is a technical courtesy that mostly protects whoever applies it.

Replaying without duplicating

Once the queue exists it has to be replayed, and that is the moment most integrations create the disorder they were meant to prevent. Replaying three hundred waiting sends without precaution produces three hundred new records alongside the ones that had already gone through.

The missing property has a technical name and a simple idea: the same send performed twice must produce the same result as once. In practice, every send carries a stable reference — not a timestamp, not a random number — and the receiving system refuses a send whose reference it has already seen.

This precaution costs almost nothing at build time and is not easily retrofitted. Without it, every recovery after an incident becomes a manual, anxious operation, done by somebody ticking rows in a spreadsheet to work out which ones have already gone, which is exactly the work the integration was supposed to remove.

The test that verifies this property is the simplest in the whole project and is almost never run: send exactly the same thing twice, and see whether there are one or two records at the far end. It takes a minute on delivery day and answers the question that will cost the most later.

The field somebody renamed

Integrations rarely break for technical reasons. They break because somebody, in one of the two systems, made a perfectly legitimate change without knowing something was listening: a field renamed, a list of values given an extra option, a form reorganised.

That person did nothing wrong. They adapted their tool to their work, which is the expected use, and nothing in their interface warned them that an integration depended on the name of that field. The information did not exist where the decision was taken.

The protection is therefore not technical but organisational, and it fits in one sentence: the list of fields the integration relies on is written down, and it is known to whoever administers each system. Two pages, one per tool, posted where the changes get made.

The technical complement is to make breakage noisy. An integration meeting an unknown value must stop and complain, not guess or skip the row. An integration that silently ignores what it does not understand is an integration that produces the divergence of section 2, larger and faster.

The history you will not recover

When an integration is put in, the request that follows immediately is to recover the past: bring across the last two years of orders, fill the new system with the old one’s history. It is legitimate and it has a limit best stated straight away.

What can be brought across is what was recorded. What was never entered exists nowhere and no migration will make it appear: if the old system did not note the acquisition channel, the new one will not have it for past years, however good the migration work.

It is a distinction requests rarely make and it changes the estimate completely. “Bring across the history” may mean copying fields that exist, which is mechanical and feasible work, or reconstituting information that was never collected, which is invention and has to be refused.

Good practice is to separate the two in the quotation, in plain words: here are the fields brought across, here are the fields that will stay empty for the earlier period. The client then decides knowingly, and nobody discovers six months later that the column meant to drive everything is empty on three quarters of the rows.

Two systems, two truths about one customer

The most stubborn case is not the technical duplicate but the human one: the same person exists on both sides with different information, and nothing allows an automatic decision. A number written with a dialling code on one side and without on the other, a name spelled two ways, a business and its owner recorded separately.

The temptation is to match automatically on name similarity, and that is the decision that produces the hardest errors to undo. Merging two customers who were not one mixes two purchase histories, two delivery addresses and sometimes two balances, and the way back is rarely clean.

The reasonable rule is to match automatically only on an exact match of a reliable identifier, and to put the rest in a list somebody looks at. A normalised phone number works well in this market; a name alone is never enough, particularly with transcriptions that vary.

You have to accept that this list never empties completely, and that is not a failure. A few dozen ambiguous cases somebody settles in ten minutes a month beats a confident automatic match that gets it wrong twice a year on the most important customers, because they are the ones with the most records.

Taking over an integration running for three years

The common case is inheriting a running integration, undocumented, whose author has left and which nobody dares touch. It works, which is both reassuring and misleading: nothing says it is correct, only that it has not stopped.

The first measure to take is not to read the code, it is to do the reconciliation described above, once. Count on both sides over the last three months. That single figure says within half a day whether you are inheriting a sound integration or an installed divergence, and it directs everything else.

Then comes the inventory of fields, obtained by watching rather than reading: which fields actually move, in which direction, and which are written on both sides — those last being the exact locations of future conflicts. A fortnight of observation gives a truer picture than the code, which describes what was intended.

The rule of caution is to rewrite nothing before having a reconciliation running. Without it, a change and a pre-existing divergence are indistinguishable, and every correction will be accused of having broken something that was already broken. The control comes before the repair, including when the repair looks obvious.

What we do, and what we refuse

What we take on is bounded: writing the source of truth field by field with the people who use both systems, building the integration with its correspondence table and its stable reference, and installing the reconciliation that gets kept — the least spectacular part and the one that makes everything else repairable.

We do not build an integration without the source of truth being written for every field that moves, even when the client finds the question theoretical. It is not: without that page, the first conflict is settled by the execution order of the programs, which is leaving a management decision to an accident of scheduling.

We do not reconstitute a history that was never recorded. We copy what exists and we say which columns will stay empty for the earlier period. Filling those columns by estimation would produce apparently complete data on which somebody will base a decision, which is more damaging than an empty cell.

Finally, we do not promise an error rate. This page explains why no published one exists — the event is recorded as a failure by neither system — and it would be incoherent to announce one after writing that. What we can promise is that the gap will be measured at your end, every week, and kept, so that the question “since when” always has an answer.

Frequently asked questions

How do you know an integration is correct and not merely running?

By counting on both sides. The acceptance test proves the pipe exists; it says nothing about what will flow through it for three years. Record the number of records and the total of the field that matters, on both sides, at the same moment, and keep those four numbers. “Does it work” is answered once; “is it correct” is a property that is maintained or lost, and it is lost silently.

Which system is right when the two contradict each other?

The question has no answer at the level of the system, only at the level of the field. For each field that moves, only one is the source and the other receives a copy it may not change. Without that page, the first conflict is settled by the execution order of the programs — and the business concludes that “the tool wipes changes”, when it is applying a rule nobody wrote down.

Why do duplicates come back after being cleaned up?

Because the cause is not data entry but a missing link: nothing keeps the connection between the originating identifier and the receiving one, so at the next send the receiving system does not recognise the record and recreates it. That correspondence has to be stored — a two-column table — before merging anything, or the cleanup is redone the following week.

What happens when the other system is down?

Three behaviours are possible and one is acceptable. Losing the send produces an invisible divergence. Blocking and waiting turns their outage into yours. Setting aside and retrying preserves both — provided the queue has a limit and speaks up past a threshold, or somebody will empty it one day to unblock things and nobody will know what was in it.

Can we recover the last two years of history?

What was recorded, yes; what was never entered, no, and no migration will make it appear. The distinction changes the estimate completely, so it belongs in the quotation in plain words: here are the fields brought across, here are the ones that will stay empty for the earlier period. Filling them by estimation would produce apparently complete data on which somebody will base a decision.

Is there a benchmark divergence rate?

No, and not because it is confidential. Nobody has ever been able to measure it: as far as the two pieces of software are concerned, the operation succeeded — the send succeeded, the write succeeded. The event is recorded nowhere as a failure, so there is no population of errors to sample. The only figure that concerns you is the gap measured at your end, every week, and kept.

Where we come in

Counting on both sides across three months gives two numbers that never coincide. The gap is not an arithmetic error: it is two systems with different definitions.

  • We fix in writing, for each field, which of the two systems is authoritative.
  • We copy across what exists and mark what is missing as missing.
  • We refuse to build until that one-page document is signed.

What was never keyed in does not exist, and we will not invent it to fill a gap: a reconstruction is worse than the hole.

Read next

Let us talk about your project

A free audit, no commitment: we look at your online presence and tell you what is holding it back.

We measure how this site is used with Google Analytics, to learn which pages actually help. You can stop that measurement at any time from the footer. Cookie policy