DeftechSenior

Data platforms

A data platform is the stack that collects, stores and moves an organisation’s records, and one built for a reliable network sends first and stores as a side effect. Invert that assumption and the architecture inverts with it: the node writes locally and always, and sending becomes an opportunistic background activity that may not happen today. The page opens with twelve ways a disconnected platform loses or corrupts data, each with the design that prevents it, then covers the priority queue, the receiving side that expects to be interrupted, what every record carries, evidence as a deliverable, twenty years of formats, and seven documented cases.

Write
Locally, always
Send
By priority, when possible
A record outlives
The software reading it

Twelve ways a disconnected platform loses data, and the design for each

Here is the whole list first, because a disconnected platform rarely fails in the lab and usually fails in one of these twelve ways in its first months in the field — quietly, with every dashboard green. Each row pairs what you will see with what actually happened and the design that prevents it. The rows are numbered so a review can say "we have nothing for row 9", and the sections below refer to them by number.

#What you seeWhat actually happenedThe design that prevents it
1The newest alert arrived after an hour of routine telemetryThe queue sent in arrival order, and each window closed before it reached the alert.Priority classes, with the critical class always sent first.
2The queue never empties, although the link comes up every hourEvery transfer restarts from the beginning, and every window closes before the end.Resumable transfer, with progress kept per record.
3Hours-old positions use up a forty-second windowNothing in the queue ever expires, and a newer position does not replace an older one.An expiry per class, and state that supersedes itself; an expired record is dropped on purpose and counted.
4Counts are too high after a day of bad linksA retry after a cut window was stored as new data, because the receiver assigned the ids.Ids generated at the edge when the observation is made; ingest ignores an id it already holds.
5Yesterday’s position replaced today’s on the mapRecords were placed in the order they arrived, not the order they happened.Every record carries its event time and is placed by it.
6A correction erased the original report, and with it the disagreementThe store overwrote the record on update.Append only: a correction is a new record pointing at the old one.
7A faulty sensor’s records cannot be found, let alone excludedRecords did not say which device, sensor or software version produced them.Provenance on every record, from the first schema.
8A working system cannot be deployed, because its data sits in the wrong placeClassification was a label added at export, not a field the storage was chosen by.Classification is a field of every record and decides where it may be stored and sent.
9A deletion run removed records it should have keptRetention was a script run against the live store, with no preview and no record of what it removed.A retention rule on each record; every deletion run is previewed, logged and reversible for a grace period.
10Records went missing between two systems, and every total still looked plausibleA format or interface limit truncated the transfer without an error.Every transfer is counted at both ends, and a mismatch stops the pipeline.
11Nobody can say what the system knew at 14:02Only the current state was kept; each update destroyed the one before.Keep when each fact was recorded as well as when it happened, and query "as known at".
12Ten-year-old records cannot be readThe format depended on a program, a library version or a medium that no longer exists.Open, documented, self-describing formats, with archived samples read back on every release.

Store and forward, and the queue that makes it a design

Store and forward is old and simple: write it down where you are, send it when you can. What makes it a design rather than a buffer is what happens when the queue is bigger than the window — which is the normal case, not the exception.

When the link is an event rather than a utility, the default architecture inverts: the node writes locally first and always, and sending is an opportunistic background activity that may not happen today. What makes this design rather than buffering is the priority queue. The contact window is short and the bandwidth is small, so most of what is queued will not fit, and which records leave first has to be decided in advance — a two-kilobyte critical event ahead of forty kilobytes of track updates ahead of nine hundred megabytes of video that may never leave at all. The receiving side is built for interruption as the normal case: transfers are idempotent so a retry costs nothing, arrival order is assumed to be wrong, and nothing already stored is overwritten by something arriving later. Three properties travel with every record and are painful to add afterwards. Provenance, because a record without a source cannot be judged. Classification, because it decides which storage the record may legally sit in. And a retention rule, because here deletion is an obligation somebody will audit rather than a cost optimisation.

Do the arithmetic once and the point becomes obvious. A forty-second window at nine kilobits per second moves about forty-five kilobytes. The critical event is two kilobytes and goes every time. The track updates are forty kilobytes and go most times. The video is nine hundred megabytes and will never go over this link at all — which is a design fact to be decided in advance, not a surprise to discover in the field. Video leaves on physical media when the platform returns, or it is summarised on board into something that fits, or it does not leave.

That decision is a table somebody has to write, class by class. The sizes below are illustrative; the columns are not. The column people leave out is expiry, and it is what row 3 is about: a position update is only worth sending until a newer one exists, so state should supersede itself in the queue rather than wait its turn behind itself.

ClassExamplesTypical sizeWhen it stops being worth sendingIf the window is short
1 · Critical eventA contact report, a fault, an alert raised by a person1–2 KBNever; it is sent until acknowledgedAlways first, repeated until acknowledged
2 · StateOwn position, track updates, battery and healthTens of KB an hourWhen a newer value existsSend the latest; drop what it supersedes
3 · SummaryDetection lists, thumbnails, a summary of the last hour of video10–500 KBAfter hoursWhen there is room
4 · BulkRaw video, full logsHundreds of MBOn returnNever over this link; physical media on return

The same logic applies to the node’s own storage, which is a queue too. A node offline for a week fills its disk, and with no budget the first thing to go is whatever arrives next — often the alert. Give each class a storage budget: routine data is evicted oldest first, critical data never, and every eviction is counted, so "we dropped 4,000 position updates" is a line in a report rather than a discovery.

The receiving side assumes it will be interrupted

Because the window closes without warning, every transfer is a transfer that might be half finished, and the connection that resumes may be a different one, from a different node, out of order. The design question is therefore not the first window but the second: what happens to the records that were in flight when the first one closed. That is rows 2 and 4, and three common answers are drawn below.

A contact window closing halfway through a transfer is not the failure case; it is the normal one. What matters is what the next window does, and three common designs give three different answers. If the receiver assigns record ids on arrival, the retry of records one to six looks like new data and is stored a second time — six permanent duplicates that no later clean-up can safely remove, because the copies are genuinely different rows. If transfers cannot resume, every window starts again at record one and is cut at record six again, so a queue larger than a window never drains. If ids are generated at the edge at the moment of observation and progress is tracked per record, the next window continues at record seven, and the one record re-sent across the cut is recognised by its id and ignored. The second design fails loudly, eventually. The first fails silently and for good: every count downstream is quietly wrong.

Four properties make interruption survivable, and all four are cheap to build in and painful to retrofit.

PropertyWhat it means concretelyWhat breaks without it
Idempotent ingest (row 4)Every record has a stable id generated at the edge; receiving it twice is indistinguishable from receiving it once.A retry after an interrupted window produces duplicates, and the count of everything is quietly wrong.
Order independence (row 5)Records carry their own event time and are placed by it, not by the sequence they arrived in.Yesterday’s batch arriving after today’s rewrites the present with the past.
Append, never overwrite (row 6)New information is a new record referencing the old one; nothing already stored is replaced.A late correction deletes the original observation, and the disagreement that mattered is gone.
Resumable transfer (row 2)Progress is tracked per record, so the next window continues rather than restarting.A queue larger than a window never drains, because every attempt starts from the beginning.

Together these make the sync protocol an exchange of immutable facts rather than a reconciliation of mutable state, which is a considerably simpler thing to get right. It is also the property the layer depends on — its checklist line 3.1, an log of reports rather than a diff of tracks. Correlation can only be re-run over the union of what both sides saw if both sides kept what they saw as records rather than as a current value.

What travels with every record

Each of these looks like metadata and each one decides something structural. Adding any of them later is a migration across every producer, every store and every consumer, which is why they belong in the first schema. Read the last column as the reason: each field is there because a row of the opening table happens without it.

FieldWhat it holdsRow it prevents
IdGenerated at the edge when the observation is made, stable across every retry.4
Event time and recorded timeWhen it happened, when the platform learned it, and which clock stamped each.5 and 11
ProvenanceDevice, sensor, software version, operator; for a derived record, the records it was derived from.7
Priority class and expiryIts place in the queue, and when it stops being worth sending.1 and 3
ClassificationThe handling category, which decides where the record may be stored, who may read it and where it may cross a border.8
Retention ruleHow long it is kept and what happens then — on the hub and on the device.9
CorrectsFor a correction, the id of the record it amends; the original stays.6

Classification is the field that surprises engineers, because it moves a legal question into the architecture. If a category of record may not leave a jurisdiction or may not sit on a shared service, that constraint decides where the store lives, how the sync is routed and which managed products are available to you — and it decides it before any performance consideration does. Nor is it a property of single records only. In January 2018 a fitness app’s public heatmap, built from a billion harmless runs, turned out to trace soldiers’ routes around bases whose layout was not public. A platform that classifies record by record also needs a rule for aggregates, and the export that builds one is where to enforce it.

Retention cuts both ways, which is row 9. Deletion here is an obligation somebody will audit, not a way to reduce a storage bill, and it has to reach the copy on a device you may not see again — so the rule travels with the record and the device enforces it on its own. Backups and archives are the part usually forgotten; encrypting each retention period under its own key and destroying the key when the period ends is how a deletion reaches copies nobody can list. The other half is just as real: in January 2021 a defective weekly deletion job on the UK Police National Computer removed hundreds of thousands of records it should have kept. A deletion run is previewed, logged and reversible for a grace period before it becomes final.

Evidence is a deliverable: what the system knew, and when

In this field, showing that something works is a deliverable with its own effort estimate: test records, traceability from each requirement to the test that proves it, an argument for why the safety case holds. The data platform carries the same obligation after the fact. When something goes wrong, the question is never what is true now. It is what the system knew at a given moment, what it showed the person who acted, and whether anyone has changed that record since.

After an incident the question is never what is true now. It is what the system knew at a given moment, and what it showed the person who acted. Here one contact happened at 13:58, its report reached the platform at 14:07, and a correction pointing at that report arrived at 14:18. The axis is recorded time — when the platform learned each fact — because that is the axis the question is about. Asked afterwards, a store that updates in place can answer only for now: the first position was overwritten at 14:18, and what the system knew at 14:02 and 14:12 is simply gone. A store that keeps both the event time and the recorded time, and appends rather than updates, answers all three: nothing yet at 14:02, which is itself evidence; the contact at its first reported position at 14:12; and at the end the corrected position with the original still linked to it. The cost is one more timestamp per record and a rule against updating in place.

The mechanism is two times on every record, which is row 11. Event time is when something happened; recorded time is when the platform learned it. Keep both, never update in place, and "as known at 14:02" becomes an ordinary query rather than an impossible one. SQL:2011 standardised both kinds of time in tables, and several databases implement it; an append-only log with two timestamps gets you the same property without depending on any one of them.

What an investigator asksWhat the platform must have kept
What did the system know at 14:02?Recorded time on every record, and no updates in place (row 11).
What did the operator see, and what did they choose?The display state and the decision, recorded — line 6.5 of the C2 checklist.
Where did this value come from?Provenance, down to the sensor and the software version (row 7).
Has anyone changed it since?An append-only log whose entries are chained by hash, so an edit shows, and a record of every administrative access.
Did every record arrive?Counts at both ends of every transfer (row 10).
Which test shows this requirement is met?Traceability from the requirement to the test, to its result, to the build that was tested.

Twenty years of formats

Ten to twenty years in service is normal here, and it changes every data-format decision. The records a system writes in its first year have to be readable in its last, by software that has not been written yet, maintained by people who have never seen the original program. The diagram puts numbers on that: by the vendors’ own policies, everything that reads the data will be replaced several times over while the data stays where it is.

Defence systems stay in service for ten to twenty years, and the records they produce must stay readable for at least as long. The software that reads them does not last that long. By the vendors’ own published policies, PostgreSQL supports each major version for five years, Python each release for five, and Ubuntu’s LTS releases get five years of standard support; Kubernetes gives each minor version about a year of patches. Across a twenty-year service life that is four PostgreSQL versions, four Pythons, four Ubuntus and twenty Kubernetes versions, every one of them replaced while the data stays where it is. So the data format is the one component that must not change with them. It has to be open and documented, carry or reference its own schema, and evolve only by rules an older reader tolerates. And the only proof that it survived is a test: a stored sample of every schema version, read back by the new reader on every release.

The cautionary tale is from 1986. The BBC marked the 900th anniversary of the Domesday Book with a digital survey of Britain, stored on laserdiscs that only one particular computer setup could read. By 2002 working hardware was so rare that the content had to be rescued by emulation. The Domesday Book itself, written in 1086, was readable the whole time.

  • Open, documented formats with a published specification — not the internal file of one product, and not whatever the current library happens to serialise.
  • The schema travels with the data or is referenced from it by version, so a file explains itself without the program that wrote it.
  • Schemas evolve by rules an older reader tolerates: fields are added, never repurposed, and an unknown field is preserved rather than dropped.
  • A sample of every schema version is archived and read back by the new reader on every release — row 12, as a test.
  • Storage media are migrated on a schedule, while drives for them are still easy to buy, not when the last one fails.

Seven cases, and the row each one teaches

Defence data failures are rarely published, so these cases are civilian, for the same reason as on the computer vision page; the mechanisms transfer exactly. Two of the seven are about data that survived rather than data that was lost, because that is the other half of the lesson: what investigators had was what had been written locally, or was small enough to leave first.

CaseWhat happenedThe row it teaches
BBC Domesday Project, 1986A digital survey of Britain, made by about a million contributors for the Domesday Book’s 900th anniversary, was published on laserdiscs for one specific BBC Micro setup. By 2002 working hardware was so rare that the content had to be rescued by emulation; the Domesday Book of 1086 stayed readable throughout.12. The format lived and died with one machine.
Space Shuttle Columbia, February 2003When Columbia broke up on re-entry, telemetry to the ground stopped first. Its Orbiter Experiments recorder, a tape recorder logging sensors that were never transmitted, was found intact near Hemphill, Texas, on 19 March 2003. Its data ran past the moment telemetry was lost and gave investigators readings they had no other way to get.The page’s first rule rather than a row: write locally, always. The recorder kept what the link never carried.
Air France 447, June 2009An Airbus A330 was lost over the Atlantic. For almost two years the main evidence was 24 automatic maintenance messages the aircraft had sent over ACARS in its last minutes, pointing to unreliable airspeed readings; the recorders were raised from the seabed only in May 2011. ICAO now requires new large aircraft in distress to report their position at least once a minute.1. The small, critical records that left first were, for two years, the only ones that arrived.
Strava heatmap, January 2018A fitness app published a global heatmap built from a billion activities. In January 2018 an Australian student, Nathan Ruser, pointed out that in places such as Syria and Afghanistan it traced soldiers’ running routes around bases whose layout was not public. Each run was harmless; the aggregate was not.8. Classification was decided per record, and nobody classified the aggregate.
Post Office Horizon, judgment December 2019For fifteen years the UK Post Office prosecuted hundreds of sub-postmasters over shortfalls shown by its Horizon accounting system. In December 2019 the High Court found that Horizon had bugs capable of causing such shortfalls, and that branch accounts could be altered remotely — which the Post Office had publicly denied. In 2021 the Court of Appeal quashed 39 convictions, holding the Horizon evidence unreliable.6 and 11. Changes were not appended with an author, so nobody could show who had changed what, or what the system had known.
Covid-19 test results, England, October 2020Public Health England found that 15,841 positive results from 25 September to 2 October 2020 had been left out of its daily figures. Lab results passed through a spreadsheet template in the old XLS format, which holds 65,536 rows; everything past the limit was dropped without an error, and contact tracing for those cases started days late.10. Nothing counted the rows at both ends.
Police National Computer, January 2021A weekly job meant to delete records past their retention date ran with a coding error and deleted records it should have kept — by the police lead’s later estimate about 213,000 offence records, 175,000 arrest records and 15,000 person records, with linked DNA and fingerprint records deleted as well.9. The deletion ran with no preview, and undoing it became a recovery project.

Where it degrades

The honest limit is that store and forward only decides the order of loss. A node destroyed before its window loses whatever it held; the priority queue decides only which records had already left. Nothing in the platform recovers an observation that was never recorded, and no queue makes a nine-kilobit link carry video. The honest design says in writing what is lost first when things go wrong, rather than implying that nothing is.

  • Priority classes where every producer marks its own records critical, which quietly turns the queue back into first in, first out.
  • An "offline mode" tested by unplugging a cable for five minutes.
  • Provenance fields that exist in the schema and say "unknown" in most rows.
  • Everything classified at the highest level, so nothing can be shared and people copy data out by hand.
  • Append-only in the database, and an export job that overwrites.
  • A retention policy that exists as a document and is enforced nowhere, least of all on devices.
  • An archive nobody has read back since the day it was written.
  • A sync dashboard that shows success rates but not counts, so a transfer that dropped half its rows reports success.
  • "Keep everything forever" presented as caution, when it is a retention decision nobody made.

When to use it

Use it when

  • As a design review for any platform that works through long absences of network — the twelve rows at the top.
  • When the queue is larger than the contact window, which makes the priority order a product decision.
  • When writing the first schema, since ids, both times, provenance, classification and retention are migrations if added later.
  • When somebody will one day have to show what the system knew, and when — which, in this field, is always.

Avoid it when

  • As general data engineering material — the databases and infrastructure sections own that and this page leans on them.
  • As guidance on the shared picture built from this data, which is the C2 page rather than this one.
  • Where the network is genuinely reliable, in which case store and forward is complexity you are not being paid for.
  • As a reason to keep everything forever, since retention here is an obligation rather than a storage decision.

Sources and method

What this page stands on

  • 11 sources
  • 6 documented failures
  • Checked October 13, 2026

Researched with Claude. Finding and cross-checking the primary sources was done with Claude (Anthropic). Selection, writing and fact-checking: the Anatomy of IT Product editors.

Found this useful?

Share it with someone who is working on the same problem.