{
  "contract_version": "gab_046_contract_v1",
  "gab_id": "GAB-046",
  "canonical_name": "StoryNarrativeScene",
  "module_owner": "EdTechStoryLearning",
  "renderer_key": "text_cta",
  "required_fields": [
    "gab_id",
    "scene_id",
    "scene_narration",
    "scene_steps"
  ],
  "optional_fields": [
    "title",
    "scene_emoji",
    "cta_label",
    "cta_label_counting",
    "cta_label_done",
    "_note_dev",
    "renderer_key"
  ],
  "field_types": {
    "scene_id": "string — identifiant unique de la scène",
    "scene_narration": "string — paragraphe narratif initial affiché dès l'ouverture",
    "scene_steps": "array<string> — étapes narratives révélées progressivement au clic, au moins 1 élément",
    "scene_emoji": "string — emoji décoratif de la bannière visuelle (défaut : 🎬)",
    "cta_label": "string — libellé du bouton quand aucun compteur (défaut : 'Continuer le récit')",
    "cta_label_counting": "string — libellé avec {remaining} substitution (ex: 'Continuer le récit ({remaining})')",
    "cta_label_done": "string — libellé quand toutes les étapes sont révélées (défaut : 'Récit terminé')"
  },
  "constraints": [
    "scene_steps doit contenir au moins 1 élément ; un tableau vide déclenche BLOCKED.",
    "cta_label_counting supporte le token {remaining} substitué par le nombre d'étapes restantes.",
    "Le bouton est désactivé (disabled) après révélation de la dernière étape.",
    "Aucune ombre box-shadow rgba(0,0,0,...) — ombres colorées uniquement (DS V2)."
  ],
  "blocked_conditions": [
    "scene_narration absent",
    "scene_steps vides",
    "scene_id absent"
  ],
  "accessibility": [
    "keyboard_navigable",
    "focus_visible",
    "prefers_reduced_motion",
    "aria-label sur le bouton Continuer",
    "aria-hidden sur l'emoji décoratif"
  ],
  "qa_cases": [
    { "case": "instance conforme", "expected": "rendu complet, narration + bouton, 0 erreur" },
    { "case": "champ requis manquant (scene_narration absent)", "expected": "BLOCKED listant le champ" },
    { "case": "scene_steps vide []", "expected": "BLOCKED — 'scene_steps vides'" },
    { "case": "clic bouton × N", "expected": "chaque étape apparaît, compteur décroît, bouton désactivé à 0" },
    { "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-046",
    "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)."
  }
}
