{
  "contract_version": "gab_116_contract_v1",
  "gab_id": "GAB-116",
  "canonical_name": "ExerciseQuestionCard",
  "module_owner": "EdTechExerciseLearning",
  "renderer_key": "text_cta",
  "required_fields": [
    "gab_id",
    "exercise_card_id",
    "instruction",
    "question"
  ],
  "optional_fields": [
    "title",
    "illustration",
    "primary_cta",
    "child_safety"
  ],
  "field_types": {
    "exercise_card_id": "string — identifiant unique de la carte exercice",
    "instruction": "string — libellé de la consigne (ex: '📋 Consigne')",
    "question": "string — texte complet de la question posée à l'élève",
    "illustration": "object{src,alt} — image optionnelle illustrant la question",
    "primary_cta": "object{label,action} — bouton d'action principal"
  },
  "constraints": [
    "instruction et question obligatoires : sans eux aucun énoncé ne peut être affiché.",
    "Ce gabarit est un CONTENEUR générique : il pose l'énoncé uniquement. Le moteur de réponse est fourni par GAB-117 à GAB-120.",
    "primary_cta.label vient du JSON, jamais hardcodé dans le HTML.",
    "illustration optionnelle : si absente, la zone n'est pas affichée."
  ],
  "blocked_conditions": [
    "instruction absent (BLOCKED)",
    "question absent (BLOCKED)"
  ],
  "accessibility": [
    "keyboard_navigable",
    "focus_visible",
    "prefers_reduced_motion",
    "alt_text_on_illustration"
  ],
  "qa_cases": [
    { "case": "instance conforme", "expected": "rendu complet — instruction + question affichées, bouton CTA visible" },
    { "case": "instruction absente", "expected": "BLOCKED listant le champ manquant" },
    { "case": "question absente", "expected": "BLOCKED listant le champ manquant" },
    { "case": "illustration absente", "expected": "zone illustration non affichée, rendu sans erreur" },
    { "case": "instance externe injectée via init(ext)", "expected": "rendu change sans modifier le HTML" },
    { "case": "responsive 375/768/1024", "expected": "aucun débordement horizontal" }
  ],
  "traceability": {
    "derived_from_core_gab": "GAB-116",
    "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)."
  },
  "external_refs": {
    "dependencies": [
      "GAB-117 (ExerciseMCQSingle) — consommateur du conteneur pour QCM réponse unique",
      "GAB-118 (ExerciseMCQMultiple) — consommateur pour QCM réponses multiples",
      "GAB-119 (ExerciseTrueFalse) — consommateur pour Vrai/Faux",
      "GAB-120 (ExerciseShortAnswer) — consommateur pour réponse courte"
    ]
  }
}
