{
  "contract_version": "gab_209_contract_v1",
  "gab_id": "GAB-209",
  "canonical_name": "PlayEngineSessionQualityGuard",
  "module_owner": "EdTechPlayEngine",
  "renderer_key": "text_cta",
  "required_fields": [
    "gab_id",
    "session_quality_guard_id",
    "title",
    "subtitle",
    "scenarios",
    "primary_cta"
  ],
  "optional_fields": [
    "icon",
    "simulator_label",
    "checks_section_label",
    "log_note",
    "secondary_cta"
  ],
  "field_types": {
    "scenarios": "array<{key:string, label:string, checks:array<{title,detail,status}>, verdict:{status,heading,text}}> — au moins 1 scénario requis",
    "scenarios[].checks[].status": "enum['pass','fail','warn']",
    "scenarios[].verdict.status": "enum['pass','fail','warn']",
    "primary_cta": "object{label,action}",
    "secondary_cta": "object{label,action}",
    "log_note": "object{icon,text}"
  },
  "constraints": [
    "scenarios doit contenir au moins 1 entrée.",
    "Chaque check doit avoir un status parmi pass/fail/warn.",
    "primary_cta.label pilote le libellé du bouton structurel — jamais hardcodé dans le HTML.",
    "Le verdict est data-driven : heading et text viennent du JSON, pas du HTML.",
    "Aucun identifiant d'un autre GAB ne doit figurer dans le renderer."
  ],
  "blocked_conditions": [
    "scenarios absent ou vide",
    "title absent",
    "primary_cta absent"
  ],
  "accessibility": [
    "keyboard_navigable",
    "focus_visible",
    "prefers_reduced_motion",
    "aria_labels_on_buttons"
  ],
  "qa_cases": [
    { "case": "instance conforme (scénario good)", "expected": "rendu complet, 5 checks pass, verdict vert" },
    { "case": "scénario broken activé", "expected": "2 checks fail, verdict rouge BLOCKED" },
    { "case": "scénario fake activé", "expected": "1 check warn + 1 fail, verdict rouge BLOCKED" },
    { "case": "champ requis manquant (title absent)", "expected": "BLOCKED listé dans le moteur" },
    { "case": "scenarios vide []", "expected": "BLOCKED + message d'erreur propre" },
    { "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-209",
    "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)."
  }
}
