# GAB-295 · OralLearningSelfReview — « Auto-évaluation orale non-jugeante »

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

## Pack (structure officielle par-GAB)
```
GAB-295/
  renderer.html            ← moteur auto-évaluation orale (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

GAB-295 est le dernier maillon de la **chaîne orale Module 21** :
`291 OralIntro → 292 SpeechPlan → 293 PracticeTimer → 294 JuryQuestion → 295 SelfReview`

Son rôle : permettre à l'élève de **se regarder sans se juger**. L'auto-évaluation commence par le ressenti émotionnel (avant les critères techniques), pour ne pas reproduire la posture « je me note comme un prof ».

## Champs requis (instance, à plat)
`gab_id` · `self_review_id` · `oral_attempt_ref` · `review_prompts[]` · `review_goal` · `next_action`

Optionnels : `title`, `subtitle`, `non_judgment_rule`, `reflection_privacy`, `primary_cta{label,action}`, `secondary_cta{label,action}`, `rubric_ref`, `save_policy`, `why_feeling_first`, `confidence_scale`, `recording_ref`, `source_metadata`.

## Ce qui vient du JSON vs HTML

- **JSON** : toutes les questions (`review_prompts`), leurs émojis et labels, le type (scale/text), le placeholder du champ libre, la règle de non-jugement, le `next_action`, la privacy, les libellés des deux boutons, la rubrique optionnelle.
- **HTML** : layout, styles DS V2, moteur de rendu, wire-up des boutons scale, validation BLOCKED.

## Moteur de prompts

`review_prompts` est un tableau polymorphe :
- `type: "scale"` → boutons cliquables avec émoji + label ; un seul actif à la fois par groupe.
- `type: "text"` → `<input>` avec placeholder.

La longueur de chaque `scale_options` est libre (4 ou 5 selon le prompt).

## Garde-fous (child_safety)

- **Non-jugement absolu** : aucune réponse n'est qualifiée de "bonne" ou "mauvaise" dans le rendu. Le feedback de confirmation est neutre et positif.
- **Privacy stricte** : `reflection_privacy` rappelle systématiquement que la réflexion est privée par défaut.
- **BLOCKED** si `review_prompts` absent/vide, `self_review_id` absent ou `oral_attempt_ref` absent.
- **next_action** = suggestion, jamais injonction. Ton bienveillant.

## QA à vérifier

1. Modifier `review_prompts[].question` → rendu change sans toucher au HTML (critère d'or).
2. `review_prompts:[]` → BLOCKED propre, pas d'affichage partiel.
3. `self_review_id` absent → BLOCKED.
4. Clic bouton scale → active le bouton, désactive les autres du groupe.
5. Prompt `type:"text"` → `<input>` avec placeholder correct.
6. CTA primaire → confirmation `panel.ok`, bouton désactivé.
7. CTA secondaire → affiche `rubric_ref` dans `panel.note`.
8. Instance externe via `ENGINE.init(ext)` → rendu change sans modifier le HTML.
9. Responsive 375/768/1024 → aucun débordement.

## Source

`INDEX-300-orallearning-GAB-291-295-PLAYABLE.html` (stage `data-tpl="295"`, section `.sr-*`).

## external_refs / dependencies

| Ref | GAB | Module | Rôle |
|-----|-----|--------|------|
| `oral_attempt_ref` | GAB-293 PracticeTimer | EdTechOralLearning | identifiant de la session d'entraînement précédente |
| Chaîne complète | GAB-291 à GAB-294 | EdTechOralLearning | contexte pédagogique amont requis pour que le SelfReview ait du sens |
