# Process : la recette visuelle Playwright — obligatoire pour toute livraison UI

> **Règle instituée le 18/08 (Enguerran).** Trois validations peuvent être vertes —
> tests, CI, rapport de fil — sans que personne n'ait REGARDÉ la page. La page
> cours (#212) l'a prouvé une dernière fois : structure livrée, habillage absent,
> « quasi aucun changement » à l'œil. Depuis que la comparaison Playwright est
> dans la boucle du fil : « résultats bien meilleurs ». Ce process est donc
> OBLIGATOIRE, pas conseillé.

## La règle en une phrase

**Aucune annonce « PRÊTE À MERGER » sur un écran sans comparaison
maquette-contre-écran au navigateur, même cadre, vraie session — et
re-comparaison après CHAQUE bloc de correctifs, pas à la fin.**

## Qui compare quoi, quand

| Moment | Qui | Quoi |
|---|---|---|
| Pendant le chantier | le fil | maquette ouverte À CÔTÉ, re-capture après chaque bloc |
| Avant d'annoncer | le fil | passe complète : structure, états (survol/focus/actif/désactivé), les 3 états de données (vide/normal/erreur) quand ils existent |
| Après déploiement | le pilote | la MÊME passe sur le bundle SERVI (le hash doit avoir changé — point 13) |

## La méthode

1. **Cadre unique** : 1440×1000, maquette et écran capturés dans le même viewport.
2. **Vraie session, vraies données** : comptes `recette-claude-*`, jamais de fixtures
   pour la passe finale (les fixtures cachent les écarts de données — vécu).
3. **Trois niveaux de comparaison**, du plus au moins objectif :
   - **structurel** : h1, sections, boutons, onglets — présence des repères de la maquette ;
   - **valeurs calculées** : couleurs, tailles, ombres, `transform`, `filter` en
     `getComputedStyle` — relever les VALEURS, jamais « présent/absent » ;
   - **œil** : une capture côte à côte dans le rapport de PR. L'habillage
     (fond, navbar, densité) porte souvent 80 % de l'effet perçu et échappe aux
     deux premiers niveaux.
4. **Le banc partagé** : `tools/recette-visuelle/` (dépôt FRONT). On l'étend, on ne
   recrée pas des scripts jetables. Les routes se lisent dans `App.jsx`, JAMAIS de
   mémoire. Les scripts d'appoint du pilote vivent dans `labs/screencast_poc/`.

## Le catalogue des pièges — tous vécus, tous coûteux

| Piège | Symptôme | Parade |
|---|---|---|
| Route inventée | « tout est absent » sur une page vide | lire `App.jsx` (3 incidents) |
| Maquette multi-états | compte d'écarts explosé (connexion : « 25/27 absents » — écran en fait conforme) | trier les repères d'ÉTATS avant de compter |
| Bouton désactivé | « aucun changement au survol » | la garde `:not(:disabled)` est un comportement, pas un bug — mesurer un actif |
| Élément présent mais invisible | timeout ou fausse absence | filtrer sur `getBoundingClientRect().height>0` |
| Champ global vs champ de liste | « la sélection survit à la recherche » (elle testait la recherche du bandeau) | viser le placeholder EXACT |
| `filter`/ombres réduits à oui/non | survol « sans effet » alors qu'il anime `brightness` ou change d'ombre | comparer les valeurs brutes |
| Élément masqué par la démo (`hidden`) | « composant introuvable » | rouvrir (`tableWrap.hidden=false`) |
| Sonde qui plante sur `null` | un garde-fou mort indiscernable d'un bug | toute absence se RAPPORTE, ne lève jamais |
| Ne pas suivre la maquette aveuglément | l'onglet Chat de la maquette cours | le produit a retiré le chat (#140) — la maquette n'est pas au-dessus des décisions produit |

## Prolongements

Le même banc alimente le **smoke post-déploiement** et le **canari** (issues FRONT
dédiées, post-recette) : un seul code de vérification, trois déclencheurs — le fil,
le pilote, la machine.
