---
{
  "title": "Cartographier Kahn sur FHIR",
  "description": "Qu'est-ce qui distingue de bonnes données FHIR des mauvaises? Le monde des données de santé a établi un vocabulaire précis à ce sujet il y a une décennie — le cadre de Kahn. Cet article en fait le tour et fait correspondre chaque partie à FHIR : ce que le validateur couvre déjà, et ce qui nécessite un jeu de données complet.",
  "date": "2026-07-21",
  "author": "Nikolai Ryzhikov",
  "reading-time": "8 min read",
  "tags": [
    "SQL on FHIR",
    "Data Quality",
    "Analytics"
  ],
  "tldr": "Demandez à des spécialistes FHIR ce que signifie la qualité des données, et ils vous parleront du validateur : profils, cardinalités, liaisons, invariants. Demandez à des ingénieurs de données, et ils vous parleront des tests dbt : non-nul, unique, valeurs acceptées, fraîcheur. Les deux ont à moitié raison, et ces moitiés ne se recoupent pas là où chacun le suppose. La frontière n'est pas conformité-contre-le-reste — le validateur FHIR vérifie aussi la plausibilité, via minValue/maxValue et les invariants. La frontière, c'est la portée : un validateur répond à toute question qui tient dans une seule ressource, et à aucune question qui ne le fait pas. Les proportions, les tolérances, l'unicité entre enregistrements, l'intégrité référentielle, les distributions, la fraîcheur — tout cela nécessite un jeu de données. Et méfiez-vous du mot « validation », qui désigne deux choses sans rapport dans ces deux univers.",
  "utm-campaign": "analytics",
  "utm-content": "kahn-framework"
}
---

> For the complete documentation index, see [llms.txt](https://www.health-samurai.io/llms.txt).
> Use it to discover all available pages before guessing URLs.

---

## Qu'est-ce qui rend les données bonnes — ou mauvaises?

Cela semble être une question simple, et ce n'en est pas une. Demandez à un spécialiste en implémentation FHIR ce que signifie la qualité des données, et il vous parlera du validateur : profils, cardinalités, liaisons de terminologie, invariants. Posez la même question à un ingénieur de données, et il vous parlera des tests dbt : non-nul, unique, valeurs acceptées, fraîcheur.

Les deux réponses ont à moitié raison, et ces moitiés ne se recoupent pas de la façon que chaque camp suppose. Cette confusion a un coût : certaines équipes reconstruisent le validateur en SQL, tandis que d'autres interprètent un résultat de validation vert comme « les données sont correctes » — et les deux erreurs se manifestent tard, généralement lorsqu'une mesure de qualité retourne un nombre que personne ne peut défendre.

La bonne nouvelle, c'est que le monde des données de santé a déjà trouvé une réponse précise à « qu'est-ce qu'une bonne donnée » il y a une décennie — le **cadre de Kahn**. Cet article en fait le tour et le fait correspondre à FHIR : ce que votre validateur couvre déjà, et ce qu'il ne peut structurellement pas couvrir.

Je suis allé le chercher en [portant les vérifications de qualité des données d'OMOP sur SQL on FHIR](/blog/fhir-data-quality-sql-on-fhir). La mécanique était simple; dire *lesquelles* des vérifications appartiennent au validateur et lesquelles n'y appartiennent pas était la partie difficile — et c'est ce cadre qui trace la ligne.

## Kahn, en trois questions

Kahn et al., [*A Harmonized Data Quality Assessment Terminology and Framework*](https://pmc.ncbi.nlm.nih.gov/articles/PMC5051581/) (2016). Ce n'est pas un ensemble de métriques ni un outil — c'est une **terminologie**, rédigée pour fusionner une douzaine de vocabulaires incompatibles que différents groupes avaient chacun inventés. C'est précisément pour cela qu'il a perduré. Se chicaner sur les noms coûte moins cher que se chicaner sur les mesures.

Il pose trois questions sur les données :

| Question | Kahn l'appelle | Exemple |
|---|---|---|
| Est-ce enregistré correctement? | **Conformance** | `Sex` n'a que les valeurs M, F ou U |
| La valeur est-elle présente? | **Completeness** | 40 % des observations ne portent aucune valeur |
| La valeur est-elle crédible? | **Plausibility** | Un poids corporel de 1 000 kg |

Deux détails sont porteurs de sens. La Completeness est *« sans référence aux valeurs des données »* — elle compte la fréquence de présence d'un élément, jamais ce qu'il dit. Et la Plausibility porte sur la **crédibilité, pas la vérité** : si 78 kg est plausible, non pas si le patient pèse réellement 78 kg. Rien dans les données ne peut répondre à la deuxième question, et le cadre n'en fait pas semblant.

## Le piège : « validation » a deux sens bien différents

Avant d'aller plus loin — ce mot va piéger un auditoire FHIR, alors laissez-moi désamorcer la situation.

En FHIR, *validation* signifie vérifier une ressource par rapport à une StructureDefinition. Chez Kahn, *validation* signifie comparer des données à un référentiel **externe**, par opposition à la *verification* par rapport à vos propres attentes. Des concepts sans rapport, le même mot, et ils se recoupent juste assez pour induire en erreur :

- Valider une ressource par rapport à **US Core** est une *validation* au sens de Kahn — la règle vient de l'extérieur.
- Valider la même ressource par rapport à **un profil que vous avez écrit vous-même** est une *verification* au sens de Kahn — la règle vous appartient.

Le validateur effectue un travail identique dans les deux cas. Seule la provenance de l'étalon a changé. Un test pratique : **pouvez-vous exécuter cette vérification avec rien d'autre que votre propre base de données?** Un poids de 1 000 kg — oui. La prévalence du diabète correspondant au taux national — non.

Un avertissement, parce qu'une version erronée circule largement : *verification = conformance, validation = completeness + plausibility* **n'est pas** ce que dit le cadre. Les deux axes se croisent véritablement. Le Data Quality Dashboard d'OHDSI, l'implémentation de référence du cadre, remplit les six cellules.

## La vraie frontière est la portée, pas la catégorie

Voici la partie que la plupart des articles ratent. La séparation **n'est pas** « le validateur s'occupe de la conformance, les vérifications de qualité s'occupent du reste. » La validation FHIR va considérablement plus loin que cela.

Elle vérifie la plausibilité, tant que la question tient dans une seule ressource. `minValue[x]` / `maxValue[x]` est littéralement une contrainte de plage plausible :

```json
{
  "path": "Observation.value[x]",
  "minValueQuantity": { "value": 0.5,  "unit": "kg" },
  "maxValueQuantity": { "value": 650,  "unit": "kg" }
}
```

Elle vérifie la plausibilité temporelle. Chaque `Period` en FHIR porte déjà `per-1` :

```
per-1: "If present, start SHALL have a lower or equal value than end"
       start.hasValue().not() or end.hasValue().not() or (start <= end)
```

Et elle vérifie la logique entre champs à l'intérieur d'une ressource, via les invariants :

```
obs-7: "If Observation.code is the same as a Observation.component.code
        then the value element associated with the code SHALL NOT be present"
```

Donc le validateur ne se limite pas à la structure. Ce qu'il ne peut pas faire, c'est tout ce qui nécessite une **population ou une deuxième ressource** :

| La question nécessite… | Exemple | Validateur |
|---|---|---|
| une seule ressource | poids entre 0,5 et 650 kg; `end` pas avant `start` | ✅ |
| une proportion | 40 % des Observations n'ont aucune valeur | ❌ pas de dénominateur |
| une tolérance | 5 % de valeurs manquantes acceptable ici, 0 % requis là | ❌ la validité est binaire |
| une autre ressource | Observation datée avant la naissance du patient | ❌ les références ne sont pas résolues |
| tous les enregistrements | un NIM par patient | ❌ aucun jeu de données en vue |
| une distribution | poids moyen, prévalence, dérive | ❌ nécessite une population |
| un référentiel externe | la prévalence correspond au taux national | ❌ rien à comparer |

Ce qui donne la formulation honnête en une ligne :

> **Un validateur répond à toute question qui tient dans une seule ressource, et à aucune question qui ne le fait pas.**

### Le seul cas qui se trouve exactement sur la ligne

Un élément est `min=1` et absent. Le validateur le signale, et cela ressemble à une vérification de complétude. Selon Kahn, il s'agit de **conformance** — une règle structurelle a été violée, pas une attente de fréquence.

La vraie complétude concerne les éléments *optionnels* renseignés si rarement que la colonne est inutile. La même requête SQL dans les deux cas; des catégories différentes, des mécanismes différents, déterminés entièrement par le fait que l'élément était obligatoire ou non.

## Ce que seul un jeu de données peut répondre

Tout ce qui est une propriété du jeu de données plutôt que d'un enregistrement individuel. En SQL on FHIR, ce sont des requêtes ordinaires sur une vue aplatie — l'idée étant qu'elles retournent les lignes fautives :

```sql
-- unicité entre enregistrements : un NIM par patient
SELECT mrn FROM patient_flat
GROUP BY mrn HAVING count(DISTINCT id) > 1
```

```sql
-- intégrité référentielle : subject pointe vers un Patient absent
-- (un export Bulk FHIR échoue à cela plus souvent qu'on ne le pense)
SELECT o.id, o.patient_id
FROM obs o LEFT JOIN pat ON o.patient_id = pat.id
WHERE o.patient_id IS NOT NULL AND pat.id IS NULL
```

```sql
-- temporel entre ressources : observation antérieure à la naissance du patient
SELECT o.id FROM obs o JOIN pat ON o.patient_id = pat.id
WHERE o.effective < pat.birth_date
```

Plus ceux qui n'ont aucun analogue sur un seul enregistrement : **les proportions** (40 % des valeurs manquantes), **les tolérances** (5 % acceptable ici, 0 % là), **les distributions** (moyenne, quantiles, valeurs aberrantes, dérive), **la fraîcheur** (le dernier enregistrement date de six semaines — rien ne cloche dans aucun enregistrement, c'est le jeu de données qui est périmé), et le **tableau de bord agrégé**.

Rien de tout cela n'est un manque qu'un meilleur validateur pourrait combler. C'est une question différente.

Et l'inverse mérite d'être dit, parce qu'une séparation nette nécessite ses deux moitiés : **les vérifications SQL ne voient que ce qu'une projection a exposé.** Le validateur inspecte la ressource entière — les éléments non projetés, le découpage, les extensions, les invariants sur les structures imbriquées, l'expansion des ValueSet avec hiérarchie. Les vérifications ne font ni ne devraient faire cela. Une vérification qui réimplémente une contrainte de profil est une deuxième source de vérité, et elle divergera de la première.

## Là où Kahn atteint ses limites

Deux lacunes que vous rencontrez immédiatement si vous vous appuyez sur ce cadre.

**Pas de fraîcheur.** « Les données arrivent-elles encore? » n'est ni de la conformance, ni de la complétude, ni de la plausibilité. C'est un échec réel et courant — la détection d'anomalies de Databricks se réduit à la fraîcheur et à la complétude — mais le cadre est antérieur à cette formulation. Soit vous ajoutez une quatrième catégorie, soit vous classez la fraîcheur sous la plausibilité temporelle et vous vivez avec l'inconfort.

**Pas de précision.** La plausibilité, c'est la crédibilité, pas la vérité. Que le poids enregistré soit le poids réel du patient est une question sans réponse à partir des données.

Deux éléments qu'OHDSI a dû ajouter en pratique valent la peine d'être adoptés en parallèle avec la taxonomie : un **niveau** (jeu de données / colonne / code) et une **sévérité** (fatal / convention / caractérisation). Leur répartition de sévérité sur 27 types de vérifications est instructive — 12 caractérisations, 8 conventions, 7 fatales. **La plupart des vérifications décrivent plutôt que jugent**, ce qui est une attente utile à établir avant que quelqu'un ne construise un tableau de bord qui colorie tout en rouge.

## Où cela nous mène

> Un validateur répond à *« cette ressource est-elle bien formée? »*
> Une vérification répond à *« ce jeu de données est-il utilisable? »*

La deuxième question est sans signification sans la première, et la première est insuffisante sans la deuxième. FHIR offre une excellente réponse à la première et, jusqu'à présent, aucun mécanisme standard pour la deuxième.

Ce qui est encourageant, c'est à quel point peu de choses restent à inventer. Le vocabulaire est établi. L'implémentation de référence tourne dans l'univers OMOP depuis une décennie. Et en FHIR, les pièces existent déjà : une ViewDefinition est le jeu de données, une SQLQuery est la vérification, et `relatedArtifact` déclare déjà le graphe de dépendances. Ce qui manque, c'est uniquement la sémantique — dire *cette requête est une vérification, voici ce qu'elle mesure, et ce niveau d'échec est acceptable*. C'est ce sur quoi porte le [travail sur la qualité des données de SQL on FHIR](https://github.com/HL7/sql-on-fhir/issues/375), et c'est ouvert.

---

**Sources**

- Kahn MG et al., *A Harmonized Data Quality Assessment Terminology and Framework for the Secondary Use of Electronic Health Record Data*, eGEMs 4(1):1244, 2016 — [PMC5051581](https://pmc.ncbi.nlm.nih.gov/articles/PMC5051581/). Toutes les citations proviennent de cet article.
- [OHDSI Data Quality Dashboard](https://github.com/OHDSI/DataQualityDashboard) — la matrice de classification à 27 types se trouve dans `inst/csv/OMOP_CDMv5.4_Check_Descriptions.csv`.