# GAB-167 · AudioListenAndRepeat — « Écouter et répéter »

**Archétype / renderer_key :** `media_viewer` (cartographie) · **module :** EdTechAudioLearning
**renderer_key à concevoir (pas de moteur kit)** : `media_viewer` n'a pas de moteur kit de référence dans la bibliothèque actuelle ; le renderer est dérivé directement de l'écran source (`data-tpl="167"`, handlers `lrListen`/`lrRecord`/`lrStopListen`/`lrStopRec` du fichier `INDEX-300-audiolearning-GAB-166-170-PLAYABLE.html`).

## Pack (structure officielle par-GAB)
```
GAB-167/
  renderer.html            ← moteur écouter-répéter (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` · `listen_repeat_id` · `title` · `instruction` · `phrase`

Optionnels : `tts_lang`, `tts_rate`, `btn_listen_label`, `btn_record_label`, `status_initial`, `status_listening`, `status_after_listen`, `status_recording`, `status_done`, `record_auto_stop_ms`, `rgpd_notice`, `accessibility`, `child_safety`.

## Ce qui vient du JSON vs HTML
- **JSON** : la phrase à reproduire, l'instruction, les libellés des boutons, les textes de statut (initial/listening/after_listen/recording/done), la mention RGPD, la durée d'enregistrement auto-stop, les paramètres TTS (lang, rate).
- **HTML** : layout carte, boutons structurels Écouter/Enregistrer, zone de statut, bannière RGPD, moteur TTS (`SpeechSynthesisUtterance`), logique enregistrement local simulé.

## Archétype pédagogique
Entraîner la prononciation orale sur une phrase courte. L'apprenant :
1. Écoute la phrase (TTS, bouton 1)
2. Enregistre sa propre répétition (local uniquement, bouton 2)

Différent de GAB-169 (feedback de prononciation analytique) et de GAB-170 (dictée écrite).

## Garde-fous (child_safety)
- **Enregistrement 100% local** : `recording_local_only: true` — jamais transmis aux serveurs. La bannière RGPD est toujours visible.
- **BLOCKED** si `phrase`, `instruction` ou `title` est absent.
- **Anti-invention** : aucun contenu pédagogique hardcodé dans le HTML. La phrase vient exclusivement de l'instance.
- **TTS optionnel** : si `SpeechSynthesisUtterance` indisponible (navigateur sans TTS), le bouton bascule en mode dégradé (timer 2s) sans blocage.

## QA à vérifier
1. Modifier `phrase` dans l'instance → rendu change sans toucher au HTML (critère d'or).
2. `phrase` absent → BLOCKED propre.
3. Clic Écouter → bouton violet actif + statut `status_listening`.
4. Fin TTS → statut `status_after_listen` (mint/done).
5. Clic Enregistrer → bouton coral actif + auto-stop après `record_auto_stop_ms` ms + statut `status_done`.
6. Bannière RGPD visible avec texte `rgpd_notice`.
7. Responsive 375/768/1024.

## Source
`INDEX-300-audiolearning-GAB-166-170-PLAYABLE.html` (stage `data-tpl="167"`, handlers `lrListen`, `lrRecord`, `lrStopListen`, `lrStopRec`, constante `LR_PHRASE`).

## external_refs / dependencies
- **GAB-169 (AudioPronunciationFeedback)** : si feedback analytique de prononciation souhaité après l'enregistrement, déléguer à GAB-169.
- **GAB-170 (DictationPrompt)** : si l'objectif est une dictée écrite (pas orale), utiliser GAB-170 à la place.
- **GAB-166 (AudioIntroPlayer)** : si l'objectif est simplement d'écouter un audio long sans répétition, utiliser GAB-166.
