{
  "contract_version": "gab_049_contract_v1",
  "gab_id": "GAB-049",
  "canonical_name": "StoryChoiceBasic",
  "module_owner": "EdTechStoryLearning",
  "renderer_key": "text_cta",
  "required_fields": [
    "gab_id",
    "choice_id",
    "title",
    "choices"
  ],
  "optional_fields": [
    "subtitle",
    "_note_dev",
    "renderer_key"
  ],
  "field_types": {
    "gab_id": "string — doit être 'GAB-049'",
    "choice_id": "string — identifiant unique de l'instance (slug)",
    "title": "string — question principale affichée en gros",
    "subtitle": "string — sous-titre/guide optionnel sous la question",
    "choices": "array<{letter:string, text:string, correct:boolean, feedback:string}> — minimum 2 entrées, exactement 1 correct:true"
  },
  "constraints": [
    "choices doit contenir au minimum 2 options.",
    "Exactement 1 option avec correct:true (la réponse juste). Les autres ont correct:false.",
    "Chaque choice doit avoir : letter (A/B/…), text (libellé affiché), correct (boolean), feedback (texte affiché après sélection).",
    "title est la question narrative posée à l'élève — ne pas la générer, extraire de la source.",
    "feedback de l'option correcte commence conventionnellement par ✓, le feedback des mauvaises réponses par ✕."
  ],
  "blocked_conditions": [
    "gab_id absent",
    "title absent",
    "choices invalides — minimum 2 requis",
    "aucune option correcte définie dans choices"
  ],
  "accessibility": [
    "keyboard_navigable",
    "focus_visible",
    "prefers_reduced_motion",
    "aria-label sur chaque bouton option",
    "bouton reset pour re-tenter"
  ],
  "qa_cases": [
    { "case": "instance conforme", "expected": "rendu complet, question + 2 options cliquables, feedback après clic, 0 erreur" },
    { "case": "champ requis title manquant", "expected": "BLOCKED affiché proprement" },
    { "case": "choices vide ou < 2 éléments", "expected": "BLOCKED affiché proprement" },
    { "case": "aucun correct:true dans choices", "expected": "BLOCKED affiché proprement" },
    { "case": "clic option correcte (A)", "expected": "border mint, feedback ✓ correct affiché, options non-clickables" },
    { "case": "clic option incorrecte (B)", "expected": "border coral, option correcte surlignée mint aussi, feedback ✕ affiché" },
    { "case": "bouton reset", "expected": "état initial restauré, options cliquables à nouveau" },
    { "case": "instance externe injectée", "expected": "le rendu change sans modifier le HTML" },
    { "case": "responsive 375/768/1024", "expected": "aucun débordement horizontal" }
  ],
  "traceability": {
    "derived_from_core_gab": "GAB-049",
    "note": "Ce schema VALIDE l'instance. Le contrat pédagogique complet (input_contract/validation_logic/feedback_scoring_logic) vit dans le CORE-GAB officiel, pas ici (évite la duplication). Source : INDEX-300-storylearning-GAB-045-049-PLAYABLE.html, stage data-tpl='49', handler choicePick()."
  }
}
