diff --git a/knowledge/ux/patterns/README.md b/knowledge/ux/patterns/README.md
index a3d2f85..f4c1c88 100644
--- a/knowledge/ux/patterns/README.md
+++ b/knowledge/ux/patterns/README.md
@@ -8,5 +8,4 @@ Avant toute proposition UX, identifie le fichier dont le nom et la description m
| Fichier | Domaine | Entrées clés |
|---------|---------|--------------|
-
-_(aucune entrée pour le moment — à alimenter via `95_a_capitaliser.md`)_
+| `general.md` | Notifications, fiche détail, CTA, listes, états read-only, i18n, a11y mobile | Marquage "lu" au mount, fiche détail single-scroll/méta/chip, FAB vs sticky bottom, ligne de contexte sous filtres, CTA toggle différencié, table i18n inclusive, état read-only cacher vs griser, avatar pastel buckets distincts, audit a11y touch targets |
diff --git a/knowledge/ux/patterns/general.md b/knowledge/ux/patterns/general.md
new file mode 100644
index 0000000..aa579ca
--- /dev/null
+++ b/knowledge/ux/patterns/general.md
@@ -0,0 +1,205 @@
+---
+title: UX — Patterns validés : Général
+domain: ux
+bucket: patterns
+tags: [mobile, navigation, cta, fab, liste, etat, i18n, a11y, notifications]
+applies_to: [design, implementation, review]
+severity: medium
+validated_on: 2026-06-25
+source_projects: [app-alexandrie]
+---
+
+# UX — Patterns validés : Général
+
+> Extrait de la base de connaissance Lead_tech. Voir `knowledge/ux/patterns/README.md` pour l'index complet.
+
+---
+
+
+## Pattern : Marquage "lu" au mount de l'écran cible (mount-based, pas click-based)
+
+- Objectif : éviter les "clics accidentels qui consomment" une notification — marquer comme lu uniquement quand l'utilisateur a réellement vu le contenu.
+- Contexte : liste de notifications qui navigue vers un écran cible (thread, conversation, achievements).
+- Quand l'utiliser : tout flux notification → écran cible où le clic ne prouve pas la lecture.
+- Quand l'éviter : action où le clic EST l'acte de lecture (ex. dépliage inline).
+
+### Description
+
+Mauvais pattern : `onPress(item) → markRead(item.id); navigate(target)` — un clic accidentel puis back immédiat consomme la notif sans qu'elle ait été vue ; la notif disparaît avant que l'écran cible monte.
+
+Bon pattern : déléguer le mark-read à l'écran cible, déclenché au mount via query param (`?notificationId=`). Un hook `useMarkNotificationReadOnMount()` lit le param et appelle `markRead` dans un `useEffect`, avec un guard d'idempotence (`alreadyMarkedRef`) contre les re-renders (focus refresh, hot reload).
+
+Comportements obtenus : cas nominal (tap → écran monte → lu), cas annulation (tap → back avant mount → reste non lu), deep-link analytics-friendly et testable.
+
+- Validé le : 28-05-2026 — app-alexandrie (IA-v2.8 AC4)
+
+---
+
+
+## Pattern : Fiche détail — single-scroll immersif, méta-infos en tête, chip drill-down
+
+- Objectif : structurer une fiche de contenu/produit/praticien/événement sans "rooms vides" ni dispersion des infos.
+- Contexte : fiche détail mobile/web avec contenu de profondeur variable.
+- Quand l'utiliser : fiche détail à contenu court ou partiellement livré.
+- Quand l'éviter : fiche à forte profondeur réelle (chapitres + avis nombreux) où les tabs sont justifiés.
+
+### Trois patterns indépendants
+
+1. **Single-scroll vs tabs Udemy/Masterclass** : pour une fiche courte (pas de chapitres, pas d'avis livrés), préférer un single-scroll vertical. Les tabs créent des "rooms vides" qui sapent la crédibilité (onglet "Chapitres" vide, "Avis" avec un faux 5 étoiles). Réintégrer les sections en single-scroll est plus simple que remplir artificiellement des tabs.
+2. **Méta-infos groupées en tête** : regrouper toutes les méta-infos dans un bloc dense entre le hero et le contenu (overline catégorie > titre H1 > InfoChips > ligne progression compacte). Évite la dispersion ; donne un signal fort sur "ce qu'est ce contenu" avant de plonger. La progression tient sur une ligne (icon + label + date), c'est une info légère.
+3. **Chip cliquable drill-down** : plutôt qu'une section vide (avis sans backend, stats peu lues), exposer l'info en chip dans la zone méta (état neutre si vide : "☆ Aucun avis") qui devient l'entrée vers une page dédiée. Évite les empty states verbeux.
+
+- Validé le : 29-05-2026 — app-alexandrie (ux-cleanup-7)
+
+---
+
+
+## Pattern : Préférer le FAB étendu au sticky bottom plein-largeur sur écran à nav persistante
+
+- Objectif : éviter le piège de positionnement à 3 couches synchronisées (sticky `bottom` + paddingBottom ScrollView + safeArea) du CTA sticky.
+- Contexte : écran avec nav persistante (TabBar/BottomBar en `position: absolute, bottom: 0`) ET un CTA principal contextuel.
+- Quand l'utiliser : écran à nav persistante avec CTA (commencer, reprendre, créer).
+- Quand l'éviter : écran SANS nav persistante (modal, full-screen) où le sticky devient naturel ; ou CTA à label très long ; ou page de paiement validée maquette par maquette.
+
+### Description
+
+Un sticky bottom plein-largeur exige de re-synchroniser 3 hauteurs à chaque évolution de la nav, et un drift → le CTA chevauche la TabBar (bug observé sur device, invisible en tests Jest). Préférer un **FAB étendu Material 3** (icon + label, bottom-right) qui se positionne via UNE seule valeur (`bottom = NAV_HEIGHT + spacing + safeArea`) gérée par le composant lui-même, n'ajoute pas de surface visuelle redondante, et est immune aux évolutions de la nav.
+
+Anti-pattern : `` avec un Button plein-largeur — semble simple mais oblige à recalculer 3 hauteurs à chaque changement de nav.
+
+- Validé le : 29-05-2026 — app-alexandrie (ux-cleanup-7, le sticky a généré ~3 cycles de bugs sur device)
+
+---
+
+
+## Pattern : Ligne de contexte sous les filtres de liste
+
+- Objectif : permettre à l'utilisateur de comprendre instantanément ce qu'il regarde (combien, quel filtre) et pourquoi la liste est vide.
+- Contexte : toute liste filtrée (annuaire, feed, bibliothèque).
+- Quand l'utiliser : liste avec filtres et/ou recherche.
+- Quand l'éviter : liste sans filtre ni recherche.
+
+### Description
+
+Afficher une ligne de contexte juste sous les filtres et au-dessus du premier résultat. Elle : compte les résultats (singulier/pluriel correct), mentionne le filtre actif ("Ma cohorte • 5 membres"), contextualise la query ("Aucun résultat pour « pnl »"), explicite le vide ("Aucun membre dans votre cohorte" plutôt qu'une chaîne générique), et ne s'affiche PAS pendant le 1er chargement (count=0 + isLoading) pour éviter le flash "Aucun X".
+
+Implémentation type : helper pur `formatXxxContext({filter, count, query, isLoading}) → string` (testable à 100% en node) + composant léger en `textSecondary` 13px.
+
+Anti-pattern : empty state global (centré, gros) sur une liste filtrée — il masque les filtres alors que l'utilisateur veut comprendre POURQUOI c'est vide.
+
+- Validé le : 29-05-2026 — app-alexandrie (ux-cleanup-9)
+
+---
+
+
+## Pattern : CTA toggle différencié au-delà du libellé
+
+- Objectif : rendre l'état d'un CTA toggle (Suivre/Suivi, Souscrire/Souscrit) perceptible au premier regard.
+- Contexte : CTA qui bascule entre deux états (action / état "fait").
+- Quand l'utiliser : tout bouton à état binaire persistant.
+- Quand l'éviter : bouton d'action one-shot sans état.
+
+### Description
+
+Deux éléments visuels distincts au-delà du libellé :
+
+- **État inactif (action disponible)** : ghost button (fond transparent, bordure + texte `colors.primary`, libellé verbe infinitif "Suivre").
+- **État actif ("fait")** : filled tinted (fond `${colors.primary}1F` ≈ 12% d'alpha, bordure transparente, icône remplie alignée gauche, libellé participe passé "Suivi" — l'icône porte l'info, pas une coche dans le texte).
+
+**Pourquoi `${color}1F` plutôt qu'`opacity: 0.12`** : `opacity` fade TOUT l'enfant (icône + label), `${color}1F` n'applique l'alpha qu'au background — icône et label gardent leur saturation pleine.
+
+A11y obligatoire : `accessibilityState={{ selected: isActive }}` + `accessibilityLabel` explicitant état + action.
+
+Anti-pattern : différencier UNIQUEMENT par le libellé (Suivre → Suivi ✓) — le ✓ Unicode est faible visuellement et inaccessible.
+
+- Validé le : 29-05-2026 — app-alexandrie (ux-cleanup-9 AC3)
+
+---
+
+
+## Pattern : Table i18n de wordings inclusifs
+
+- Objectif : centraliser les wordings pour qu'ils soient auditables et inclusifs, et empêcher le composant d'inventer ses propres libellés.
+- Contexte : app francophone avec wordings genrés potentiels (notifications, messages).
+- Quand l'utiliser : tout domaine produisant des wordings adressés à l'utilisateur.
+- Quand l'éviter : —
+
+### Structure
+
+Un fichier `i18n/.ts` par domaine exposant : un `Record` interne `WORDING_FALLBACK` (générique), une fonction `Wording(type, ctx?)` qui combine type + contexte, et un `.spec.ts` qui vérifie fallbacks, cas avec contexte, dégradation gracieuse, et la règle d'inclusivité via un garde-fou regex anti-régression (`expect(wording).not.toMatch(/mentionnée(?![\w·])/)`).
+
+### Règles d'inclusivité française
+
+1. **Point milieu `·e`** pour les participes : "mentionné·e", "invité·e".
+2. **Nom commun neutre** quand possible : "abonné" plutôt que "follower".
+3. **Passé composé impersonnel** sans acteur nommé : "Nouvelle réponse à votre fil" plutôt que "Vous avez été répondu".
+4. **Nommer l'acteur quand on l'a** : "Bob a répondu à votre fil" (plus actionnable).
+
+Anti-patterns : wording inline dans le composant (inauditable) ; wording dans le push payload backend sans miroir dans la table mobile (divergence lockscreen vs in-app) ; test "smoke" qui vérifie juste que le wording n'est pas vide (rate les régressions de genre).
+
+- Validé le : 29-05-2026 — app-alexandrie
+
+---
+
+
+## Pattern : État read-only — cacher l'interactif plutôt que griser
+
+- Objectif : éviter le grisage avec placeholder ("Action désactivée"), un anti-pattern d'invitation qui fait essayer puis échouer l'utilisateur.
+- Contexte : élément interactif (composer DM, bouton "Acheter", formulaire) indisponible pour cause d'état métier (lecture seule, compte suspendu, plan inactif).
+- Quand l'utiliser : indisponibilité durable liée à un état métier.
+- Quand l'éviter : désactivation transitoire pendant un async court (préférer un loading).
+
+### Description
+
+Ne pas griser — **cacher** l'élément et afficher en remplacement un **bandeau neutre** qui explique l'état.
+
+Pourquoi cacher est meilleur : pas d'invitation à essayer ; explicite > implicite (le bandeau explique POURQUOI) ; a11y (`accessibilityRole="alert"` annonce l'état au mount, un input `editable={false}` ne signale rien) ; visuel (1 zone au lieu de composer grisé + bandeau redondant).
+
+Pattern de code : `{isReadOnly ? : }`. Ton neutre (`textSecondary` / `surfaceContainerLow`), pas `error` (réservé aux vraies erreurs réversibles).
+
+Anti-patterns : placeholder "Envoi désactivé" dans un TextInput non éditable ; `opacity: 0.5` (reste cliquable visuellement) ; bandeau ET composer affichés ensemble.
+
+- Validé le : 29-05-2026 — app-alexandrie (ux-cleanup-11 AC4)
+
+---
+
+
+## Pattern : Avatar coloré par hash — buckets distincts du fallback
+
+- Objectif : éviter qu'un utilisateur tombant dans un bucket trop neutre soit confondu avec un compte supprimé.
+- Contexte : avatar coloré "hash du nom" avec un bucket fallback (compte supprimé/anonyme).
+- Quand l'utiliser : avatars générés par hash.
+- Quand l'éviter : avatars uploadés / sans fallback identitaire.
+
+### Description
+
+Ne mettre dans le pool hashable QUE des accents colorés (`primary`/`secondary`/`tertiary` + leurs containers). Le fallback (`outlineVariant`) reste réservé aux fallbacks identitaires (compte supprimé, handle vide).
+
+Anti-pattern : inclure un token "surface" très clair (background-like) dans le pool — il ressemble au fallback grisé en light theme. Validation : tester visuellement les 8-12 tokens du pool sous light + dark ; retirer tout token proche du fallback.
+
+- Validé le : 30-05-2026 — app-alexandrie (ux-cleanup-11 M1)
+
+---
+
+
+## Pattern : Audit a11y des touch targets mobile RN
+
+- Objectif : garantir des cibles tactiles conformes (EAA 2025) sans linter a11y RN mainstream.
+- Contexte : app mobile React Native / Expo avec composants interactifs denses.
+- Quand l'utiliser : audit a11y ou story de polish touch targets.
+- Quand l'éviter : —
+
+### Cible et méthode
+
+Cible : 44×44pt iOS (Apple HIG) / 48×48dp Android (Material). Méthode (grep + calcul, pas de linter) : grep tous les `Pressable`/`TouchableOpacity`/`onPress` ; pour chacun, taille effective = `max(width, iconSize + paddingH*2) × max(height, fontSize + paddingV*2)` + `hitSlop` ; marquer non conforme si une dimension < 44pt ; rapport ordonné par gravité.
+
+### Décision hitSlop vs padding
+
+| Choisir... | Quand... |
+|---|---|
+| `hitSlop` | Composant qui DOIT rester visuellement compact (chip dense, icône + label adjacent, pill en liste serrée), réutilisé multi-écrans (changer le padding casse les callers), pas de feedback visuel attendu au-delà de la cible (chevron, lien "Voir tout") |
+| `padding` / `minHeight: 44` | Composant qui peut grossir sans gêne (CTA EmptyState, bouton primaire), feedback visuel attendu sur la zone élargie, composant isolé sans dépendance layout serrée |
+
+Syntaxe : `hitSlop={{ top: N, bottom: N, left: M, right: M }}` — N pour atteindre exactement 44pt en hauteur ; `left/right` plus petits (4-8) si chips côte-à-côte pour éviter l'overlap. Limite acceptée : audit visuel + grep seul (cf. risque associé dans `ux/risques/general.md`).
+
+- Validé le : 31-05-2026 — app-alexandrie (ux-cleanup-14)
diff --git a/knowledge/ux/risques/general.md b/knowledge/ux/risques/general.md
new file mode 100644
index 0000000..cbde18b
--- /dev/null
+++ b/knowledge/ux/risques/general.md
@@ -0,0 +1,119 @@
+---
+title: UX — Risques & vigilance : Général
+domain: ux
+bucket: risques
+tags: [mobile, navigation, handler, wording, tokens, a11y]
+applies_to: [design, implementation, review]
+severity: medium
+validated_on: 2026-06-25
+source_projects: [app-alexandrie]
+---
+
+# UX — Risques & vigilance : Général
+
+> Extrait de la base de connaissance Lead_tech. Voir `knowledge/ux/risques/README.md` pour l'index complet.
+
+---
+
+
+## Bouton retour placé à l'intérieur du ScrollView
+
+### Risques
+
+- Sur une app mobile RN/Expo avec une TopBar globale sans back natif, un bouton retour ajouté localement dans le `` disparaît dès que l'utilisateur défile
+- Sur une page critique (gestion d'abonnement, résiliation, support), perdre l'accès au retour pendant le scroll est un piège UX direct
+
+### Symptômes
+
+- Le bouton retour est le premier enfant du contenu scrollable et défile avec lui ; il devient inaccessible plus bas dans une page longue
+
+### Bonnes pratiques / mitigations
+
+- Tout bouton retour local doit vivre **hors du ScrollView** : header local sticky en `` parent (flex:1) + ScrollView frère.
+- Stop conditions : ne PAS doubler `insets.top` (le header le consomme → `contentInset.top = 0`) ; ne PAS placer le bouton dans `contentContainerStyle`. Si l'app utilise `` Expo Router avec header natif, préférer `headerBackVisible: true`.
+- Filet de test : test statique vérifiant qu'un fichier avec `handleBack` ne place pas le `` dans un ``.
+
+- Contexte technique : RN/Expo + TopBar globale — app-alexandrie 28-05-2026 (ux-cleanup-2)
+
+---
+
+
+## Bouton/lien sans handler laissé dans l'UI ("hors scope")
+
+### Risques
+
+- Un bouton survit dans l'UI sans `onPress` (résidu de template ou de dépendance retirée) : il tapote sans rien faire → boucle de frustration, l'utilisateur conclut que l'app est cassée et abandonne (grave sur le flow auth, critique pour l'acquisition)
+- "Hors scope" utilisé comme argument pour laisser passer → dérive de dette story après story
+
+### Symptômes
+
+- `` / `` visible sans prop `onPress` (ex. bouton "Facebook" sans OAuth côté API)
+
+### Bonnes pratiques / mitigations
+
+- **Règle** : tout bouton/lien visible doit avoir un `onPress` qui fait quelque chose. Si la feature n'est pas livrée : supprimer le bouton (défaut) ; OU le mettre derrière un feature flag interne ; OU afficher un toast/modal "Bientôt disponible".
+- Garde-fou review : grep `
+## Wording divergent cross-écran pour le même état métier
+
+### Risques
+
+- Deux écrans/composants affichent le même état métier (`NOT_STARTED`, `OUT_OF_STOCK`) avec des libellés différents, souvent parce que livrés par des stories distinctes
+- L'utilisateur traverse les écrans et voit deux mots pour le même état → confusion ; ne casse aucun test, dette qui s'accumule en silence
+
+### Symptômes
+
+- `CourseListItem` affiche "Nouveau" pour `NOT_STARTED`, `ProgressionInline` affiche "Pas encore commencé" pour le même état
+
+### Bonnes pratiques / mitigations
+
+- Centraliser le mapping état → libellé dans une seule fonction pure exportée (`statusLabel(state) => string`) consommée par tous les écrans.
+- Review : grep les libellés de status sur les écrans du domaine ; > 1 wording par état = finding MEDIUM.
+- Préférer les libellés courts et positifs ("Nouveau" > "Pas encore commencé").
+
+- Contexte technique : RN/Expo — app-alexandrie 29-05-2026 (ux-cleanup-6/7)
+
+---
+
+
+## Règle d'usage de token sans stratégie de détection
+
+### Risques
+
+- Un token décoratif (`outlineVariant` MD3 marqué "ne pas utiliser pour des séparations fonctionnelles") continue d'être utilisé pour des bordures fonctionnelles
+- La règle reste écrite dans le README mais inappliquée → divergence README vs code
+
+### Symptômes
+
+- Callsites résiduels utilisant le token décoratif en `borderColor`/`borderTopColor` malgré la règle documentée
+
+### Bonnes pratiques / mitigations
+
+- **Une règle d'usage de token doit être assortie d'une stratégie de détection** : (1) lint custom qui flag le token dans une prop bordure/couleur ; (2) audit récurrent (CI cron qui liste les usages) ; (3) renommer le token (`outlineDecorative` rend l'intention explicite).
+- Le coût "écrire la règle" est ~10 min, le coût "détecter les violations" est récurrent — investir dans la détection automatique.
+
+- Contexte technique : design tokens MD3 — app-alexandrie 30-05-2026 (ux-cleanup-8/11)
+
+---
+
+
+## Augmenter le padding d'un composant réutilisé multi-écrans (touch targets)
+
+### Risques
+
+- Élargir un touch target en augmentant le `padding` d'un composant réutilisé multi-écrans casse le layout des callers (liste serrée, ligne d'icônes header avec gap fixe)
+
+### Symptômes
+
+- Une cible tactile passe sous 44pt ; la corriger par `padding` change la taille visuelle et décale les callers
+
+### Bonnes pratiques / mitigations
+
+- Pour un composant réutilisé, préférer `hitSlop` au `padding` : seul effet = zone tap étendue, taille visuelle inchangée (cf. pattern d'audit dans `ux/patterns/general.md`).
+
+- Contexte technique : RN/Expo a11y — app-alexandrie 31-05-2026 (ux-cleanup-14)
diff --git a/knowledge/workflow/patterns/README.md b/knowledge/workflow/patterns/README.md
index 172f501..c00042c 100644
--- a/knowledge/workflow/patterns/README.md
+++ b/knowledge/workflow/patterns/README.md
@@ -8,4 +8,4 @@ Avant toute proposition workflow, identifie le fichier dont le nom et la descrip
| Fichier | Domaine | Entrées clés |
|---------|---------|--------------|
-| `general.md` | Review adversarial, isolation de hunks, méthode de chantier | Review adversarial obligatoire sur chemin critique, isolation chirurgicale d'un hunk via `git apply --cached` |
+| `general.md` | Review adversarial, méthode de chantier, sub-agents, migration, traçabilité | Review adversarial sur chemin critique, isolation de hunk via `git apply --cached`, triangulation sub-agent, audit cartographique avant chantier, Go/No-Go par lot, phasage feature avec placeholders, préparation Epic N+1 via rétro, sub-agent review fresh-context, revue adverse "information asymmetry", sweep read-only double-agent, audit-first migration large-scale, story polish multi-écrans, test obsolète après durcissement enum, génération palette Stitch MCP |
diff --git a/knowledge/workflow/patterns/general.md b/knowledge/workflow/patterns/general.md
index 2eac33e..462f648 100644
--- a/knowledge/workflow/patterns/general.md
+++ b/knowledge/workflow/patterns/general.md
@@ -5,8 +5,8 @@ bucket: patterns
tags: [review, adversarial, git, chantier, agent]
applies_to: [analysis, implementation, review]
severity: high
-validated_on: 2026-04-27
-source_projects: [RL799_V2]
+validated_on: 2026-06-25
+source_projects: [RL799_V2, app-alexandrie]
---
# Workflow — Patterns : Général
@@ -155,3 +155,261 @@ Les `index` et `@@` viennent du `git diff` original — pas besoin de recalculer
### Communication au user
> *"Sub-agent X signale 4 fichiers, j'ai validé 1/4 et invalidé 3/4. Voici le plan d'action corrigé."*
+
+---
+
+
+## Pattern : Audit cartographique 15-30 min avant tout chantier de fusion ou refacto transverse
+
+- Objectif : cadrer le chantier sur la **vraie** surface d'impact, pas sur une estimation à priori souvent fausse à ×3-5.
+- Contexte : chantier qui touche un composant/pattern utilisé en plusieurs endroits (fusion de 2 composants, migration de N call-sites, consolidation de pattern).
+- Quand l'utiliser : avant de planifier les sous-lots, dès que le scope annoncé dépasse 1-2 fichiers.
+- Quand l'éviter : modification locale à un seul fichier sans dépendance inverse.
+- Validé le : 05-05-2026
+- Contexte technique : monorepo Vue / pnpm — RL799_V2
+
+### Checklist d'audit
+
+1. **Call-sites directs** : `grep` du nom du composant/symbole (``, ``, `import X`).
+2. **Call-sites indirects** : grep des **classes CSS**, des **data-testid**, des **types/enums** exportés. Piège fréquent : un composant scoped qui réutilise une classe CSS globale sans importer le composant.
+3. **Tests** : grep dans `__tests__/`, `tests/e2e/`, `tests/`. Inclure string-match (lecture du source) ET tests de mount.
+4. **Dépendances inverses** : qui produit/consomme les types métier exportés ? (un call-site peut dépendre du type sans dépendre du composant.)
+5. **Doublons CSS scoped vs global** : une classe nommée identiquement en `