{
  "contract_version": "gab_213_contract_v1",
  "gab_id": "GAB-213",
  "canonical_name": "AdaptiveLearningRemediationPath",
  "module_owner": "EdTechAdaptiveLearning",
  "renderer_key": "text_cta",
  "required_fields": [
    "gab_id",
    "remediation_path_id",
    "title",
    "summary",
    "items",
    "primary_cta"
  ],
  "optional_fields": [
    "reason",
    "depth",
    "estimated_duration",
    "steps_count_label",
    "secondary_cta",
    "anti_stigma_message",
    "accessibility",
    "child_safety"
  ],
  "field_types": {
    "gab_id": "string — valeur fixe 'GAB-213'",
    "remediation_path_id": "string — identifiant unique du parcours (ex: 'rp-justification-pythagore-brevet')",
    "title": "string — titre court du parcours, affiché en hero et dans la card",
    "summary": "string — sous-titre descriptif (nb étapes, durée estimée, ton non punitif)",
    "reason": "string — explication transparente en langage élève pourquoi un parcours structuré (slot canonique AdaptiveLearning)",
    "depth": "enum['light','standard','deep'] — profondeur du parcours (défaut: 'standard')",
    "estimated_duration": "string — durée totale affichée (ex: '~ 12 min')",
    "steps_count_label": "string — libellé du compteur d'étapes (ex: '4 modules')",
    "items": "array<{step:number, title:string, description:string, module_type:enum['visual','exercise','leveltest','audio','memory'], module_label:string, duration:string}> — séquence ordonnée des étapes, min 2, max 6",
    "primary_cta": "object{label:string, action:string} — CTA principal (lancer le parcours)",
    "secondary_cta": "object{label:string, action:string} — CTA alternatif optionnel (ex: voir seulement la fiche)",
    "anti_stigma_message": "string — message non punitif affiché avant les CTAs",
    "accessibility": "object{keyboard_navigable:boolean, focus_visible:boolean, prefers_reduced_motion:boolean, aria_labels:string}",
    "child_safety": "object{anti_stigma:boolean, no_definitive_judgment:boolean, non_punitive:boolean, skip_allowed:boolean}"
  },
  "constraints": [
    "items : min 2 étapes, max 6 étapes — au-delà de 6 étapes utiliser PathMap (module 11).",
    "items[*].module_type : enum strict — visual, exercise, leveltest, audio, memory.",
    "primary_cta.label : libellé structurel du bouton HTML, vient exclusivement du JSON.",
    "reason : en langage élève — pas de jargon technique, pas de score brut exposé.",
    "depth : si absent, défaut 'standard' côté renderer.",
    "anti_stigma_message : ton non punitif obligatoire — ce gabarit ne sanctionne pas."
  ],
  "blocked_conditions": [
    "title absent (BLOCKED)",
    "summary absent (BLOCKED)",
    "items vides ou absents (BLOCKED)",
    "primary_cta absent (BLOCKED)"
  ],
  "accessibility": [
    "keyboard_navigable",
    "focus_visible",
    "prefers_reduced_motion",
    "aria_labels sur steps et CTAs"
  ],
  "qa_cases": [
    { "case": "instance conforme", "expected": "rendu complet : title, steps numérotés, stats, anti-stigma, CTAs — 0 erreur" },
    { "case": "champ requis manquant (ex: items vides)", "expected": "BLOCKED listant le champ manquant" },
    { "case": "instance externe injectée via init(ext)", "expected": "le rendu change sans modifier le HTML" },
    { "case": "items à 2 étapes (minimum)", "expected": "rendu correct avec 2 steps, ligne de connexion verticale visible" },
    { "case": "items à 6 étapes (maximum)", "expected": "rendu correct, pas de débordement" },
    { "case": "secondary_cta absent", "expected": "bouton secondaire masqué (display:none)" },
    { "case": "responsive 375/768/1024", "expected": "aucun débordement horizontal, stats en colonne sur mobile" }
  ],
  "traceability": {
    "derived_from_core_gab": "GAB-213",
    "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 HTML : INDEX-300-adaptivelearning-GAB-211-215-PLAYABLE.html, stage data-tpl='213'."
  }
}
