Ground Truth

Why Air-Gapped Changes Every Assumption in Your ML Pipeline

Mostafa DhouibMostafa Dhouib··7 min read
The short answer

An air gap is usually treated as a deployment constraint, something to solve at the end with a USB drive and a procedure. It is not. It invalidates assumptions at every stage of the pipeline: how you get data, how you version artifacts, how you know what is running, how you evaluate, and how you find out anything went wrong.

Why Air-Gapped Changes Every Assumption in Your ML Pipeline

The short answer. An air gap is not a deployment detail bolted on at the end. It breaks an assumption at every stage: training data arrives in batches with latency measured in weeks, artifact identity has to be established without a registry, you cannot query what version is running, evaluation cannot use production traffic, and failure discovery happens when someone walks back with a drive. Each of those has a fix, all the fixes are architectural, and every one is expensive to retrofit.

Teams treat the air gap as a packaging problem. The pipeline is built the normal way, and near the end someone is assigned to work out how the model gets across.

That framing is wrong in a way that costs a program its schedule, because the air gap does not change the last step. It changes every step.

Collect data
returns in weeks or months, biased by who carried it
Train
on a distribution that is ageing between collections
Version the artifact
no registry. Identity has to be established by hash
Evaluate
no production traffic. What you validated is the whole evidence base
Deploy
a person, a drive, and a procedure
Observe
fixed at ship time. You cannot add a log line to a fielded unit
Every item is the same move: something that was a runtime capability becomes a design-time decision. A team that defers them is choosing the connected defaults.
FigureAn air gap is treated as a packaging problem to solve at the end. It changes every stage, and each fix has to be made before the thing it governs is built.

Data collection: the loop closes in weeks, not minutes

In a connected system, production inputs flow back continuously. Hard cases accumulate, the distribution is observable, and retraining is a decision about when rather than whether you have the data.

Air-gapped, data comes back when someone physically carries it back. The loop closes in weeks or months, sometimes not at all, and what returns is a subset chosen by whoever was doing the carrying.

Three consequences worth designing around.

You must decide in advance what to keep. Storage on the platform is finite and the interesting cases are rare. A policy that keeps everything fills the disk with the ordinary; a policy that keeps only failures cannot tell you your false-negative rate, because a failure the system did not recognise is not recorded as one. Keep a stratified sample plus everything near the decision boundary, and decide it before the unit ships.

Your training distribution ages. Between collections, the field moves and your dataset does not. This is ordinary drift with the feedback loop removed, so the first sign of it is a degraded demonstration rather than a metric.

The returning data is not representative. It is biased by which units came back, which operators bothered, and which missions were run. Treat it as a convenience sample, and say so in the same sentence as any number computed from it.

Artifact identity: no registry, so hash everything

The most common cause of "it worked in testing" is that the artifact serving production is not the artifact you evaluated. Connected systems paper over this with a registry: the model has an id, the id is queryable, and you can check.

Across an air gap the chain of custody is a person, a drive, and a procedure. Every one of those is a place where a version can diverge without anyone lying about anything.

Built here
hash it
Packaged
hash it again
Carried across
the step with no automated record
Loaded on target
hash it once more, and let the unit state its own identity locally
The failure point
Version the whole pipeline, not just the weights.
Preprocessing, normalisation constants, vocabulary, thresholds, configuration. A matching model with mismatched preprocessing produces exactly the same symptom as a wrong model and takes far longer to find.
FigureConnected systems check artifact identity against a registry. Across an air gap the chain of custody is a person, a drive, and a procedure, and every step is a place a version can diverge without anyone lying.

The replacement is mechanical and it costs almost nothing to build early:

Hash the artifact, not the version string. Record the hash at build, at packaging, at transfer, and at load on the target. Four points, four recorded values, compared automatically.

Make the running system able to state its own identity locally. It cannot phone home, so it must be able to display or log a hash on demand, in a form an operator can read out.

Version the whole pipeline, not just the weights. The preprocessing, the normalisation constants, the vocabulary, the thresholds, the configuration. A model that matches and a preprocessing step that does not produces exactly the same symptom as a wrong model, and takes far longer to find.

Evaluation: your test set is the whole world

Connected systems evaluate continuously against live traffic. Air-gapped, whatever you validated before shipping is the entire evidence base until someone returns.

That makes two ordinary practices load-bearing rather than optional.

Split by group, never at random. If the same operators, the same units, or the same conditions appear on both sides of the split, your number measures internal consistency and you will not find out otherwise for months. Hold out whole units, whole operators, whole sites, whichever will be new in the field.

Report by slice, and treat the worst slice with real volume as the decision. One aggregate number over a mixed set hides the condition where it fails, and in the field you meet the conditions rather than the average.

The cost of getting this wrong is asymmetric here in a way it is not in a web service. A connected system that ships with an inflated number finds out in a week. An air-gapped system finds out at the demonstration.

Observability: decide the black box before you ship

You cannot add a log line to a fielded unit. Whatever the system records is fixed at ship time, and it is the only account you will ever have of what happened.

Four things worth recording that teams routinely omit:

Inputs near the decision boundary, because those are the cases that teach you something.

Every time a fallback or default path was taken. These return silently by design, which is what makes them invisible and why the absence of the counter is itself a finding.

Every refusal. For a fail-closed system, the refusal rate is the primary health signal. A system refusing far more than expected is degraded even though nothing errored.

The artifact hash and the configuration in force, written into the same record, so an anomalous trace can be attributed to a build without anyone having to reconstruct what was deployed that week.

Inputs near the decision boundarythe cases that teach you something
Every fallback or default takensilent by designthe absence of this counter is itself a finding
Every refusalthe primary health signal for a fail-closed systemrefusing more than expected is degradation with nothing erroring
Artifact hash and configuration in forcein the same recordso an anomalous trace can be attributed without reconstructing the week
FigureWhat the system records is fixed at ship time and is the only account you will ever have. Four things teams routinely omit.

Dependencies: the environment must be reproducible offline

The mundane one that consumes the most calendar time.

No package index, no model hub, no container registry, no certificate revocation check, no time server. Every one of those is a network call some library makes without telling you, and each fails differently on a machine with no route out. Some hang until a timeout, which is worse than failing, because a hang at load time looks like a hardware problem.

The work is to build and validate the full environment offline from the start, not to discover the dependencies when the target machine is in front of you. That includes pinning everything by hash, vendoring what you cannot pin, and running the build once on a machine with the network physically disconnected. The last one finds things no audit of the manifest will.

The pattern underneath

Every item on this list is the same move: something that was a runtime capability becomes a design-time decision.

Data collection becomes a retention policy. Version checking becomes a hashing scheme. Evaluation becomes a split strategy. Debugging becomes a recording plan. Dependency resolution becomes a vendored environment.

That is why an air gap cannot be handled at the end. Each of those decisions has to be made before the thing it governs is built, and a team that defers them is not deferring work but choosing the defaults, which are all the connected ones.

This is the shape of most defense and uncrewed systems work, where the air gap is a requirement rather than a circumstance. It applies equally to any system deployed somewhere it cannot be reached: a device in a hospital, a controller in a substation, a unit in a vehicle.

FAQ

Is an air gap just a deployment constraint? No. It invalidates an assumption at every pipeline stage: data collection becomes batched and biased, artifact identity has no registry to lean on, evaluation cannot use production traffic, observability is fixed at ship time, and dependency resolution has no network. Each fix is architectural and expensive to retrofit.

How do you verify which model is running on an air-gapped system? Hash the artifact and record it at build, packaging, transfer and load, comparing automatically. Version the whole pipeline including preprocessing and configuration, and make the running system able to state its own hash locally, since it cannot report it anywhere.

How should an air-gapped system be evaluated? Split by group rather than at random, holding out whole units, operators or sites that will be new in the field, and report per slice rather than as one number. Whatever you validated before shipping is the entire evidence base until someone physically returns with data.

What should an air-gapped system record? Inputs near the decision boundary, every fallback or default path taken, every refusal, and the artifact hash plus configuration in force. It cannot be changed after shipping, so the recording plan is a design decision rather than an operational one.

Why do offline dependencies cause so much delay? Because libraries make network calls nobody declared: package indexes, model hubs, certificate revocation, time servers. Some fail, some hang, and a hang at load time presents as a hardware fault. Building once on a physically disconnected machine finds what no manifest audit will.

Free checklist
The Field Recovery Checklist

Sort every property into fixed at manufacture, changeable by update, or changeable by configuration, then run the physical ceiling arithmetic, the A/B slot and confirmation scheme, the staged rollout policy, and the absence monitoring. Includes an air-gap section for systems with no route home.

One email, the resource, and nothing else unless you reply.
Carrying a program like this one?

Tell us the system, the stakes, and the date that matters. You get a straight technical reply from the person who would lead the work, within 24 hours.

Bring us the program