{
  "contract_version": "gab_132_contract_v1",
  "gab_id": "GAB-132",
  "canonical_name": "ExerciseExamModeQuestion",
  "module_owner": "EdTechExerciseLearning",
  "renderer_key": "text_cta",
  "required_fields": [
    "gab_id",
    "exercise_id",
    "title",
    "question",
    "attendus"
  ],
  "optional_fields": [
    "consigne_label",
    "bareme",
    "placeholder",
    "min_length",
    "feedback_too_short",
    "feedback_submitted",
    "feedback_draft",
    "cta_draft_label",
    "cta_submit_label"
  ],
  "field_types": {
    "exercise_id": "string — identifiant unique de cet exercice",
    "title": "string — affiché dans le header sombre de la carte examen",
    "consigne_label": "string — label de durée conseillée affiché au-dessus de la question",
    "question": "string — énoncé complet de la question",
    "bareme": "string — ex. '/ 5 pts', affiché en badge doré dans le header",
    "attendus": "array<string> — liste des critères de réussite pour la note maximale",
    "placeholder": "string — texte indicatif dans la zone de saisie",
    "min_length": "number — seuil minimal en caractères avant soumission valide",
    "feedback_too_short": "string — message si réponse trop courte ; {length} interpolable",
    "feedback_submitted": "string — message après soumission valide ; {length} interpolable",
    "feedback_draft": "string — message après sauvegarde brouillon",
    "cta_draft_label": "string — libellé bouton brouillon",
    "cta_submit_label": "string — libellé bouton rendre"
  },
  "constraints": [
    "attendus doit contenir au moins 1 entrée.",
    "min_length si fourni doit être un entier > 0.",
    "bareme : chaîne libre, jamais une note calculée automatiquement.",
    "feedback_submitted peut contenir {length} — interpolé côté moteur avec le nombre de caractères saisis."
  ],
  "blocked_conditions": [
    "question absent (BLOCKED)",
    "attendus absent ou vide (BLOCKED)",
    "exercise_id absent (BLOCKED)"
  ],
  "accessibility": [
    "keyboard_navigable",
    "focus_visible",
    "prefers_reduced_motion",
    "textarea_labelled",
    "aria_live_feedback"
  ],
  "qa_cases": [
    { "case": "instance conforme", "expected": "rendu complet, header, question, attendus, textarea, 2 boutons" },
    { "case": "champ requis manquant (question)", "expected": "BLOCKED listé dans le moteur" },
    { "case": "attendus vide []", "expected": "BLOCKED — section attendus non rendue" },
    { "case": "soumission réponse < min_length", "expected": "feedback_too_short affiché en gold" },
    { "case": "soumission réponse >= min_length", "expected": "feedback_submitted affiché en mint avec {length} interpolé" },
    { "case": "clic brouillon", "expected": "feedback_draft affiché en sky" },
    { "case": "instance externe injectée via ENGINE.init(ext)", "expected": "rendu change sans modifier le HTML" },
    { "case": "responsive 375/768/1024", "expected": "aucun débordement horizontal, textarea conserve sa hauteur" }
  ],
  "traceability": {
    "derived_from_core_gab": "GAB-132",
    "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)."
  }
}
