Skip to content

The data gap (Article 10)

Article 10: representativeness meets bias detection

Section titled “Article 10: representativeness meets bias detection”

EU AI Act Article 10 is about data and data governance for high-risk systems. Two of its paragraphs matter to us, and the lesson lives where they meet.

  • Art. 10(3) says the training, validation and testing datasets must be relevant, sufficiently representative, and — to the best extent possible — free of errors and complete, in view of the intended purpose. This is where sample sufficiency and representativeness live. “Sufficiently representative” is not a slogan: it means you actually have enough data, including enough of the populations you intend to serve, to support the claims you are making about the system.

  • Art. 10(5) says providers may exceptionally process special categories of personal data — protected attributes such as ethnicity or sex — when strictly necessary to ensure bias detection and correction (read together with 10(2)(f) and (g)), and only under safeguards. In other words, the law anticipates that to check a hiring or screening model for disparate impact you may need to hold, carefully, the very attribute you must not discriminate on.

Now put them together, because the data gap lives at the union of the two. You cannot perform the bias detection and correction that 10(5)/10(2) require if you do not have a 10(3)-adequate sample — that is, enough data, including enough labelled examples of the protected group, to measure disparity with statistical reliability. A fairness measurement on 18 examples of a minority class is not a measurement; it is noise with a decimal point.

Most of the controls you meet are closable by a code change, and that is the whole shape of Risk-Driven Development: the treatment is a versioned change (ISO 23894 §6.5), and the git diff is the treatment.

  • A leakage control: a feature is leaking the target, so you drop the feature. One commit. The control flips GREEN.
  • A fairness control: a learner produces disparate impact, so you swap in a fairness-constrained learner or reweight. One commit. The control flips GREEN.

A sufficiency control is different in kind. Consider a control whose pass criterion is a sample-adequacy ratio:

sample_adequacy_ratio = n / 500 ≥ 1.0

No line of code you can write changes n. You can refactor the model, tune hyper-parameters, swap the learner, rewrite the pipeline — and the ratio does not move, because the binding quantity is how much representative data exists, not how the model is built. The treatment for this risk is therefore not a model change at all. It is a data gap (data_gap): the honest statement “the remedy is to acquire more representative data.”

The deepest openness: treated without a residual

Section titled “The deepest openness: treated without a residual”

Here is the mechanism that makes the data gap the hardest state in the course. It is verified in the engine’s coherence layer (cloud/lib/approval/coherence.ts), not asserted.

A risk that is treated (it has a treatment plan), and that relies on a blocking control (enforcement: gate), but has no bounded residual (no residual_likelihood declared), fires the violation treated-without-residual. And treated-without-residual is classified as a hard block (hardBlockingForApprove): the portal removes the «Approve» action entirely. Not greyed out, not behind a confirmation — gone. You literally cannot approve, with or without a motive.

Why is that the right behaviour, and not the engine being unhelpful? Because the reasoning is profound and worth saying plainly:

You cannot consciously accept a residual you cannot even measure.

A residual is the risk that remains after treatment. To accept it knowingly, you must first be able to state it — “after treatment, the likelihood of harm is X, and that is what I am signing for.” On a data gap, the data needed to estimate X is not there. There is no residual to certify, so there is nothing to accept yet. The engine refuses to let you sign for a number that does not exist. That refusal is the engine being honest about the limits of its own evidence.

The red door, and why this is one step further

Section titled “The red door, and why this is one step further”

Elsewhere in the course you meet the “red door”: the case where the owner may approve a risk that is above appetite, but only with a mandatory, recorded motive. That mechanism is real, and it is different from the data gap. Both are verified in coherence.ts:

  • residual-exceeds-appetite — the risk has a measured residual, and that residual is higher than the appetite. The owner may approve, but the act demands a mandatory motive that is recorded server-side. (On the CLI, froga approve has no --reason flag, so this conscious-acceptance act is portal-only.)
  • untreated-above-appetite — the risk is untreated and sits above appetite. Same shape: approval is possible with a recorded motive.

That is the red door: conscious risk acceptance over appetite, recorded — eyes open, on the record. (And note: walking through it is a governance decision by the owner, not a basis of conformity. The verdict still shows the risk was accepted over appetite.)

So what do you do with a data gap? You acquire more representative data — enough, including enough of the protected group, to make the bias check (10(5)) statistically meaningful and the sample sufficient (10(3)). Then you re-measure. A residual finally exists. Only then can the cycle move past request.

Everything else is a lie dressed as a fix:

  • Lowering the threshold so 0.43 “passes” does not make the sample representative; it just hides the inadequacy. Fraud.
  • Faking n so the ratio reads ≥ 1.0 fabricates the very evidence the gate exists to check. Fraud.

The engine will not do either. It leaves the gate honestly RED and the lifecycle paused.

Why can't a sufficiency control be closed by a code change, when a leakage or fairness control can?

A leakage or fairness control is bound to how the model is built, so a versioned code change closes it: drop the leaked feature, or swap in a fairness-constrained learner, and the control flips GREEN — the git diff is the treatment (ISO 23894 §6.5). A sufficiency control is bound to how much representative data exists — e.g. sample_adequacy_ratio = n / 500 ≥ 1.0. No commit changes n: with n=215 the ratio is 0.43 at HEAD, at HEAD~1, and at every future commit, because none of them add data. The only thing that moves it is acquiring more data — a data_gap, not a model change.

What does `treated-without-residual` mean, and why is it harder than the 'red door'?

treated-without-residual fires when a risk is treated (has a plan) and relies on a blocking control (enforcement: gate) but has no bounded residual (no residual_likelihood). The engine classes it as a hard block (hardBlockingForApprove) and hides the «Approve» button entirely — you cannot approve with or without a motive. It is harder than the red door because the red door (residual-exceeds-appetite / untreated-above-appetite) lets you approve a measured-but-too-high residual with a recorded motive — eyes open, on the record. The data gap gives you no measurement to walk through, so the engine does not even offer the door: you cannot consciously accept a residual you cannot yet measure. It is one step more open.

A demo says the data gap is an 'Art. 10(5)' problem. What is the more precise framing?

The honest framing is the union of 10(3) and 10(5). Art. 10(5) lets you exceptionally process protected attributes when strictly necessary for bias detection and correction — that is what you must measure. Art. 10(3) requires the dataset to be relevant, sufficiently representative and complete — and that is why you cannot yet, because the sample is too small to measure disparity reliably (including too few examples of the protected group). The demo’s “10(5)” is a fair shorthand for the visible symptom (the bias check cannot run), but the binding requirement under it is the sufficiency/representativeness of 10(3). Teach the union.