{
  "contract_version": "gab_317_contract_v1",
  "gab_id": "GAB-317",
  "canonical_name": "RevisionLearningExamSprint",
  "module_owner": "EdTechRevisionLearning",
  "renderer_key": "text_cta",
  "required_fields": [
    "gab_id",
    "sprint_id",
    "segments",
    "training_disclaimer"
  ],
  "optional_fields": [
    "title",
    "break_after_segment",
    "break_message",
    "segment_done_message",
    "completion_message",
    "primary_cta"
  ],
  "field_types": {
    "sprint_id": "string — identifiant unique de l'instance sprint",
    "segments": "array<{id:number, label:string, duration_min:number}> — liste ordonnée des segments",
    "training_disclaimer": "string — avertissement obligatoire : ce n'est PAS l'examen officiel",
    "break_after_segment": "number — id du segment après lequel déclencher la pause (optionnel)",
    "break_message": "string — message de pause anti-surcharge cognitive",
    "segment_done_message": "string — message intermédiaire avec placeholder {n} pour le numéro de segment",
    "completion_message": "string — message de fin de sprint",
    "primary_cta": "object{label:string, action:string}"
  },
  "constraints": [
    "segments doit contenir au moins 1 élément, sinon BLOCKED.",
    "training_disclaimer est obligatoire : distinguer entraînement / examen officiel est une garde-fou pédagogique.",
    "segment_done_message peut contenir le placeholder {n} remplacé dynamiquement par l'id du segment complété.",
    "break_after_segment doit correspondre à un id existant dans segments si renseigné.",
    "Jamais utiliser GAB-317 pour un examen officiel noté (cf. do_not_use_when)."
  ],
  "blocked_conditions": [
    "sprint_id absent",
    "segments vides ou absents",
    "training_disclaimer absent"
  ],
  "accessibility": [
    "keyboard_navigable",
    "focus_visible",
    "prefers_reduced_motion",
    "tabindex sur chaque segment"
  ],
  "qa_cases": [
    { "case": "instance conforme", "expected": "rendu complet, segments cliquables, 0 erreur" },
    { "case": "sprint_id absent", "expected": "BLOCKED listant sprint_id" },
    { "case": "segments vides []", "expected": "BLOCKED listant segments vides" },
    { "case": "training_disclaimer absent", "expected": "BLOCKED listant training_disclaimer" },
    { "case": "segment n°2 cliqué", "expected": "message break_message affiché (si break_after_segment=2)" },
    { "case": "tous segments complétés", "expected": "completion_message affiché en panel ok" },
    { "case": "instance externe injectée via init(ext)", "expected": "rendu change sans modifier le HTML" },
    { "case": "responsive 375/768/1024", "expected": "aucun débordement horizontal" }
  ],
  "traceability": {
    "derived_from_core_gab": "GAB-317",
    "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)."
  }
}
