# GAB-221 · SmartSelectContentMatch — « Sélection du contenu pertinent »

**Archétype / renderer_key :** `text_cta` (cartographie) · **module :** EdTechSmartSelect
**Critère validé :** changer le JSON change le rendu sans modifier le HTML.

## Pack (structure officielle par-GAB)
```
GAB-221/
  renderer.html            ← moteur sélection contenu (ne pas modifier par instance)
  instance.example.json    ← SOURCE DE VÉRITÉ (contenu réel, à plat)
  schema.contract.json     ← contrat de validation
  README-contract.md       ← ce fichier
```

## Champs requis (instance, à plat)
`gab_id` · `title` · `selected_item{label,slug?,format?,estimated_duration?,difficulty?}` · `candidates[]{label,format?,status:'winner'|'eliminated',skip_reason?}` · `primary_cta{label,action}`

Optionnels : `content_match_id`, `summary`, `match_type`, `reason`, `match_type_enum`, `secondary_cta{label,action}`, `skip_cta{label,action}`.

## Ce qui vient du JSON vs HTML
- **JSON** : titre, résumé, match_type badge, candidat retenu (label/slug/format/durée/difficulté), raison du choix, pool de candidats, enum match_type, libellés des 3 CTAs.
- **HTML** : layout carte, section selected, reason-block, liste candidats avec statut WIN/SKIP, enum chips, 3 boutons CTA structurels.

## Archétype
SmartSelectContentMatch est la **couche de sélection pure** en entrée du pipeline SmartSelect (221→222→223→224→225). Il CHOISIT le candidat dans la liste indexée — il ne décide pas (AdaptiveLearning), ne priorise pas (Organizer). Le `match_type` encode la raison de déclenchement (weakness, exam, theme, etc.).

## Garde-fous
- `candidates` doit contenir exactement 1 item `status='winner'` et N items `status='eliminated'`.
- `match_type` est un enum strict 6 valeurs : `objective`, `weakness`, `exam`, `theme`, `previous_activity`, `teacher_assigned`.
- **BLOCKED** si `title` absent / `selected_item` absent / `candidates` vide / `primary_cta` absent.
- Ne jamais hardcoder le contenu pédagogique — tout vient de l'instance.
- `reason` : langage élève uniquement, jamais de raw data/scores exposés.

## QA à vérifier
1. Modifier `selected_item.label` → rendu change sans toucher au HTML (critère d'or).
2. `candidates:[]` → BLOCKED propre.
3. `title` absent → BLOCKED propre.
4. Clic enum_chip → chip actif change + panel note.
5. Responsive 375/768/1024 : pas de débordement.

## External refs / dependencies
- **GAB-212 AdaptiveRecommendation** : prend la DÉCISION adaptative en amont. GAB-221 consomme le signal, ne le calcule pas.
- **GAB-180 LevelTestRecoBridge** : sortie diagnostic contextuelle — différent de ContentMatch.
- **GAB-222 SmartSelectLevelFit** : étape suivante dans la chaîne pipeline (sélection du niveau).
- La chaîne complète : `221 ContentMatch → 222 LevelFit → 223 FormatChoice → (224 Fallback) → 225 ReasonCard`.

## Source
`INDEX-300-smartselect-GAB-221-225-PLAYABLE.html` (stage `data-tpl="221"`, section `.cm-card`).
