{
  "contract_version": "gab_141_contract_v1",
  "gab_id": "GAB-141",
  "canonical_name": "InteractiveCauseEffectLab",
  "module_owner": "EdTechInteractiveLearning",
  "renderer_key": "text_cta",
  "required_fields": [
    "gab_id",
    "cause_effect_id",
    "instruction",
    "items",
    "result"
  ],
  "optional_fields": [
    "title",
    "accessibility"
  ],
  "field_types": {
    "cause_effect_id": "string — identifiant unique de l'instance lab",
    "instruction": "string — consigne affichée en haut du lab",
    "items": "array<{id:string, icon:string, label:string, weight:integer(1..100)}> — liste des causes activables",
    "result": "object{meter_label:string, thresholds:array<{min:integer, max:integer, text:string}>} — configuration du compteur d'effet",
    "accessibility": "object{keyboard_navigable:boolean, focus_visible:boolean, prefers_reduced_motion:boolean}"
  },
  "constraints": [
    "items doit contenir au moins 1 élément.",
    "La somme des weights peut dépasser 100 — le renderer plafonne à 100%.",
    "Chaque threshold doit couvrir une plage [min, max] sans trou (le renderer prend le dernier match).",
    "Le threshold avec min=0 et max=0 représente l'état repos (aucune cause activée)."
  ],
  "blocked_conditions": [
    "gab_id absent",
    "instruction absente",
    "items vides",
    "result.thresholds absent"
  ],
  "accessibility": [
    "keyboard_navigable",
    "focus_visible",
    "prefers_reduced_motion",
    "role=checkbox sur chaque cause avec aria-checked"
  ],
  "qa_cases": [
    { "case": "instance conforme", "expected": "rendu complet, 0 erreur, toutes les causes affichées" },
    { "case": "champ requis manquant (instruction)", "expected": "BLOCKED listant le champ" },
    { "case": "items vides", "expected": "BLOCKED items vides" },
    { "case": "activation de toutes les causes", "expected": "compteur = somme des weights (plafonné 100%), dernier seuil affiché" },
    { "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" },
    { "case": "navigation clavier (Tab + Espace)", "expected": "toggle cause activable au clavier" }
  ],
  "traceability": {
    "derived_from_core_gab": "GAB-141",
    "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). Extrait de INDEX-300-interactivelearning-GAB-141-145-PLAYABLE.html, stage data-tpl='141', handlers celToggle/celUpdate."
  }
}
