{
  "contract_version": "gab_039_contract_v1",
  "gab_id": "GAB-039",
  "canonical_name": "StreakBadgeInline",
  "module_owner": "EdTechPlayKit",
  "renderer_key": "text_cta",
  "required_fields": [
    "gab_id",
    "streak_id",
    "streak_count",
    "days_labels",
    "days_active"
  ],
  "optional_fields": [
    "streak_unit_label",
    "motivation_note",
    "context_note",
    "cta_label",
    "cta_action"
  ],
  "field_types": {
    "streak_count": "number — entier >= 0, fourni par GamificationAdapter, jamais calculé ici",
    "streak_unit_label": "string — libellé affiché sous le nombre (ex: 'jours d'affilée')",
    "days_labels": "array<string> — 7 labels de jours (ex: ['L','M','M','J','V','S','D'])",
    "days_active": "array<boolean> — 7 booléens alignés avec days_labels, true = jour actif",
    "motivation_note": "string — message contextuel affiché sous les cercles jours",
    "context_note": "string — note de contexte d'usage (lecture seule, header/recap/dashboard)",
    "cta_label": "string — libellé du bouton CTA optionnel",
    "cta_action": "string — identifiant action CTA (ex: 'open_streak_history')"
  },
  "constraints": [
    "streak_count >= 0 — PlayKit ne calcule JAMAIS le streak, il l'affiche seulement.",
    "days_labels.length === 7 ET days_active.length === 7 (alignés).",
    "days_active[i] = true <=> le jour i est inclus dans la série active.",
    "cta_label et cta_action sont liés : si cta_label présent, cta_action doit l'être aussi.",
    "streak_unit_label par défaut 'jours d'affilée' si absent."
  ],
  "blocked_conditions": [
    "streak_count absent",
    "days_labels absent ou longueur != 7",
    "days_active absent ou longueur != 7"
  ],
  "accessibility": [
    "keyboard_navigable",
    "focus_visible",
    "prefers_reduced_motion",
    "aria_labels_jours",
    "fallback_text"
  ],
  "qa_cases": [
    { "case": "instance conforme (3 jours actifs)", "expected": "rendu complet, flame animée, 3 cercles actifs, 0 erreur" },
    { "case": "streak_count absent", "expected": "BLOCKED listant le champ" },
    { "case": "days_active longueur != 7", "expected": "BLOCKED longueur incorrecte" },
    { "case": "streak_count = 0", "expected": "rendu valide, 0 cercle actif, affichage 0" },
    { "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, cercles jours restent visibles" }
  ],
  "traceability": {
    "derived_from_core_gab": "GAB-039",
    "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). Règle d'or : PlayKit affiche — GamificationAdapter calcule et écrit."
  }
}
