{
  "contract_version": "gab_211_contract_v1",
  "gab_id": "GAB-211",
  "canonical_name": "AdaptiveLearningEntrySignal",
  "module_owner": "EdTechAdaptiveLearning",
  "renderer_key": "text_cta",
  "required_fields": [
    "gab_id",
    "entry_signal_id",
    "signal_type",
    "title",
    "summary",
    "reason"
  ],
  "optional_fields": [
    "source_module",
    "source_description",
    "confidence_score",
    "privacy_notice",
    "primary_cta"
  ],
  "field_types": {
    "signal_type": "enum['mistake','success','weakness','pace','goal','level_test']",
    "title": "string — intitulé du signal en langage élève",
    "summary": "string — contexte court (matière, niveau, notion)",
    "reason": "string — explication transparente du signal en langage élève (obligatoire, jamais opaque)",
    "source_module": "string — nom du module source (ex: 'EdTechExerciseLearning', 'EdTechLevelTest')",
    "source_description": "string — description courte de la source et du pattern détecté",
    "confidence_score": "number(0..100) — score interne, NE PAS afficher à l'élève",
    "privacy_notice": "string — mention RGPD/pédagogique sur l'usage des signaux",
    "primary_cta": "object{label:string, action:string}"
  },
  "constraints": [
    "reason est obligatoire : chaque signal DOIT exposer sa raison en langage élève (doctrine transparence adaptive).",
    "confidence_score est interne : ne jamais l'afficher directement à l'élève dans l'interface.",
    "signal_type doit appartenir à l'enum strict défini — pas de valeur libre.",
    "Un signal ne constitue pas un diagnostic médical ou psychologique — l'affichage doit le refléter.",
    "primary_cta.label vient du JSON, jamais hardcodé dans le HTML."
  ],
  "blocked_conditions": [
    "gab_id absent (BLOCKED)",
    "entry_signal_id absent (BLOCKED)",
    "signal_type absent (BLOCKED)",
    "title absent (BLOCKED)",
    "summary absent (BLOCKED)",
    "reason absent (BLOCKED)"
  ],
  "accessibility": [
    "keyboard_navigable",
    "focus_visible",
    "prefers_reduced_motion",
    "aria_labels_cta"
  ],
  "qa_cases": [
    { "case": "instance conforme signal_type=mistake", "expected": "rendu complet, titre/raison/source affichés, 0 erreur" },
    { "case": "champ requis manquant (ex: reason)", "expected": "BLOCKED listant le champ manquant" },
    { "case": "confidence_score absent", "expected": "section confidence masquée proprement (hidden)" },
    { "case": "privacy_notice absent", "expected": "disclaimer masqué sans erreur JS" },
    { "case": "instance externe injectée via ENGINE.init(ext)", "expected": "rendu change sans modifier le HTML" },
    { "case": "responsive 375/768/1024", "expected": "aucun débordement horizontal" },
    { "case": "signal_type=level_test", "expected": "badge signal_type affiché, icône source correcte" }
  ],
  "traceability": {
    "derived_from_core_gab": "GAB-211",
    "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). Contenu extrait du stage data-tpl='211' + JS ES_SIGNALS de l'INDEX-300-adaptivelearning-GAB-211-215-PLAYABLE.html."
  }
}
