{
  "contract_version": "gab_197_contract_v1",
  "gab_id": "GAB-197",
  "canonical_name": "PathMapAlternativeRoute",
  "module_owner": "EdTechPathMap",
  "renderer_key": "text_cta",
  "required_fields": [
    "gab_id",
    "route_selector_id",
    "title",
    "summary",
    "routes",
    "primary_cta"
  ],
  "optional_fields": [
    "intro_text"
  ],
  "field_types": {
    "route_selector_id": "string — identifiant unique de ce sélecteur de routes",
    "title": "string — titre affiché dans le header de la card",
    "summary": "string — sous-titre court (nb routes disponibles, invite)",
    "intro_text": "string — texte de contexte pédagogique affiché avant les routes",
    "routes": "array<{route_id, type, tag_label, title, description, duration_label, difficulty_label, nodes_label, cta_label}> — min 2, max 3 éléments",
    "routes[].route_id": "string — identifiant court de la route (ex: 'g', 'f', 'c')",
    "routes[].type": "enum['guided','fast','challenge'] — détermine le style coloré de la card",
    "routes[].tag_label": "string — libellé du badge de type (ex: '🌱 Guidée')",
    "routes[].title": "string — titre de la route",
    "routes[].description": "string — description pédagogique courte",
    "routes[].duration_label": "string — durée estimée (ex: '⏱ ~ 20 min')",
    "routes[].difficulty_label": "string — niveau de difficulté (ex: '⭐ Facile')",
    "routes[].nodes_label": "string — nombre de nœuds (ex: '📖 5 nœuds')",
    "routes[].cta_label": "string — libellé du bouton CTA quand cette route est sélectionnée",
    "primary_cta": "object{label, label_selected, action} — bouton de confirmation"
  },
  "constraints": [
    "routes doit contenir entre 2 et 3 éléments — un seul choix réel = utiliser GAB-194.",
    "Chaque route doit avoir route_id unique dans le tableau.",
    "routes[].type doit être l'un de : 'guided', 'fast', 'challenge'.",
    "primary_cta.label est affiché tant qu'aucune route n'est sélectionnée (bouton désactivé).",
    "primary_cta.label_selected est affiché dès qu'une route est sélectionnée.",
    "Ne jamais proposer de routes menant à un prérequis non respecté."
  ],
  "blocked_conditions": [
    "routes absent ou vide",
    "route_selector_id absent",
    "primary_cta absent"
  ],
  "accessibility": [
    "keyboard_navigable",
    "focus_visible",
    "prefers_reduced_motion",
    "aria-pressed sur les boutons route sélectionnés"
  ],
  "qa_cases": [
    { "case": "instance conforme 3 routes", "expected": "rendu complet, 3 cards, bouton désactivé puis activé à la sélection, 0 erreur" },
    { "case": "champ requis manquant (routes absent)", "expected": "BLOCKED listé dans le panel d'erreur" },
    { "case": "route_selector_id absent", "expected": "BLOCKED listé dans le panel d'erreur" },
    { "case": "primary_cta absent", "expected": "BLOCKED listé dans le panel d'erreur" },
    { "case": "sélection d'une route", "expected": "CTA activé, libellé = cta_label de la route sélectionnée" },
    { "case": "instance externe injectée via init(ext)", "expected": "le rendu change sans modifier le HTML" },
    { "case": "responsive 375/768/1024", "expected": "aucun débordement horizontal" }
  ],
  "traceability": {
    "derived_from_core_gab": "GAB-197",
    "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)."
  }
}
