{
  "contract_version": "gab_174_contract_v1",
  "gab_id": "GAB-174",
  "canonical_name": "AudioSpeedControl",
  "module_owner": "EdTechAudioLearning",
  "renderer_key": "media_viewer",
  "required_fields": [
    "gab_id",
    "speed_control_id",
    "title",
    "items",
    "preview_sentence",
    "default_rate"
  ],
  "optional_fields": [
    "recommendation",
    "accessibility",
    "child_safety"
  ],
  "field_types": {
    "speed_control_id": "string — identifiant unique de l'instance",
    "title": "string — libellé affiché en en-tête du composant",
    "preview_sentence": "string — phrase lue lors de l'aperçu (SpeechSynthesis)",
    "default_rate": "number(0.5..2.0) — vitesse active à l'initialisation",
    "items": "array<{id:string, icon:string, label:string, rate:number, display_rate:string, tip:string, is_default:boolean}> — exactement les options de vitesse",
    "recommendation": "string — texte contextuel affiché sous le sélecteur (optionnel)",
    "accessibility": "object{preview_btn_label, grid_role, grid_aria_label}",
    "child_safety": "object{speed_min:number, speed_max:number, note:string}"
  },
  "constraints": [
    "items doit contenir au moins 2 entrées.",
    "Exactement un item doit avoir is_default:true.",
    "Chaque item.rate doit être dans [0.5, 2.0].",
    "preview_sentence ne peut pas être vide.",
    "default_rate doit correspondre au rate d'un item is_default:true."
  ],
  "blocked_conditions": [
    "items absent ou vide",
    "preview_sentence absent",
    "speed_control_id absent"
  ],
  "accessibility": [
    "keyboard_navigable",
    "focus_visible",
    "prefers_reduced_motion",
    "aria_radiogroup_sur_la_grille",
    "preview_btn_label_lisible"
  ],
  "qa_cases": [
    { "case": "instance conforme", "expected": "rendu complet, sélecteur 3 vitesses, aperçu actif" },
    { "case": "items absent", "expected": "BLOCKED listant items absent" },
    { "case": "preview_sentence absent", "expected": "BLOCKED listant preview_sentence absent" },
    { "case": "speed_control_id absent", "expected": "BLOCKED listant speed_control_id absent" },
    { "case": "clic vitesse Lent", "expected": "item 0.7× passe active, label aperçu = 0.7×" },
    { "case": "clic vitesse Rapide", "expected": "item 1.4× passe active, label aperçu = 1.4×" },
    { "case": "bouton aperçu", "expected": "SpeechSynthesis joue preview_sentence au rate actif" },
    { "case": "instance externe injectée via init(ext)", "expected": "le rendu change sans modifier le HTML" },
    { "case": "responsive 375/768/1024", "expected": "grille affichée sans débordement horizontal" }
  ],
  "traceability": {
    "derived_from_core_gab": "GAB-174",
    "note": "Extrait du stage data-tpl=174 (INDEX-300-audiolearning-GAB-171-175-PLAYABLE.html). Composant transversal embarquable dans GAB-166, GAB-168, GAB-170, GAB-171. renderer_key 'media_viewer' à concevoir (pas de moteur kit de référence) — renderer dérivé de l'écran source lui-même."
  }
}
