{
  "contract_version": "gab_050_contract_v1",
  "gab_id": "GAB-050",
  "canonical_name": "StoryChoiceConsequence",
  "module_owner": "EdTechStoryLearning",
  "renderer_key": "text_cta",
  "required_fields": [
    "gab_id",
    "story_choice_id",
    "question",
    "choices"
  ],
  "optional_fields": [
    "fallback_text_summary"
  ],
  "field_types": {
    "story_choice_id": "string — identifiant unique de l'instance",
    "question": "string — la question posée à l'élève",
    "choices": "array<{id:string, text:string, is_good:boolean, feedback_label:string, feedback_text:string}> — 2 options minimum",
    "fallback_text_summary": "string — résumé textuel pour accessibilité/fallback"
  },
  "constraints": [
    "choices doit contenir au moins 2 éléments.",
    "Chaque choice doit avoir : id, text, is_good (boolean), feedback_label, feedback_text.",
    "is_good:true = bonne approche (feedback mint), is_good:false = mauvaise approche (feedback coral).",
    "Un seul clic autorisé (lock après premier choix) — côté moteur.",
    "Les lettres de choix (A, B, …) sont lues depuis choices[].id, jamais en dur dans le HTML."
  ],
  "blocked_conditions": [
    "question absente",
    "choices absents ou vides",
    "story_choice_id absent"
  ],
  "accessibility": [
    "keyboard_navigable",
    "focus_visible",
    "prefers_reduced_motion",
    "fallback_text"
  ],
  "qa_cases": [
    { "case": "instance conforme", "expected": "rendu complet, 0 erreur, question + 2 options affichées" },
    { "case": "champ requis manquant (ex: choices vide)", "expected": "BLOCKED listant le champ" },
    { "case": "clic option A (is_good:true)", "expected": "option stylée mint, feedback mint affiché, lock activé" },
    { "case": "clic option B (is_good:false)", "expected": "option stylée coral, feedback coral affiché, lock activé" },
    { "case": "double-clic (lock)", "expected": "second clic ignoré" },
    { "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-050",
    "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)."
  }
}
