# GAB-202 · PlayEngineBlockStack — « Pile ordonnée blocs multi-modules »

**Archétype / renderer_key :** `text_cta` (cartographie) · **module :** EdTechPlayEngine
**Critère validé :** changer le JSON change la pile sans modifier le HTML. ✅ check.py 12/12.

## Pack (structure officielle par-GAB)
```
GAB-202/
  renderer.html            ← moteur pile de blocs (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
```

## Archétype

**PlayEngineBlockStack** : pile ordonnée de blocs provenant de modules différents (Story, Visual, Interactive, Exercise, Memory…). PlayEngine orchestre l'enchaînement sans posséder la logique pédagogique de chaque bloc — celle-ci reste sous la responsabilité du `module_owner` du bloc.

Chaque bloc porte un `status` (`completed` / `active` / `pending` / `error`). Un bloc en erreur affiche un message isolé et la session continue — fallback contrôlé, jamais silencieux.

## Champs requis (instance, à plat)
`gab_id` · `block_stack_id` · `blocks[]{num, label, module_type, module_label, ref, status}` · `primary_cta{label, action}`

Optionnels : `title`, `subtitle`, `doctrine_note`, `progress_label`, `progress_pct`, `renderer_key`, `_note_dev`.

## Ce qui vient du JSON vs HTML
- **JSON** : titre, sous-titre, doctrine, chaque bloc (label, module_type, ref, status, error_msg), progression, libellé du bouton CTA.
- **HTML** : structure des blocs, états visuels (completed/active/error/pending), barre de progression, bouton structurel, layout, BLOCKED.

## Garde-fous (child_safety)
- **Anti-erreur silencieuse** : un bloc `status:error` doit porter un `error_msg` explicite — jamais masquer.
- **Doctrine PlayEngine** : ce gabarit n'écrit jamais XP/badge/coins — délégué à PlayKit après complétion côté serveur.
- **BLOCKED** si `blocks` vide, `block_stack_id` absent, ou `primary_cta` absent.

## QA à vérifier
1. Modifier un `label` de bloc → rendu change sans toucher au HTML (critère d'or).
2. `blocks:[]` → BLOCKED propre.
3. Bloc `status:error` → affiché en coral dashed avec `error_msg`.
4. `ENGINE.init(ext)` avec instance externe → rendu piloté par ext.
5. Responsive 375/768/1024.

## external_refs / dependencies

Ce gabarit est conçu pour fonctionner dans une session composite PlayEngine. Il référence des blocs appartenant à d'autres modules (`module_owner`) mais **n'instancie pas** ces modules :

| Famille ref | module_owner cible (LOT externe) |
|---|---|
| `story/` | EdTechStoryLearning |
| `visual/` | EdTechVisualLearning |
| `interactive/` | EdTechInteractiveLearning |
| `memory/` | EdTechMemoryLearning |

Les refs sont des identifiants de contenu — leur résolution vers un composant React est déléguée au bridge GAB-204 (PlayEngineProviderBridge, même LOT).

## Source
`INDEX-300-playengine-composite-GAB-201-205-PLAYABLE.html` (stage `data-tpl="202"`, styles `.bs-*`).
