{
  "contract_version": "gab_329_contract_v1",
  "gab_id": "GAB-329",
  "canonical_name": "ResearchLearningBiasPerspectiveCheck",
  "module_owner": "EdTechResearchLearning",
  "renderer_key": "text_cta",
  "required_fields": [
    "gab_id",
    "bias_check_id",
    "source_quote",
    "source_label",
    "instruction",
    "bias_criteria",
    "primary_cta",
    "verdict_thresholds"
  ],
  "optional_fields": [
    "title",
    "progress_label_tpl"
  ],
  "field_types": {
    "source_quote": "string — citation brute de la source à examiner (entre guillemets)",
    "source_label": "string — libellé affiché au-dessus de la citation (ex : 'Source à examiner')",
    "instruction": "string — consigne d'introduction à la liste de critères",
    "bias_criteria": "array<{id:string, label:string}> — liste des indices de biais à cocher, min 1 item",
    "progress_label_tpl": "string — template avec {done}/{total} pour le compteur de cases cochées",
    "primary_cta": "object{label:string, action:string} — bouton structurel, libellé depuis le JSON",
    "verdict_thresholds": "object{bias_probable:{min_checked,state,panel_class,message}, isolated_clue:{exact_checked,state,panel_class,message}, balanced:{exact_checked,state,panel_class,message}}"
  },
  "constraints": [
    "bias_criteria doit contenir au moins 1 item.",
    "verdict_thresholds doit définir les 3 cas : bias_probable (min_checked>=2), isolated_clue (exact_checked===1), balanced (exact_checked===0).",
    "Anti-relativisme : le message bias_probable DOIT rappeler que 'orientée ≠ fausse'.",
    "primary_cta : bouton structurel HTML, libellé venant du JSON.",
    "progress_label_tpl : les tokens {done} et {total} sont requis si le champ est fourni."
  ],
  "blocked_conditions": [
    "bias_criteria absent ou tableau vide",
    "primary_cta absent",
    "verdict_thresholds absent ou incomplet (clés bias_probable/isolated_clue/balanced manquantes)"
  ],
  "accessibility": [
    "keyboard_navigable",
    "focus_visible",
    "prefers_reduced_motion",
    "aria_labels_on_checkboxes"
  ],
  "qa_cases": [
    { "case": "instance conforme", "expected": "rendu complet, 0 erreur, 3 critères cochables" },
    { "case": "champ requis manquant (ex: bias_criteria vide)", "expected": "BLOCKED listant le champ" },
    { "case": "0 case cochée + CTA", "expected": "panel 'note' — aucun indice coché" },
    { "case": "1 case cochée + CTA", "expected": "panel 'note' — indice isolé" },
    { "case": "2+ cases cochées + CTA", "expected": "panel 'warn' — biais probable + anti-relativisme" },
    { "case": "instance externe injectée", "expected": "le rendu change sans modifier le HTML" },
    { "case": "responsive 375/768/1024", "expected": "aucun débordement horizontal" }
  ],
  "traceability": {
    "derived_from_core_gab": "GAB-329",
    "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)."
  }
}
