{
  "contract_version": "gab_140_contract_v1",
  "gab_id": "GAB-140",
  "canonical_name": "InteractiveSliderExperiment",
  "module_owner": "EdTechInteractiveLearning",
  "renderer_key": "text_cta",
  "required_fields": [
    "gab_id",
    "experiment_id",
    "question",
    "variable",
    "output"
  ],
  "optional_fields": [
    "title",
    "instruction",
    "primary_cta"
  ],
  "field_types": {
    "experiment_id": "string — identifiant unique de l'expérience",
    "question": "string — question pédagogique affichée au-dessus du curseur",
    "variable": "object{label,unit,min,max,default} — paramètre contrôlé par le curseur",
    "output": "object{label,unit,formula_type} — grandeur observée calculée en temps réel",
    "primary_cta": "object{label,action} — bouton structurel (libellé venant du JSON)",
    "formula_type": "enum['inverse_square','linear','quadratic'] — loi appliquée par le moteur"
  },
  "constraints": [
    "variable.min < variable.max (slider bounds valides).",
    "variable.default doit être dans [variable.min, variable.max].",
    "formula_type 'inverse_square' : intensité = round(100 / (d*d)), normalisé max 100% pour d=1.",
    "primary_cta : bouton structurel (HTML), libellé venant du JSON.",
    "Aucun contenu pédagogique (question, unités, loi) ne doit être en dur dans le renderer."
  ],
  "blocked_conditions": [
    "question absent",
    "variable absent",
    "output absent"
  ],
  "accessibility": [
    "keyboard_navigable",
    "focus_visible",
    "prefers_reduced_motion",
    "aria_labels_slider",
    "fallback_text"
  ],
  "qa_cases": [
    { "case": "instance conforme", "expected": "rendu complet, curseur fonctionnel, 0 erreur" },
    { "case": "champ requis manquant (question absent)", "expected": "BLOCKED listant le champ" },
    { "case": "champ requis manquant (variable absent)", "expected": "BLOCKED listant le champ" },
    { "case": "déplacement curseur vers d=1", "expected": "intensité affichée 100%" },
    { "case": "déplacement curseur vers d=10", "expected": "intensité affichée 1%" },
    { "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-140",
    "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)."
  }
}
