{
  "contract_version": "gab_208_contract_v1",
  "gab_id": "GAB-208",
  "canonical_name": "PlayEngineRemediationInsert",
  "module_owner": "EdTechPlayEngine",
  "renderer_key": "text_cta",
  "required_fields": [
    "gab_id",
    "remediation_insert_id",
    "title",
    "items",
    "primary_cta"
  ],
  "optional_fields": [
    "summary",
    "variant",
    "variant_note",
    "trigger_label",
    "trigger_text",
    "back_promise",
    "skip_cta"
  ],
  "field_types": {
    "remediation_insert_id": "string — identifiant unique de cet insert de remédiation",
    "title": "string — libellé du titre affiché dans le bottom_sheet",
    "summary": "string — durée estimée + note de reprise (ex: '~ 2 min · puis on reprend la session')",
    "variant": "enum['bottom_sheet'] — seul variant supporté actuellement",
    "variant_note": "string — description contextuelle du variant",
    "trigger_label": "string — libellé du bandeau trigger (ex: 'Trigger détecté · fiable')",
    "trigger_text": "string — texte explicatif de l'erreur détectée par PlayEngine",
    "items": "array<{num:integer, text:string, mod_type:enum['visual','memory','story','interactive','exercise','audio'], mod_label:string}>",
    "back_promise": "string — texte confirmant le retour à l'étape d'origine après les micro-actions",
    "primary_cta": "object{label:string, action:string}",
    "skip_cta": "object{label:string, action:string}"
  },
  "constraints": [
    "items doit contenir au moins 1 entrée et au plus 3 (micro-actions ciblées max).",
    "primary_cta.label : libellé structurel visible, vient du JSON.",
    "variant 'bottom_sheet' : surgit IN-SESSION, PlayEngine préserve l'état du module.",
    "Ne pas utiliser ce gabarit pour une remédiation longue ou qui casse l'état module (→ GAB-198 PathMapReviewLoop)."
  ],
  "blocked_conditions": [
    "title absent",
    "items vides",
    "primary_cta absent"
  ],
  "accessibility": [
    "keyboard_navigable",
    "focus_visible",
    "prefers_reduced_motion",
    "aria_hidden_decorative_icons"
  ],
  "qa_cases": [
    { "case": "instance conforme", "expected": "rendu complet, titre, trigger, items, promesse de retour, CTAs — 0 erreur" },
    { "case": "title absent", "expected": "BLOCKED affiché dans le panel, rendu interrompu" },
    { "case": "items vides ([])", "expected": "BLOCKED affiché dans le panel" },
    { "case": "primary_cta absent", "expected": "BLOCKED affiché dans le panel" },
    { "case": "skip_cta absent (optionnel)", "expected": "bouton skip masqué, rendu intact" },
    { "case": "instance externe injectée via ENGINE.init(obj)", "expected": "rendu change sans modifier le HTML" },
    { "case": "responsive 375/768/1024", "expected": "aucun débordement horizontal, CTAs en colonne sur mobile" }
  ],
  "traceability": {
    "derived_from_core_gab": "GAB-208",
    "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). Distinction doctrinaire : GAB-208 vit IN-SESSION (PlayEngine garde l'état) — GAB-198 PathMapReviewLoop vit DANS la carte parcours."
  }
}
