# GAB-209 · PlayEngineSessionQualityGuard — « Garde qualité anti-fake session »

**Archétype / renderer_key :** `text_cta` (cartographie) · **module :** EdTechPlayEngine
**Critère validé :** changer le JSON change l'affichage des scénarios/checks/verdict sans modifier le HTML. check.py 12/12.

## Pack (structure officielle par-GAB)
```
GAB-209/
  renderer.html            ← moteur quality guard (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` · `session_quality_guard_id` · `title` · `subtitle` · `scenarios[]{key,label,checks[]{title,detail,status},verdict{status,heading,text}}` · `primary_cta{label,action}`

Optionnels : `icon`, `simulator_label`, `checks_section_label`, `log_note{icon,text}`, `secondary_cta{label,action}`.

## Ce qui vient du JSON vs HTML
- **JSON** : icône shield, titre, sous-titre, libellés boutons scénarios, tous les checks (title/detail/status), les verdicts (heading/text/status), la log note QA, libellés des CTAs.
- **HTML** : structure card, classes CSS de couleur par status (pass/fail/warn), layout boutons, rendu moteur.

## Comportement du moteur
- Au chargement, le premier scénario de `scenarios[]` est rendu par défaut.
- Clic sur un bouton scénario → re-rendu dynamique checks + verdict.
- Chaque check reçoit la classe CSS `pass`/`fail`/`warn` depuis `status` du JSON.
- Le verdict reçoit la classe `pass` si `verdict.status === 'pass'`, sinon état fail (rouge).

## Garde-fous (child_safety / anti-invention)
- **BLOCKED** si `title` absent, `scenarios` vide ou absent, `primary_cta` absent.
- Aucun texte pédagogique en dur dans le HTML — tout provient de l'instance.
- Status `pass`/`fail`/`warn` pilotent les couleurs CSS via classes, jamais des inline styles.
- Le rendu est reproductible : même JSON = même affichage, quelle que soit la session.

## Scénarios de l'instance exemple
| key | description | résultat |
|---|---|---|
| `good` | 5/5 checks pass | verdict vert (✓ Session valide) |
| `broken` | 2 refs manquantes côté DB | verdict rouge (⚠ Session bloquée) |
| `fake` | 0 objectif pédagogique | verdict rouge (⚠ Session "fake" détectée) |

## QA à vérifier
1. Modifier un `title`/`detail` de check → rendu change sans toucher au HTML.
2. `scenarios:[]` → BLOCKED propre avec message lisible.
3. Switcher entre les 3 scénarios → checks et verdict se mettent à jour dynamiquement.
4. `primary_cta` absent → BLOCKED.
5. Responsive 375/768/1024 — aucun débordement.

## Source
`INDEX-300-playengine-composite-GAB-206-210-PLAYABLE.html` (stage `data-tpl="209"`, handlers `qgScenario`/`qgRender`, const `QG_SCENARIOS`).
