# GAB-304 · DocumentLearningExtractInformation — « Extraire l'info utile »

**Format :** GAB data-driven (moule GAB-VALIDE/GAM) · **renderer_key :** `extract_select` · **family_code :** `document_analysis`
**Critère validé :** changer le JSON change l'écran sans modifier le HTML. ✅ (check.py ; Playwright à faire)

## Pack (format GAB-VALIDE attendu)
```
GAB-304/
  renderer.html                          ← moteur extract_select générique (ne pas modifier par instance)
  instance-extract-information.json      ← SOURCE DE VÉRITÉ (le dev remplit ça)
  schema.json                            ← contrat de validation
  README-contract.md                     ← ce fichier
```

## Le JSON déclare
- `gab_id: GAB-304` · `renderer_key: extract_select` · `family_code: document_analysis` · `site`
- `instance.title` — titre d'écran
- `instance.target_question` — la question cible à laquelle l'extraction doit répondre
- `instance.info_type` — nature de l'info recherchée (ex agent, date, lieu)
- `instance.evidence_zone` — zone/preuve du document à citer
- `instance.instruction` — consigne affichée
- `instance.items[]` — chaque item : `{ label, useful, why }`. **`useful:true`** = info qui répond ; **`useful:false`** = donnée inutile OU hors document (jamais inventée comme réponse)
- `instance.success_feedback` — message quand tous les items utiles sont extraits
- `accessibility[]` / `child_safety[]` — `no_invented_information`, `out_of_document_rejected`, `no_hard_failure`

## Comment le dev ajoute / change un item
```json
{ "label": "Le décor est urbain", "useful": false, "why": "Détail de fond, ne répond pas à la question ciblée." }
```
Il l'ajoute dans `instance.items`. Le moteur l'affiche, gère le clic, le verdict et le compteur tout seul. **Il ne touche jamais renderer.html.**

## Le moteur (extract_select) fait
- peint la question cible (`target_question`) + les tags `info_type` / `evidence_zone`
- peint chaque item depuis `instance.items`
- clic sur un item = applique son verdict (`useful`) + affiche son `why` (validation ✓ pour utile, rejet pour inutile/hors document)
- quand tous les items `useful:true` sont extraits = affiche `success_feedback` (N/N)
- BLOCKED si `target_question` absente / `items` vide / aucun item `useful:true`

## Garde-fous (child_safety)
- `no_invented_information` : aucune réponse n'est hallucinée, chaque verdict vient de l'instance.
- `out_of_document_rejected` : un item hors document est `useful:false` et son `why` signale qu'on ne sait pas.
- `no_hard_failure` : un mauvais clic donne un feedback de rejet, jamais un échec bloquant.

## Inline vs externe
Inline (`window.GAB_INSTANCE`) = copie de démo pour ouvrir sans serveur. **Source de vérité = le .json.**
Moteur prêt pour l'externe : `DATA = (arguments.length && ext) ? ext : (window.GAB_INSTANCE || null)`.

## Source d'origine
`GAB-001-390-DATA-SOURCES/INDEX-300-documentlearning-GAB-301-305-PLAYABLE.html` (stage `data-tpl="304"`, lignes ~294-329 + handler `d304Pick(...)` lignes ~438-449). Contenu extrait : question cible (« qui supporte le poids dans la caricature ? »), 4 chips (2 utiles : « Deux personnages portent le 3ᵉ », « Le personnage assis ne porte rien » ; 2 inutiles : « Le sceau est rouge », « C'était un 14 juillet »), feedbacks de validation et de rejet repris mot pour mot.
