# Rapport d'enrichissement de catalogue

**Source :** `catalogue-source.csv` — 119 lignes, 11 colonnes
**Sortie :** `catalogue-enrichi.csv` — 110 références uniques, 16 colonnes
**À trancher par un humain :** `a-decider.csv` — 90 lignes

---

## 1. Taux de remplissage, avant et après

| Champ | Avant | Après | Écart |
|---|---:|---:|---:|
| libellé | 97.5 % | 100.0 % | +2.5 pt |
| marque | 100.0 % | 100.0 % | +0.0 pt |
| catégorie | 100.0 % | 100.0 % | +0.0 pt |
| prix | 100.0 % | 100.0 % | +0.0 pt |
| poids | 89.9 % | 90.0 % | +0.1 pt |
| couleur | 83.2 % | 82.7 % | -0.5 pt |
| matière | 70.6 % | 68.2 % | -2.4 pt |
| GTIN valide | 47.9 % | 48.2 % | +0.3 pt |
| attribut métier structuré | 0,0 % | 100.0 % | +100.0 pt |
| chemin de taxonomie | 0,0 % | 100.0 % | +100.0 pt |
| slug d'URL | 0,0 % | 100,0 % | +100,0 pt |

**Références complètes sur tous les champs obligatoires : 54/110 (49.1 %).**

Le champ « attribut métier » est le vrai apport : le volume d'un sac, la température de
confort d'un duvet ou le flux d'une frontale étaient noyés dans le libellé, en texte libre.
Ils sont désormais des colonnes exploitables — donc filtrables en boutique, et lisibles
par un flux Google Shopping.

---

## 2. Corrections appliquées

| Correction | Occurrences |
|---|---:|
| libellé nettoyé (HTML, espaces, casse, unités recollées) | 99 |
| catégorie libre rattachée à la taxonomie | 96 |
| poids converti en grammes (kg, g, « grammes ») | 74 |
| casse de marque normalisée | 71 |
| prix converti en décimal (formats €, EUR, virgule, espaces) | 62 |
| GTIN invalide écarté | 37 |
| couleur normalisée | 35 |
| matière normalisée | 35 |
| stock négatif ramené à 0 | 29 |
| stock non numérique ramené à 0 | 23 |
| attribut « temperature_c » extrait du libellé | 17 |
| attribut « volume_l » extrait du libellé | 17 |
| attribut « flux_lm » extrait du libellé | 17 |
| attribut « longueur_cm » extrait du libellé | 16 |
| attribut « places » extrait du libellé | 13 |
| attribut « epaisseur_cm » extrait du libellé | 13 |
| attribut « poids_annonce_g » extrait du libellé | 12 |
| attribut « contenance_ml » extrait du libellé | 11 |
| doublon de référence fusionné | 6 |
| libellé vide — ligne écartée | 3 |

**Total : 686 corrections déterministes.**

---

## 3. Ce que la machine n'a pas tranché

90 lignes sont remontées dans `a-decider.csv`.

| Motif | Lignes |
|---|---:|
| matière incohérente avec la catégorie | 44 |
| GTIN invalide (clé de contrôle ou longueur) | 37 |
| doublon avec deux prix différents | 6 |
| libellé vide | 3 |

Aucune de ces valeurs n'a été devinée. Un pipeline qui invente un prix manquant ou
rattache une catégorie inconnue « au plus proche » ne produit pas un catalogue complet,
il produit un catalogue faux — et l'erreur devient invisible. Le temps humain se
concentre ici, et nulle part ailleurs.

---

## 4. Contrôles exécutés

| Contrôle | Règle |
|---|---|
| Doublon de référence | fusion des deux lignes, la valeur renseignée l'emporte sur le vide ; prix divergents remontés |
| GTIN-13 | longueur 13 + clé de contrôle modulo 10 recalculée ; les codes tout à zéro sont rejetés |
| Prix | `12,90 €`, `12.90EUR`, `  12.90  ` → `12.90` ; zéro et négatif rejetés |
| Poids | `780g`, `0,78 kg`, `780 grammes` → `780` |
| Libellé | balises HTML retirées, espaces insécables et multiples réduits, capitales corrigées, unités recollées |
| Catégorie | rattachement à une taxonomie fermée + chemin Google Shopping ; hors référentiel = remonté |
| Matière | cohérence avec la catégorie (un duvet en acier inoxydable est une erreur de saisie) |
| Stock | valeurs négatives et non numériques ramenées à 0 |
| Slug | translittération sans accent, minuscules, tirets |

---

## 5. Reproductibilité

```bash
python3 generer-source.py   # régénère la source, graine fixe
python3 enrichir.py                    # régénère les trois fichiers de sortie
```

Le traitement est déterministe : deux exécutions sur la même source donnent le même
octet. C'est ce qui rend le rapport opposable.
