mirror of
https://github.com/MaksTinyWorkshop/_Assistant_Lead_Tech
synced 2026-06-27 17:43:41 +02:00
capitalisation: purge buffer après routage projet (RL799_V2, app-alexandrie)
Les 3 dernières propositions "en attente de routage projet" ont été déplacées vers le CLAUDE.md de leur projet source : - RL799_V2 (app-rl799): pattern centre d'aide in-app + taux de présence borné par initiatedAt - app-alexandrie: piège tronc commun vs extension premium (Skool) Buffer restauré à son état initial (template vide). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
+13
-163
@@ -80,176 +80,26 @@ Description courte, factuelle, orientée réutilisation.
|
||||
|
||||
---
|
||||
|
||||
---
|
||||
|
||||
# Entrées en attente de routage projet
|
||||
|
||||
Les propositions ci-dessous ont été jugées **trop spécifiques à un projet** lors du
|
||||
triage de capitalisation (2026-06-25). Elles ne vont PAS dans `knowledge/` global mais
|
||||
dans le `CLAUDE.md` du projet source. À router manuellement dans le repo concerné :
|
||||
|
||||
- **RL799_V2** : « centre d'aide utilisateur in-app » + « taux de présence borné par initiatedAt »
|
||||
- **app-alexandrie** : « tronc commun vs extension premium » (formation Skool)
|
||||
|
||||
Le reste du buffer (≈270 propositions, mai-juin 2026) a été intégré dans `knowledge/`,
|
||||
`40_decisions_et_archi.md` et `90_debug_et_postmortem.md` (commits du 2026-06-25).
|
||||
|
||||
_Aucune entrée pour le moment_
|
||||
|
||||
---
|
||||
|
||||
2026-05-11 — RL799_V2
|
||||
|
||||
FILE_UPDATE_PROPOSAL
|
||||
Fichier cible : knowledge/frontend/patterns/general.md (ou créer un nouveau
|
||||
fichier `knowledge/frontend/patterns/doc-utilisateur-in-app.md` si le sujet
|
||||
mérite sa propre entrée — le pattern est dense)
|
||||
|
||||
Pourquoi :
|
||||
|
||||
Pattern complet et réutilisable de **centre d'aide utilisateur in-app** pour
|
||||
toute application Vue 3 / Vite avec un public cible exigeant (B2B niche,
|
||||
métiers spécialisés, organisations à valeur de confiance). Le pattern combine
|
||||
**5 disciplines** qui se renforcent mutuellement et constituent un système
|
||||
durable, contrairement aux approches "FAQ statique" ou "tour guidé Userpilot"
|
||||
qui dérivent silencieusement en 6 mois.
|
||||
|
||||
Livré sur RL799_V2 en 4 sous-lots + 1 d'opportunité (~10h effort réel vs
|
||||
26h estimés), validé par 948 tests verts, build OK, déployé. Bénéfice direct :
|
||||
réduction du coût marginal de support par loge déployée, argument commercial
|
||||
(signal de sérieux opérationnel attendu en B2B niche).
|
||||
|
||||
Proposition :
|
||||
|
||||
## Pattern — Centre d'aide utilisateur in-app (Vue + Markdown + tests CI)
|
||||
|
||||
### Anti-patterns explicitement écartés
|
||||
|
||||
- ❌ **Tour guidé pas-à-pas au premier login** (Userpilot, Intro.js) — friction
|
||||
pour public initié, maintenance lourde à chaque changement UI
|
||||
- ❌ **FAQ statique en page wiki/Notion** — dérive silencieuse, pas de revue
|
||||
par PR, pas de versionnement, pas de tests
|
||||
- ❌ **Chatbot IA** — perception négative en contexte B2B niche (méfiance),
|
||||
coût récurrent API LLM, pas de garantie de justesse
|
||||
- ❌ **Vidéos longues à la place du texte** — non-cherchable, maintenance lourde
|
||||
|
||||
### Architecture
|
||||
# Rôle dans l'architecture
|
||||
|
||||
```
|
||||
docs/user/<audience>/<slug>.md (Markdown + frontmatter YAML)
|
||||
↓ import.meta.glob (Vite, lazy)
|
||||
↓ frontmatter parser inline (js-yaml — JAMAIS gray-matter, cf. piège)
|
||||
↓ index par audience (slug, title, audience, last_reviewed)
|
||||
Projet
|
||||
↓
|
||||
/aide (index par onglets de rôle)
|
||||
/aide/:audience/:slug (rendu Markdown via marked)
|
||||
Proposition
|
||||
↓
|
||||
Bouton "?" contextuel en top-bar (route → guide canonique mappé)
|
||||
95_a_capitaliser.md
|
||||
↓
|
||||
Validation humaine
|
||||
↓
|
||||
Lead_tech
|
||||
```
|
||||
|
||||
### Discipline 1 — Source unique de vérité
|
||||
Ce mécanisme permet :
|
||||
|
||||
Tous les guides vivent dans `docs/user/`, en Markdown, versionnés en Git.
|
||||
**Pas de Notion. Pas de Google Docs. Pas de wiki externe. Pas d'exception.**
|
||||
|
||||
Bénéfices :
|
||||
- Versionnement gratuit (historique Git)
|
||||
- Revue par PR (qualité éditoriale)
|
||||
- Diff visible (changement traçable)
|
||||
- Bundling au build par Vite (lecture in-app sans fetch runtime, ~14 Ko
|
||||
gzippé pour 8 guides + composants)
|
||||
- Aucun service tiers à maintenir
|
||||
|
||||
### Discipline 2 — Frontmatter YAML validé Zod
|
||||
|
||||
```yaml
|
||||
|
||||
---
|
||||
|
||||
2026-06-08 — app-alexandrie
|
||||
|
||||
FILE_UPDATE_PROPOSAL
|
||||
Fichier cible : 90_debug_et_postmortem.md (ET pointeur dans 10_backend_risques_et_vigilance.md / 10_frontend_risques_et_vigilance.md)
|
||||
|
||||
Pourquoi :
|
||||
Pendant une session de rédaction de tech-specs (BMad quick-spec) sur une app de
|
||||
formation (modèle Skool : Pack → Module → Leçon, avec modules PREMIUM = add-ons
|
||||
payants en plus du pack de base), le MÊME piège a cassé 5 fois de suite, à travers
|
||||
3 specs différentes (#2 leçon-preview, #6 achievements, #4 écran-de-fin) et a été
|
||||
attrapé uniquement par la revue adversariale itérative (parfois 4 tours pour une
|
||||
seule spec). Le piège est suffisamment générique pour mériter une règle.
|
||||
|
||||
Le piège (formulation générique) :
|
||||
Dans tout domaine où un parcours a un « tronc commun obligatoire » + des
|
||||
« extensions optionnelles » (premium, bonus, modules payants à part), les notions
|
||||
de **séquence**, **suivant**, **fin**, **progression %**, **complétion 100%** ont
|
||||
DEUX définitions qui divergent silencieusement :
|
||||
- définition POSITIONNELLE/PHYSIQUE (toutes les unités, premium inclus, triées
|
||||
par position) — c'est ce que renvoient typiquement les helpers `nextAfter()`,
|
||||
`flattenSequence()`, `findNext()` ;
|
||||
- définition MÉTIER (tronc commun seul = ce qu'un acheteur de base doit/peut
|
||||
finir) — c'est ce que veut presque toujours la logique produit (« diplômé »,
|
||||
« formation terminée », badge, déblocage).
|
||||
Un champ nommé `nextUnlockedLessonId`, `continueLessonId`, `sequence`,
|
||||
`completedIds` n'est PRESQUE JAMAIS filtré sur le tronc commun — il inclut le
|
||||
premium. Supposer le contraire produit, selon le cas :
|
||||
- faux NÉGATIF : la fin n'est jamais détectée (une unité premium reste « après »
|
||||
le tronc fini → `next !== null` éternellement) ;
|
||||
- faux POSITIF : « terminé » déclenché alors que le tronc ne l'est pas (finir une
|
||||
unité premium terminale alors que le tronc a un trou).
|
||||
|
||||
Symptômes observés (concrets, pour reconnaissance) :
|
||||
- `nextLessonAfter(sequence, id)` = `idx+1 >= sequence.length ? null` → purement
|
||||
positionnel, `sequence` = `flattenSequence` qui inclut `isPremium`.
|
||||
- `completedIds` chargé AVANT l'upsert de l'unité courante → au moment d'un hook
|
||||
post-commit, la dernière unité validée MANQUE encore.
|
||||
- 3 définitions de « 100% » coexistant dans le même codebase (progress UI =
|
||||
COMPLETED brut sur baseSequence ; remboursement = visionnage réel ≥90% sur TOUS
|
||||
modules ; ce qu'on voulait = visionnage réel sur tronc) → citer l'une comme
|
||||
« réutilisable » envoie le dev recopier le mauvais périmètre OU la mauvaise métrique.
|
||||
- `baseSequence = sequence.filter(!isPremium)` existe souvent DÉJÀ mais en `const`
|
||||
interne non exporté → tentation de le citer comme réutilisable à tort.
|
||||
|
||||
Proposition (règle) :
|
||||
« Tronc commun vs extension premium — ne jamais supposer qu'un champ
|
||||
fin/suivant/séquence/progression filtre le premium. »
|
||||
1. Avant de spécifier/coder toute logique de complétion, fin, déblocage,
|
||||
progression ou « 100% » : LIRE le code réel des helpers de séquence
|
||||
(`buildSequence`/`flatten`/`nextAfter`/`findContinue`) et confirmer s'ils
|
||||
incluent ou non les unités premium/optionnelles. Ne pas déduire du nom.
|
||||
2. Identifier TOUTES les définitions de complétion existantes dans le codebase
|
||||
(souvent ≥2 : UI progress, remboursement, déblocage). Vérifier leur PÉRIMÈTRE
|
||||
(tronc seul ? tous modules ?) ET leur MÉTRIQUE (état brut COMPLETED ? visionnage
|
||||
réel ≥seuil ?). Si aucune ne combine le périmètre + la métrique voulus, écrire une
|
||||
fonction dédiée et le DIRE explicitement (« ni X ni Y n'est réutilisable tel quel »)
|
||||
— ne pas citer une fonction proche comme réutilisable.
|
||||
3. Garde-fou systématique : une condition « 100% » via `every()` sur un ensemble
|
||||
filtré DOIT garder le cas vide (`length === 0 → false`), sinon `every([]) === true`
|
||||
= faux positif massif (déblocage pour tous, y compris au backfill).
|
||||
4. Préférer un BOOLÉEN SERVEUR explicite (`isFormationComplete`,
|
||||
`isBaseTrackDone`) porté dans le payload, et déclencher la logique mobile/UI
|
||||
dessus — JAMAIS sur un dérivé positionnel (`next === null`).
|
||||
5. Effet de bord du fix : si on déclenche un calcul « est-ce fini ? » sur la
|
||||
présence d'une extension premium (`hasPremium`), ce flag est CONSTANT pour
|
||||
l'entité → le calcul tourne à chaque action, et tout événement post-tronc le
|
||||
redonne `true` → risque de re-célébration/re-déclenchement en boucle. Ajouter une
|
||||
garde de transition (false→true) ou une ref de session.
|
||||
|
||||
Méta-leçon (pour 40_decisions_et_archi.md ou workflow) :
|
||||
Quand une MÊME zone (ici complétion/premium) casse à plusieurs tours de revue
|
||||
adversariale, le défaut N'EST PAS épuisé — chaque correction sur cette zone mérite
|
||||
une RE-vérification dédiée, car les fixes y introduisent des effets de bord non
|
||||
évidents (ex. un `|| hasPremium` qui corrige un faux négatif crée une re-célébration
|
||||
en boucle). Ne jamais clore une telle zone sur une intuition de convergence.
|
||||
|
||||
---
|
||||
|
||||
2026-06-20 — RL799_V2 / Code review v2-4-2
|
||||
|
||||
FILE_UPDATE_PROPOSAL
|
||||
Fichier cible : knowledge/backend/risques/general.md
|
||||
|
||||
Pourquoi :
|
||||
`computeSeasonStats` dans `hospitalierVeilleService.ts` filtrait les tenues par grade et par saison mais omettait de les borner par `member.initiatedAt`. Un Frère initié en mars 2026 apparaissait avec un mauvais taux de présence saison 2025-2026 car le dénominateur incluait toutes les tenues depuis septembre 2025 — avant qu'il soit membre. L'AC5 et les Dev Notes le précisaient explicitement, mais le bug était invisible aux tests (le seed n'a pas de membre récemment initié avec des tenues antérieures).
|
||||
|
||||
Proposition :
|
||||
**Taux de présence sur périmètre borné par `initiatedAt` : toujours filtrer `tenue.date >= member.initiatedAt`.** Quand on calcule un taux/compteur d'absences sur un périmètre temporel (saison, trimestre, etc.) pour un membre, le dénominateur doit exclure les tenues antérieures à la date d'initiation du membre — il n'était pas encore convié. Pattern : `if (tenue.date < member.initiatedAt) continue;` avant tout autre filtre de périmètre. Ce filtre est rarement couvert par les tests automatiques (le seed a des membres initiés avant la saison de test), ce qui le rend vulnérable aux oublis. Le mettre en première vérification dans la boucle le rend visible et documenté. Cas vécu : `computeSeasonStats` dans `hospitalierVeilleService.ts` — filtre ajouté en code review v2-4-2 du 2026-06-20.
|
||||
- d'éviter la pollution de la base de connaissance
|
||||
- de capitaliser progressivement l'expérience des projets
|
||||
- de garder `Lead_tech` cohérent et fiable.
|
||||
|
||||
Reference in New Issue
Block a user