{
  "contract_version": "gab_319_contract_v1",
  "gab_id": "GAB-319",
  "canonical_name": "RevisionLearningProgressRecap",
  "module_owner": "EdTechRevisionLearning",
  "renderer_key": "text_cta",
  "required_fields": [
    "gab_id",
    "recap_id",
    "evidence_label",
    "evidence_text",
    "remaining_label",
    "remaining_text",
    "next_action_cta_label",
    "next_action_body"
  ],
  "optional_fields": [
    "title",
    "next_action_title",
    "no_overcert_notice",
    "sync_pending"
  ],
  "field_types": {
    "recap_id": "string — identifiant unique de la session de récap",
    "evidence_label": "string — libellé du bloc preuves (ex: '✓ Acquis (preuve)')",
    "evidence_text": "string — description factuelle des acquis prouvés",
    "remaining_label": "string — libellé du bloc erreurs restantes (ex: '↻ Reste')",
    "remaining_text": "string — description des erreurs ou points fragiles restants",
    "next_action_cta_label": "string — libellé du bouton CTA next action",
    "next_action_title": "string — titre affiché dans le panel next action",
    "next_action_body": "string — description de la next action proposée",
    "no_overcert_notice": "string — avertissement anti-sur-certification (optionnel, affiché en muted)",
    "sync_pending": "boolean — indique si une synchro est en attente"
  },
  "constraints": [
    "evidence_text doit décrire une preuve factuelle (nb de réussites, nb de fois), jamais une assertion vague.",
    "remaining_text doit nommer explicitement l'erreur ou la notion fragile.",
    "next_action_body doit proposer une action concrète (mini-série, exercice, révision ciblée).",
    "no_overcert_notice : si présent, affiché en zone muted — jamais omis si sync_pending:true.",
    "Anti-sur-certification : le renderer n'affiche jamais 'maîtrisé' sans evidence_text prouvant la maîtrise."
  ],
  "blocked_conditions": [
    "evidence_text absent",
    "remaining_text absent",
    "next_action_body absent"
  ],
  "accessibility": [
    "keyboard_navigable",
    "focus_visible",
    "prefers_reduced_motion",
    "fallback_text"
  ],
  "qa_cases": [
    { "case": "instance conforme", "expected": "rendu complet, blocs acquis + reste + panel next action, 0 erreur" },
    { "case": "champ requis manquant (evidence_text)", "expected": "BLOCKED listant le champ" },
    { "case": "champ requis manquant (remaining_text)", "expected": "BLOCKED listant le champ" },
    { "case": "champ requis manquant (next_action_body)", "expected": "BLOCKED listant le champ" },
    { "case": "instance externe injectée via init(ext)", "expected": "le rendu change sans modifier le HTML" },
    { "case": "sync_pending:true + no_overcert_notice présent", "expected": "notice muted affichée dans le panel" },
    { "case": "responsive 375/768/1024", "expected": "aucun débordement horizontal" }
  ],
  "traceability": {
    "derived_from_core_gab": "GAB-319",
    "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)."
  }
}
