{
  "contract_version": "gab_030_contract_v1",
  "gab_id": "GAB-030",
  "canonical_name": "ErrorFallbackBlock",
  "module_owner": "EdTechPlayKit",
  "renderer_key": "text_cta",
  "required_fields": [
    "gab_id",
    "error_fallback_id",
    "error_title",
    "fallback_text",
    "primary_cta"
  ],
  "optional_fields": [
    "error_subtitle",
    "error_icon",
    "fallback_label",
    "retry_cta",
    "feedback_continue",
    "feedback_retry"
  ],
  "field_types": {
    "error_title": "string — titre court de l'erreur (ressource qui ne s'affiche pas)",
    "error_subtitle": "string — sous-titre rassurant affiché sous le titre",
    "error_icon": "string — emoji ou code icône (défaut : '🛟')",
    "fallback_label": "string — libellé de la zone de secours (défaut : 'Contenu de secours')",
    "fallback_text": "string — contenu textuel de substitution lisible par l'élève",
    "primary_cta": "object{label,action} — bouton principal 'continuer'",
    "retry_cta": "object{label,action} — bouton secondaire 'réessayer' (optionnel)",
    "feedback_continue": "string — message feedback affiché après clic 'continuer'",
    "feedback_retry": "string — message feedback affiché après clic 'réessayer'"
  },
  "constraints": [
    "error_title et fallback_text sont obligatoires : sans eux le bloc ne peut pas guider l'élève.",
    "primary_cta : bouton structurel (HTML), libellé et action viennent du JSON.",
    "retry_cta est optionnel : si absent, le bouton 'réessayer' n'est pas rendu.",
    "Le bloc indique une erreur NON bloquante : la session continue via le fallback textuel.",
    "feedback_continue et feedback_retry sont des messages inline (pas de navigation)."
  ],
  "blocked_conditions": [
    "error_title absent",
    "fallback_text absent",
    "primary_cta absent"
  ],
  "accessibility": [
    "keyboard_navigable",
    "focus_visible",
    "prefers_reduced_motion",
    "aria_live_feedback"
  ],
  "qa_cases": [
    { "case": "instance conforme", "expected": "rendu complet, titre + fallback + 2 boutons, 0 erreur" },
    { "case": "champ requis manquant (error_title)", "expected": "BLOCKED listant le champ" },
    { "case": "champ requis manquant (fallback_text)", "expected": "BLOCKED listant le champ" },
    { "case": "retry_cta absent", "expected": "seul le bouton primary_cta est rendu" },
    { "case": "clic continuer", "expected": "feedback_continue affiché en vert (mint)" },
    { "case": "clic réessayer", "expected": "feedback_retry affiché en or (gold)" },
    { "case": "instance externe injectée", "expected": "rendu change sans modifier le HTML" },
    { "case": "responsive 375/768/1024", "expected": "aucun débordement horizontal" }
  ],
  "traceability": {
    "derived_from_core_gab": "GAB-030",
    "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)."
  }
}
