{
  "contract_version": "gab_277_contract_v1",
  "gab_id": "GAB-277",
  "canonical_name": "MethodLearningModelAnswerGuide",
  "module_owner": "EdTechMethodLearning",
  "renderer_key": "text_cta",
  "required_fields": [
    "gab_id",
    "model_guide_id",
    "task_ref",
    "model_answer",
    "annotation_points",
    "display_policy"
  ],
  "optional_fields": [
    "card_subtitle",
    "anti_copy_notice",
    "comparison_prompt",
    "alternative_valid_answers",
    "reason_block",
    "primary_cta",
    "secondary_cta",
    "rubric_ref",
    "source_metadata"
  ],
  "field_types": {
    "model_guide_id": "string — identifiant unique de l'instance",
    "task_ref": "string — référence de la tâche cible (ex: 'démontrer Pythagore')",
    "model_answer": "object{html_annotated:string, annotations:array<{id,span,note}>}",
    "annotation_points": "array<{num:integer, label:string}> — 1 entrée par marqueur annoté",
    "display_policy": "object{label:string, state:enum['LOCKED','UNLOCKED'], student_attempt_required:boolean, min_incorrect_attempts:integer}",
    "anti_copy_notice": "object{title:string, text:string}",
    "primary_cta": "object{label:string, action:string}",
    "secondary_cta": "object{label:string, action:string}",
    "reason_block": "object{title:string, text:string}"
  },
  "constraints": [
    "annotation_points doit avoir au moins 1 entrée si model_answer.annotations est présent.",
    "display_policy.state doit être 'LOCKED' ou 'UNLOCKED'.",
    "primary_cta.label vient du JSON — jamais codé en dur dans le HTML.",
    "model_answer ne doit pas contenir de données personnelles élève."
  ],
  "blocked_conditions": [
    "model_guide_id absent (BLOCKED)",
    "task_ref absent (BLOCKED)",
    "model_answer absent (BLOCKED)",
    "annotation_points absent ou vide (BLOCKED)",
    "display_policy absent (BLOCKED)"
  ],
  "accessibility": [
    "keyboard_navigable",
    "focus_visible",
    "prefers_reduced_motion",
    "aria_labels_on_interactive_elements"
  ],
  "qa_cases": [
    { "case": "instance conforme", "expected": "rendu complet, 0 erreur" },
    { "case": "champ requis manquant (ex: annotation_points absent)", "expected": "BLOCKED listant le champ manquant" },
    { "case": "model_guide_id absent", "expected": "BLOCKED avec message clair" },
    { "case": "instance externe injectée via init(ext)", "expected": "le rendu change sans modifier le HTML" },
    { "case": "display_policy.state = LOCKED", "expected": "état verrouillé affiché, CTA désactivé" },
    { "case": "responsive 375/768/1024", "expected": "aucun débordement horizontal" }
  ],
  "traceability": {
    "derived_from_core_gab": "GAB-277",
    "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)."
  }
}
