From f7a55b1113a282303f2d167353559e1dae81deb3 Mon Sep 17 00:00:00 2001 From: MaksTinyWorkshop Date: Tue, 10 Mar 2026 10:52:07 +0100 Subject: [PATCH] Capitalise nouveaux patterns backend/frontend/BMAD et externalise les templates du post-install BMAD --- 00_INDEX.md | 5 + 10_backend_patterns_valides.md | 132 ++++++- 10_backend_risques_et_vigilance.md | 127 +++++- 10_frontend_risques_et_vigilance.md | 52 ++- 40_decisions_et_archi.md | 87 ++++- .../claude/leadtech-capitalisation.mdfrag | 30 ++ .../config/producer_agents.tsv | 11 + .../bmad_post_install/memories/analyst.txt | 1 + .../bmad_post_install/memories/architect.txt | 1 + .../memories/core_bmad_master.txt | 1 + .../memories/dev_implementation.txt | 1 + .../bmad_post_install/memories/pm.txt | 1 + .../bmad_post_install/memories/qa.txt | 1 + .../bmad_post_install/memories/sm.txt | 1 + .../memories/tech_writer.txt | 1 + .../memories/ux_designer.txt | 1 + .../code-review-capitalisation.xmlfrag | 8 + .../workflows/code-review-checklist.mdfrag | 1 + .../dev-story-capitalisation.xmlfrag | 8 + .../workflows/dev-story-checklist.mdfrag | 1 + 80_bmad/process_llm_et_parallelisation.md | 98 +++++ 90_debug_et_postmortem.md | 26 ++ scripts/post-bmad-install.sh | 367 +++++++----------- 23 files changed, 742 insertions(+), 220 deletions(-) create mode 100644 70_templates/bmad_post_install/claude/leadtech-capitalisation.mdfrag create mode 100644 70_templates/bmad_post_install/config/producer_agents.tsv create mode 100644 70_templates/bmad_post_install/memories/analyst.txt create mode 100644 70_templates/bmad_post_install/memories/architect.txt create mode 100644 70_templates/bmad_post_install/memories/core_bmad_master.txt create mode 100644 70_templates/bmad_post_install/memories/dev_implementation.txt create mode 100644 70_templates/bmad_post_install/memories/pm.txt create mode 100644 70_templates/bmad_post_install/memories/qa.txt create mode 100644 70_templates/bmad_post_install/memories/sm.txt create mode 100644 70_templates/bmad_post_install/memories/tech_writer.txt create mode 100644 70_templates/bmad_post_install/memories/ux_designer.txt create mode 100644 70_templates/bmad_post_install/workflows/code-review-capitalisation.xmlfrag create mode 100644 70_templates/bmad_post_install/workflows/code-review-checklist.mdfrag create mode 100644 70_templates/bmad_post_install/workflows/dev-story-capitalisation.xmlfrag create mode 100644 70_templates/bmad_post_install/workflows/dev-story-checklist.mdfrag create mode 100644 80_bmad/process_llm_et_parallelisation.md diff --git a/00_INDEX.md b/00_INDEX.md index a023962..b7957f7 100644 --- a/00_INDEX.md +++ b/00_INDEX.md @@ -142,6 +142,11 @@ Dossier : 80_bmad/ ``` +Fichiers principaux : + +- `80_bmad/articulation_avec_lead_tech.md` +- `80_bmad/process_llm_et_parallelisation.md` + --- ## Debug et post‑mortems diff --git a/10_backend_patterns_valides.md b/10_backend_patterns_valides.md index 2304897..a635fd4 100644 --- a/10_backend_patterns_valides.md +++ b/10_backend_patterns_valides.md @@ -8,7 +8,7 @@ Ce fichier contient **uniquement** des patterns back-end : Objectif : éviter de réinventer la roue et réduire le temps de debug. -Dernière mise à jour : 09-03-2026 +Dernière mise à jour : 10-03-2026 --- @@ -27,6 +27,10 @@ Dernière mise à jour : 09-03-2026 - [Stripe — metadata sur `subscription_data`, pas sur la Session](#pattern-stripe-subscription-metadata) - [Webhooks entrants — parsing unique (single constructWebhookEvent)](#pattern-webhook-parsing-unique) - [Contracts-First — error codes comme contrat obligatoire](#pattern-contracts-error-codes) +- [RedisHealthService avec cache interne court](#pattern-redis-health-cache-court) +- [Sémantique explicite `Trial` vs `Paid` dans Subscription](#pattern-subscription-trial-vs-paid) +- [Restauration d’achats Stripe en 3 étapes](#pattern-restauration-achats-stripe) +- [Mapping explicite de `P2002` Prisma sur update de champ unique](#pattern-prisma-p2002-update-unique) --- @@ -558,6 +562,132 @@ handlePackWebhookEvent(event): PackWebhookResult | null --- + +## Pattern : RedisHealthService avec cache interne court + +- Objectif : exposer un état Redis exploitable par les guards globaux sans ping Redis à chaque requête. +- Contexte : backend Node/NestJS avec Redis consulté dans le chemin de décision d’écriture. +- Quand l’utiliser : quand plusieurs requêtes concurrentes doivent consulter l’état Redis. +- Quand l’éviter : si Redis n’est pas consulté dans le chemin request/response. +- Avantage : + - réduit fortement le flood de `PING` + - garde un signal d’état suffisamment frais +- Limites / vigilance : + - la fenêtre de cache doit rester courte + - l’état initial doit être explicite et assumé +- Validé le : 10-03-2026 +- Contexte technique : NestJS / Redis + +### Implémentation (exemple minimal) + +```txt +- Mémoriser lastStatus et lastCheck +- Si le dernier check a moins de 5s, retourner l’état en cache +- Sinon exécuter un vrai PING et mettre le cache à jour +- Utiliser un état initial optimiste (`up`) si le produit ne doit pas bloquer les écritures au boot +``` + +### Checklist + +- Cache court documenté +- Pas de ping Redis à chaque requête +- Comportement initial explicite + +--- + + +## Pattern : Sémantique explicite `Trial` vs `Paid` dans Subscription + +- Objectif : aligner le modèle métier, les guards et les jeux de tests sur une définition unique de l’abonnement payant actif. +- Contexte : modèle `Subscription` où `trialEndsAt` matérialise un essai. +- Quand l’utiliser : dès qu’un même enregistrement supporte trial et abonnement payant. +- Quand l’éviter : si trial et abonnement payant sont modélisés par des entités distinctes. +- Avantage : + - évite les incohérences silencieuses dans les guards + - rend les fixtures et mocks e2e cohérents avec la règle métier +- Limites / vigilance : + - toute logique `isActive` doit préciser si elle signifie “trial ou paid” ou “paid only” +- Validé le : 10-03-2026 +- Contexte technique : Backend agnostique / modèle d’abonnement + +### Implémentation (exemple minimal) + +```txt +- Un abonnement payant actif n’est pas seulement status = ACTIVE +- Il doit aussi avoir trialEndsAt = null +- Les fixtures et mocks e2e d’un abonnement payant fixent toujours trialEndsAt: null +``` + +### Checklist + +- Règle métier explicitée +- Guards alignés sur la sémantique choisie +- Fixtures et seeds cohérents + +--- + + +## Pattern : restauration d’achats Stripe en 3 étapes + +- Objectif : reconstruire un état local cohérent à partir de Stripe sans dépendre d’une hypothèse fragile. +- Contexte : flux de restore purchases mobile/web avec état local potentiellement désynchronisé. +- Quand l’utiliser : dès qu’un utilisateur peut restaurer des achats depuis un nouveau device ou après désynchronisation. +- Quand l’éviter : si l’état Stripe n’est pas la source de vérité. +- Avantage : + - rend la réconciliation explicite + - supporte retries et restaurations tardives +- Limites / vigilance : + - la pagination Stripe et l’idempotence d’écriture restent obligatoires +- Validé le : 10-03-2026 +- Contexte technique : Stripe API / backend Node/NestJS + +### Implémentation (exemple minimal) + +```txt +1. Résolution du customer Stripe (ID persisté en DB, fallback robuste si absent) +2. Reconstruction de l’état Stripe utile au domaine +3. Réconciliation et écritures locales idempotentes +``` + +### Checklist + +- `stripeCustomerId` persistant côté app +- Réconciliation explicite documentée +- Upsert ou écriture idempotente + +--- + + +## Pattern : mapping explicite de `P2002` Prisma sur update de champ unique + +- Objectif : transformer un conflit d’unicité prévisible en erreur métier exploitable plutôt qu’en 500 opaque. +- Contexte : `update` Prisma sur un champ `@unique` alimenté par une source externe ou concurrente. +- Quand l’utiliser : dès qu’un champ unique peut être mis à jour après création. +- Quand l’éviter : jamais si le champ peut réellement entrer en collision. +- Avantage : + - réponse client stable + - diagnostic métier plus rapide +- Limites / vigilance : + - le mapping doit rester cohérent avec le format d’erreur API standardisé +- Validé le : 10-03-2026 +- Contexte technique : Prisma / PostgreSQL / NestJS + +### Implémentation (exemple minimal) + +```txt +- Catch explicite de PrismaClientKnownRequestError code P2002 +- Mapping vers une erreur métier stable +- Conserver requestId et format d’erreur standardisé +``` + +### Checklist + +- `P2002` intercepté sur les updates sensibles +- Code d’erreur métier stable +- Pas de 500 générique sur conflit prévisible + +--- + ### Notes importantes - On préfère 5 patterns solides à 50 “bons conseils”. diff --git a/10_backend_risques_et_vigilance.md b/10_backend_risques_et_vigilance.md index be5fbe9..9a72948 100644 --- a/10_backend_risques_et_vigilance.md +++ b/10_backend_risques_et_vigilance.md @@ -8,7 +8,7 @@ Ce fichier recense des risques back-end susceptibles de provoquer : - régressions coûteuses, - incohérences de données. -Dernière mise à jour : 09-03-2026 +Dernière mise à jour : 10-03-2026 --- @@ -39,6 +39,11 @@ Dernière mise à jour : 09-03-2026 - [Entitlements — TTL cache supérieur au SLA de propagation](#risque-entitlements-ttl-sla) - [Guard NestJS route-level — null-check manquant sur `request.user`](#risque-guard-request-user-null) - [Compteurs in-memory ≠ métriques persistées](#risque-compteurs-inmemory) +- [Interface provider incomplète ou divergente de ses implémentations](#risque-interface-provider-incomplete) +- [Boucle `upsert` N+1 sur synchronisation provider](#risque-upsert-n-plus-un-provider) +- [Stripe `list()` sans gestion de `has_more`](#risque-stripe-list-has-more) +- [Concurrence entre activation locale et webhook sur transition trial → payant](#risque-trial-payant-concurrence) +- [`jest.clearAllMocks()` dans des `beforeEach` imbriqués avec mocks Prisma](#risque-jest-clearallmocks-imbrique) --- @@ -378,3 +383,123 @@ if (!user?.userId) { - V1 low-cost : `Redis INCRBY` best-effort par `eventType` → persisté et agrégé multi-instances - Évolutif vers Prometheus/OTel sans changer l'interface (abstraction dès le départ) - Contexte technique : Redis / NestJS — 09-03-2026 + +--- + + +## Interface provider incomplète ou divergente de ses implémentations + +### Risques + +- Une implémentation expose des méthodes non déclarées dans le contrat commun +- Les appelants contournent l’interface et se couplent à un provider concret +- Une stratégie provider devient non interchangeable en pratique + +### Symptômes + +- Appels avec cast ou accès direct à une implémentation spécifique +- Méthodes présentes dans une classe mais absentes de l’interface +- Régression lors d’un changement de provider + +### Bonnes pratiques / mitigations + +- Toute capacité commune attendue par les appelants doit être déclarée dans l’interface +- Interdire les méthodes “cachées” consommées hors contrat +- Tester au moins une implémentation par le contrat abstrait +- Contexte technique : TypeScript / provider strategy — 10-03-2026 + +--- + + +## Boucle `upsert` N+1 sur synchronisation provider + +### Risques + +- Latence multipliée par le nombre d’items +- Charge DB inutile +- Timeouts ou contention sur gros volumes + +### Symptômes + +- Une boucle applicative exécute un `upsert` par item +- Temps de traitement qui explose avec le volume +- Logs SQL répétitifs et séquentiels + +### Bonnes pratiques / mitigations + +- Batcher quand c’est possible +- Précharger les données nécessaires avant boucle +- Mesurer explicitement le coût d’un `upsert` unitaire dans les flux de sync +- Contexte technique : Prisma / synchronisation provider — 10-03-2026 + +--- + + +## Stripe `list()` sans gestion de `has_more` + +### Risques + +- Pagination tronquée silencieusement +- Réconciliation incomplète d’abonnements, achats ou moyens de paiement +- Décisions métier prises sur un jeu de données partiel + +### Symptômes + +- Comportement correct sur petits comptes mais faux sur comptes plus chargés +- Premiers éléments traités, les suivants ignorés +- Absence de boucle de pagination ou d’auto-pagination + +### Bonnes pratiques / mitigations + +- Traiter explicitement `has_more` +- Utiliser l’auto-pagination Stripe si adaptée +- Tester au moins un cas avec plusieurs pages de résultats +- Contexte technique : Stripe API — 10-03-2026 + +--- + + +## Concurrence entre activation locale et webhook sur transition trial → payant + +### Risques + +- Double création ou double attachement d’une ressource unique +- Conflit `P2002` +- État local différent de l’état Stripe pendant la transition + +### Symptômes + +- La transition fonctionne parfois, puis échoue aléatoirement +- Un webhook Stripe et une action applicative écrivent la même mutation métier +- Erreurs d’unicité lors de l’activation payante + +### Bonnes pratiques / mitigations + +- Définir une seule source autorisée pour chaque transition d’état +- Rendre les écritures idempotentes +- Sérialiser ou réconcilier explicitement les transitions pilotées à la fois par action utilisateur et webhook +- Contexte technique : Stripe / Prisma / trial subscription — 10-03-2026 + +--- + + +## `jest.clearAllMocks()` dans des `beforeEach` imbriqués avec mocks Prisma + +### Risques + +- Remise à zéro d’un setup attendu par un scope de test plus profond +- Tests verts ou rouges pour de mauvaises raisons +- Forte difficulté à comprendre l’état réel des mocks + +### Symptômes + +- Comportement différent selon l’ordre ou le niveau d’imbrication des `describe` +- Mocks Prisma “perdus” entre deux tests +- Corrections locales qui cassent d’autres blocs de tests + +### Bonnes pratiques / mitigations + +- Centraliser la stratégie de reset des mocks +- Éviter les `clearAllMocks()` concurrents à plusieurs niveaux de nesting +- Préférer un setup explicite et local par scénario quand les mocks Prisma sont structurants +- Contexte technique : Jest / Prisma / tests NestJS — 10-03-2026 diff --git a/10_frontend_risques_et_vigilance.md b/10_frontend_risques_et_vigilance.md index 0af9dd4..ce59cc6 100644 --- a/10_frontend_risques_et_vigilance.md +++ b/10_frontend_risques_et_vigilance.md @@ -7,7 +7,7 @@ Ce fichier recense des risques front-end susceptibles de provoquer : - dette technique rapide, - régressions UX/perf/a11y. -Dernière mise à jour : 09-03-2026 +Dernière mise à jour : 10-03-2026 --- @@ -30,6 +30,8 @@ Dernière mise à jour : 09-03-2026 - [Performances : sur-renders + bundle](#risque-performances-sur-renders) - [Accessibilité oubliée (a11y)](#risque-accessibilite-oubliee) - [Catch silencieux — erreur inconnue sans feedback utilisateur](#risque-catch-silencieux) +- [Auto-reset d’un état dégradé sur toute réponse 2xx](#risque-auto-reset-etat-degrade) +- [Refresh store en fire-and-forget après mutation](#risque-refresh-store-fire-and-forget) --- @@ -205,3 +207,51 @@ Dernière mise à jour : 09-03-2026 - **Règle** : tout `catch` doit avoir une branche `else` (ou `default`) qui affiche un feedback utilisateur explicite. - Contexte technique : React Native / Expo — 09-03-2026 + +--- + + +## Auto-reset d’un état dégradé sur toute réponse 2xx + +### Risques + +- Le client sort trop tôt d’un mode dégradé alors que la cause serveur est toujours présente +- Le bandeau ou l’état read-only clignote puis disparaît à tort +- Les utilisateurs retentent une action d’écriture qui va encore échouer + +### Symptômes + +- Un GET réussi réinitialise `isReadOnly` ou `isDegraded` +- L’UI redevient “normale” alors que Redis ou un service critique est toujours indisponible +- Les erreurs reviennent immédiatement à la prochaine mutation + +### Bonnes pratiques / mitigations + +- Ne réinitialiser l’état dégradé qu’après une requête d’écriture réussie +- Exclure `GET` et `HEAD` de la logique de reset +- Conserver le mode dégradé tant qu’aucune mutation n’a prouvé le retour à la normale +- Contexte technique : React Native / Expo — 10-03-2026 + +--- + + +## Refresh store en fire-and-forget après mutation + +### Risques + +- L’UI affiche un succès alors que la resynchronisation a échoué +- État local incohérent avec l’état serveur +- Erreurs silencieuses impossibles à diagnostiquer + +### Symptômes + +- Mutation réussie puis store jamais rafraîchi +- Spinner coupé avant que l’écran soit réellement à jour +- Données anciennes qui persistent jusqu’au prochain reload + +### Bonnes pratiques / mitigations + +- `await` explicite du refresh si l’UI dépend du résultat +- Gestion d’erreur dédiée sur la phase de resynchronisation +- N’utiliser le fire-and-forget que pour un effet secondaire réellement non bloquant +- Contexte technique : React Native / Expo — 10-03-2026 diff --git a/40_decisions_et_archi.md b/40_decisions_et_archi.md index 27dd6e8..86abce2 100644 --- a/40_decisions_et_archi.md +++ b/40_decisions_et_archi.md @@ -8,7 +8,7 @@ Objectifs : - éviter de reposer les mêmes questions - assumer les compromis -Dernière mise à jour : 2026-03-09 +Dernière mise à jour : 2026-03-10 --- @@ -20,6 +20,8 @@ Dernière mise à jour : 2026-03-09 - [Le front-end est un logiciel en production](#decision-frontend-production) - [Le back-end est un logiciel en production](#decision-backend-production) - [Contrats d’API explicites et versionnés](#decision-contrats-api) +- [Single source of truth des contrats — schémas runtime partagés (Zod) + z.infer (No-DTO)](#decision-contrats-sso-zod) +- [User views — User public par défaut + MeUser explicite](#decision-user-views) - [Gestion standard des erreurs et des statuts HTTP](#decision-erreurs-http) - [Migrations et évolution de schéma maîtrisées](#decision-migrations) - [Observabilité minimale obligatoire](#decision-observabilite) @@ -301,6 +303,89 @@ Minimum attendu : --- + +## Single source of truth des contrats — schémas runtime partagés (Zod) + z.infer (No-DTO) + +- Date : 2026-03-10 +- Statut : Proposed +- Périmètre : global + +### Contexte + +TypeScript ne valide pas les payloads HTTP au runtime (les types disparaissent à l’exécution). +Quand on maintient à la fois des DTO/back (ex. Nest + decorators) et des types/contracts côté clients, on obtient une double source de vérité → drift, régressions, temps de debug. + +### Options envisagées + +- DTO NestJS + `class-validator` (validation runtime OK côté API, mais non partageable tel quel côté clients → duplication ou génération) +- Schémas runtime partagés dans un package `contracts` + types dérivés (validation + types alignés) +- OpenAPI/JSON Schema “first” + codegen (artefact contractuel unique, mais pipeline/outillage à maintenir) + +### Décision + +La source de vérité des contrats API↔clients est un package `contracts` contenant des **schémas runtime** (Zod), et les types TypeScript sont **dérivés** via `z.infer` (No-DTO / pas de redéfinition locale). + +Principe opérationnel : + +- validation concentrée aux frontières (ex. pipe/guard de validation côté API), +- le reste du code consomme des **types** (et non des classes DTO redondantes), +- les contrats restent “wire-level” (pas de métier, pas de stores, pas de classes Nest). + +### Justification + +- Un seul artefact sert à la fois de validation runtime et de typage compile-time +- Propagation des changements plus fiable (compile + tests) → réduction du temps de debug + +### Conséquences + +- Dépendance assumée à Zod dans `contracts` +- Les clients consomment les types; la validation côté client reste optionnelle (utile surtout sur entrées non-API : storage, deeplinks, etc.) +- En contexte non-mobile (Nest/React), OpenAPI-first + codegen reste une alternative valide si multi-clients/externe ou besoin fort de contrat public/documenté + +--- + + +## User views — User public par défaut + MeUser explicite + +- Date : 2026-03-10 +- Statut : Proposed +- Périmètre : global + +### Contexte + +Un “User” complet est rarement un bon contrat universel : il peut contenir des champs sensibles (email, adresse, téléphone, flags internes…). +Les dérivations TypeScript seules (`Omit`) ne protègent pas au runtime et favorisent les fuites accidentelles. + +### Options envisagées + +- Un type `User` “god object” + dérivations TS (Omit/Pick) au cas par cas +- Des “views” explicites par contexte (public, self, admin…), dérivées depuis les schémas runtime +- Un modèle unique côté DB + sérialisation implicite (risque élevé de fuite) + +### Décision + +`User` (dans les contracts) est **public par défaut** et minimal (safe-by-default). +La vue self/compte est un contrat séparé `MeUser`. +Toute vue plus riche est créée explicitement et nommée (ex. `AdminUser`, `UserDirectoryEntry`). + +Règles associées : + +- les vues sont dérivées depuis les schémas runtime (extend/pick/omit) + `z.infer` +- `password` (et assimilés) n’existe que dans des requêtes d’auth (login/register/reset/change), jamais dans un `User*` + +### Justification + +- Réduit le risque de fuite de données et clarifie les permissions/UX +- Évite les champs optionnels ambigus et les contrats “implicites” + +### Conséquences + +- Chaque endpoint choisit explicitement la vue renvoyée (et côté DB, un `select` explicite par vue) +- Les clients typent “public” vs “mon compte” distinctement +- Des tests “no secret keys” sur réponses user/auth deviennent simples et efficaces + +--- + ## Gestion standard des erreurs et des statuts HTTP diff --git a/70_templates/bmad_post_install/claude/leadtech-capitalisation.mdfrag b/70_templates/bmad_post_install/claude/leadtech-capitalisation.mdfrag new file mode 100644 index 0000000..cbb06d6 --- /dev/null +++ b/70_templates/bmad_post_install/claude/leadtech-capitalisation.mdfrag @@ -0,0 +1,30 @@ + +--- + +# Capitalisation vers Lead_tech + +Quand un apprentissage émerge (bug difficile, pattern réutilisable, anti-pattern, décision d'archi), +l'écrire dans la zone tampon Lead_tech : + +``` +~/AI_RULES/_Assistant_Lead_Tech/95_a_capitaliser.md +``` + +Sur le NUC : `/srv/projects/_Assistant_Lead_Tech/95_a_capitaliser.md` + +Format : + +``` +DATE — __PROJECT_NAME__ + +FILE_UPDATE_PROPOSAL +Fichier cible : <10_backend_patterns_valides.md | 10_frontend_patterns_valides.md | 10_ux_patterns_valides.md | 10_backend_risques_et_vigilance.md | 10_frontend_risques_et_vigilance.md | 10_ux_risques_et_vigilance.md | 40_decisions_et_archi.md | 90_debug_et_postmortem.md> + +Pourquoi : + + +Proposition : + +``` + +Règle : écrire dans `95_a_capitaliser.md` uniquement. Jamais directement dans les fichiers Lead_tech validés. diff --git a/70_templates/bmad_post_install/config/producer_agents.tsv b/70_templates/bmad_post_install/config/producer_agents.tsv new file mode 100644 index 0000000..32f4e63 --- /dev/null +++ b/70_templates/bmad_post_install/config/producer_agents.tsv @@ -0,0 +1,11 @@ +bmm-dev dev_implementation +bmm-architect architect +bmm-sm sm +bmm-qa qa +bmm-quick-flow-solo-dev dev_implementation +bmm-analyst analyst +bmm-pm pm +bmm-tech-writer tech_writer +bmm-ux-designer ux_designer +tea-tea qa +core-bmad-master core_bmad_master diff --git a/70_templates/bmad_post_install/memories/analyst.txt b/70_templates/bmad_post_install/memories/analyst.txt new file mode 100644 index 0000000..2899212 --- /dev/null +++ b/70_templates/bmad_post_install/memories/analyst.txt @@ -0,0 +1 @@ +When a reusable analysis pattern, requirements anti-pattern, or domain insight emerges, write a proposal to ~/AI_RULES/_Assistant_Lead_Tech/95_a_capitaliser.md (NUC: /srv/projects/_Assistant_Lead_Tech/95_a_capitaliser.md). Format: DATE — __PROJECT_NAME__ / FILE_UPDATE_PROPOSAL / Fichier cible: <10_product_patterns_valides.md | 10_backend_patterns_valides.md | 40_decisions_et_archi.md> / Pourquoi: / Proposition: . Never write directly to Lead_tech validated files. diff --git a/70_templates/bmad_post_install/memories/architect.txt b/70_templates/bmad_post_install/memories/architect.txt new file mode 100644 index 0000000..16df743 --- /dev/null +++ b/70_templates/bmad_post_install/memories/architect.txt @@ -0,0 +1 @@ +When a reusable pattern, difficult bug fix, anti-pattern, or architecture decision emerges during architecture or technical design, write a proposal to ~/AI_RULES/_Assistant_Lead_Tech/95_a_capitaliser.md (NUC: /srv/projects/_Assistant_Lead_Tech/95_a_capitaliser.md). Format: DATE — __PROJECT_NAME__ / FILE_UPDATE_PROPOSAL / Fichier cible: <40_decisions_et_archi.md | 10_backend_patterns_valides.md | 10_backend_risques_et_vigilance.md> / Pourquoi: / Proposition: . Never write directly to Lead_tech validated files. diff --git a/70_templates/bmad_post_install/memories/core_bmad_master.txt b/70_templates/bmad_post_install/memories/core_bmad_master.txt new file mode 100644 index 0000000..147fce8 --- /dev/null +++ b/70_templates/bmad_post_install/memories/core_bmad_master.txt @@ -0,0 +1 @@ +As the orchestrating agent, when any cross-cutting pattern, process improvement, recurring friction, or architectural decision emerges across the project, write a proposal to ~/AI_RULES/_Assistant_Lead_Tech/95_a_capitaliser.md (NUC: /srv/projects/_Assistant_Lead_Tech/95_a_capitaliser.md). Format: DATE — __PROJECT_NAME__ / FILE_UPDATE_PROPOSAL / Fichier cible: <10_backend_patterns_valides.md | 10_frontend_patterns_valides.md | 10_product_patterns_valides.md | 10_ux_patterns_valides.md | 10_backend_risques_et_vigilance.md | 10_frontend_risques_et_vigilance.md | 40_decisions_et_archi.md | 90_debug_et_postmortem.md> / Pourquoi: / Proposition: . Never write directly to Lead_tech validated files. diff --git a/70_templates/bmad_post_install/memories/dev_implementation.txt b/70_templates/bmad_post_install/memories/dev_implementation.txt new file mode 100644 index 0000000..ccd177d --- /dev/null +++ b/70_templates/bmad_post_install/memories/dev_implementation.txt @@ -0,0 +1 @@ +When a reusable pattern, difficult bug fix, anti-pattern, or architecture decision emerges during implementation, write a proposal to ~/AI_RULES/_Assistant_Lead_Tech/95_a_capitaliser.md (NUC: /srv/projects/_Assistant_Lead_Tech/95_a_capitaliser.md). Format: DATE — __PROJECT_NAME__ / FILE_UPDATE_PROPOSAL / Fichier cible: <10_backend_patterns_valides.md | 10_frontend_patterns_valides.md | 10_backend_risques_et_vigilance.md | 10_frontend_risques_et_vigilance.md | 90_debug_et_postmortem.md> / Pourquoi: / Proposition: . Never write directly to Lead_tech validated files. diff --git a/70_templates/bmad_post_install/memories/pm.txt b/70_templates/bmad_post_install/memories/pm.txt new file mode 100644 index 0000000..97d788c --- /dev/null +++ b/70_templates/bmad_post_install/memories/pm.txt @@ -0,0 +1 @@ +When a product decision, prioritization pattern, or recurring friction is identified, write a proposal to ~/AI_RULES/_Assistant_Lead_Tech/95_a_capitaliser.md (NUC: /srv/projects/_Assistant_Lead_Tech/95_a_capitaliser.md). Format: DATE — __PROJECT_NAME__ / FILE_UPDATE_PROPOSAL / Fichier cible: <10_product_patterns_valides.md | 40_decisions_et_archi.md> / Pourquoi: / Proposition: . Never write directly to Lead_tech validated files. diff --git a/70_templates/bmad_post_install/memories/qa.txt b/70_templates/bmad_post_install/memories/qa.txt new file mode 100644 index 0000000..e0e11e3 --- /dev/null +++ b/70_templates/bmad_post_install/memories/qa.txt @@ -0,0 +1 @@ +When a reusable test pattern, tricky bug, or quality anti-pattern is identified, write a proposal to ~/AI_RULES/_Assistant_Lead_Tech/95_a_capitaliser.md (NUC: /srv/projects/_Assistant_Lead_Tech/95_a_capitaliser.md). Format: DATE — __PROJECT_NAME__ / FILE_UPDATE_PROPOSAL / Fichier cible: / Pourquoi: / Proposition: . Never write directly to Lead_tech validated files. diff --git a/70_templates/bmad_post_install/memories/sm.txt b/70_templates/bmad_post_install/memories/sm.txt new file mode 100644 index 0000000..2dca19b --- /dev/null +++ b/70_templates/bmad_post_install/memories/sm.txt @@ -0,0 +1 @@ +When a process improvement, recurring friction, or architecture decision emerges during sprint work, write a proposal to ~/AI_RULES/_Assistant_Lead_Tech/95_a_capitaliser.md (NUC: /srv/projects/_Assistant_Lead_Tech/95_a_capitaliser.md). Format: DATE — __PROJECT_NAME__ / FILE_UPDATE_PROPOSAL / Fichier cible: / Pourquoi: / Proposition: . Never write directly to Lead_tech validated files. diff --git a/70_templates/bmad_post_install/memories/tech_writer.txt b/70_templates/bmad_post_install/memories/tech_writer.txt new file mode 100644 index 0000000..093283f --- /dev/null +++ b/70_templates/bmad_post_install/memories/tech_writer.txt @@ -0,0 +1 @@ +When a reusable documentation pattern, writing convention, or recurring documentation friction emerges, write a proposal to ~/AI_RULES/_Assistant_Lead_Tech/95_a_capitaliser.md (NUC: /srv/projects/_Assistant_Lead_Tech/95_a_capitaliser.md). Format: DATE — __PROJECT_NAME__ / FILE_UPDATE_PROPOSAL / Fichier cible: <10_conventions_redaction.md | 40_decisions_et_archi.md> / Pourquoi: / Proposition: . Never write directly to Lead_tech validated files. diff --git a/70_templates/bmad_post_install/memories/ux_designer.txt b/70_templates/bmad_post_install/memories/ux_designer.txt new file mode 100644 index 0000000..91bdbe1 --- /dev/null +++ b/70_templates/bmad_post_install/memories/ux_designer.txt @@ -0,0 +1 @@ +When a reusable UX/UI pattern, interaction anti-pattern, or UX decision emerges, write a proposal to ~/AI_RULES/_Assistant_Lead_Tech/95_a_capitaliser.md (NUC: /srv/projects/_Assistant_Lead_Tech/95_a_capitaliser.md). Format: DATE — __PROJECT_NAME__ / FILE_UPDATE_PROPOSAL / Fichier cible: <10_ux_patterns_valides.md | 10_ux_risques_et_vigilance.md | 40_decisions_et_archi.md> / Pourquoi: / Proposition: . Never write directly to Lead_tech validated files. diff --git a/70_templates/bmad_post_install/workflows/code-review-capitalisation.xmlfrag b/70_templates/bmad_post_install/workflows/code-review-capitalisation.xmlfrag new file mode 100644 index 0000000..a753463 --- /dev/null +++ b/70_templates/bmad_post_install/workflows/code-review-capitalisation.xmlfrag @@ -0,0 +1,8 @@ + + You MUST output this section — do NOT skip it silently + ## 🧠 Capitalisation Lead_tech + + Review all findings for: anti-patterns found, recurring issues, architecture decisions confirmed or invalidated during this review. + + For EACH candidate (aim for 1-3): write a proposal to ~/AI_RULES/_Assistant_Lead_Tech/95_a_capitaliser.md ONLY — NEVER inside the project repo. FORMAT = "DATE — __PROJECT_NAME__ / FILE_UPDATE_PROPOSAL / Fichier cible: <target> / Pourquoi: <reason> / Proposition: <content>" + Output explicitly: "Rien à capitaliser pour cette review." — do NOT skip silently diff --git a/70_templates/bmad_post_install/workflows/code-review-checklist.mdfrag b/70_templates/bmad_post_install/workflows/code-review-checklist.mdfrag new file mode 100644 index 0000000..2907b1d --- /dev/null +++ b/70_templates/bmad_post_install/workflows/code-review-checklist.mdfrag @@ -0,0 +1 @@ +- [ ] Capitalisation Lead_tech outputted — proposals written to `95_a_capitaliser.md` OR explicit "Rien à capitaliser" stated diff --git a/70_templates/bmad_post_install/workflows/dev-story-capitalisation.xmlfrag b/70_templates/bmad_post_install/workflows/dev-story-capitalisation.xmlfrag new file mode 100644 index 0000000..bb1bac8 --- /dev/null +++ b/70_templates/bmad_post_install/workflows/dev-story-capitalisation.xmlfrag @@ -0,0 +1,8 @@ + + You MUST output this section — do NOT skip it silently + ## 🧠 Capitalisation Lead_tech + + Review the full implementation for: reusable patterns, difficult bug fixes, anti-patterns, architecture decisions, or subtle nuances discovered during this story. + + For EACH candidate (aim for 1-3): write a proposal to ~/AI_RULES/_Assistant_Lead_Tech/95_a_capitaliser.md ONLY — NEVER inside the project repo. FORMAT = "DATE — __PROJECT_NAME__ / FILE_UPDATE_PROPOSAL / Fichier cible: <target> / Pourquoi: <reason> / Proposition: <content>" + Output explicitly: "Rien à capitaliser pour cette story." — do NOT skip silently diff --git a/70_templates/bmad_post_install/workflows/dev-story-checklist.mdfrag b/70_templates/bmad_post_install/workflows/dev-story-checklist.mdfrag new file mode 100644 index 0000000..6d06498 --- /dev/null +++ b/70_templates/bmad_post_install/workflows/dev-story-checklist.mdfrag @@ -0,0 +1 @@ +- [ ] **Capitalisation Lead_tech:** Section "🧠 Capitalisation Lead_tech" outputted — proposals written to `95_a_capitaliser.md` OR explicit "Rien à capitaliser" stated diff --git a/80_bmad/process_llm_et_parallelisation.md b/80_bmad/process_llm_et_parallelisation.md new file mode 100644 index 0000000..a1558bb --- /dev/null +++ b/80_bmad/process_llm_et_parallelisation.md @@ -0,0 +1,98 @@ +# BMAD — Process LLM et parallélisation + +Ce fichier capitalise les règles opératoires spécifiques au développement BMAD +assisté par LLM quand plusieurs stories, branches ou sessions peuvent avancer +en parallèle. + +Dernière mise à jour : 10-03-2026 + +--- + +## Index + +- [Métadonnées de parallélisation dans le template story](#process-parallel-safe-template-story) +- [Synchronisation obligatoire `.md` ↔ `sprint-status`](#process-sync-story-md-sprint-status) +- [Multi-sessions LLM sur une même story sans handoff](#process-multi-sessions-sans-handoff) + +--- + +## Règle d'or + +Le fichier de story reste la source de vérité partagée entre sessions. +Si l'état réel du code, du `.md` et du sprint diverge, la story n'est pas sous contrôle. + +--- + + +## Convention : métadonnées de parallélisation dans le template story + +- Objectif : rendre explicite si une story peut être développée en parallèle d'une autre. +- Quand l'utiliser : sur tout template de story BMAD utilisé par plusieurs agents ou sessions. +- Avantage : + - réduit les collisions entre branches + - évite les faux parallélismes + - rend les dépendances visibles avant implémentation +- Limites / vigilance : + - `Parallel-safe: true` ne remplace pas une vérification humaine du périmètre réel + +### Champs recommandés + +```txt +Status: ready-for-dev +Parallel-safe: false +Depends-on: ~ +Can-run-with: ~ +``` + +### Règles + +- `Parallel-safe: true` seulement si la story peut avancer sur une branche séparée sans dépendre d'un code non mergé +- `Depends-on` documente une dépendance de code réelle +- `Can-run-with` documente les stories compatibles en exécution parallèle + +--- + + +## Convention : synchronisation obligatoire `.md` ↔ `sprint-status` + +- Objectif : éviter qu'une story soit considérée terminée alors que ses artefacts d'état divergent. +- Quand l'utiliser : sur toute clôture de story. +- Risque si ignoré : + - story marquée `done` dans le sprint mais encore `ready-for-dev` dans son fichier + - reprise erronée par une autre session + +### Règles + +- une story n'est `done` que si son fichier `.md` est à `Status: done` +- `sprint-status.yaml` ne passe à `done` qu'en dernier +- toute divergence `.md` ↔ `sprint-status` doit être traitée comme une anomalie détectable par script + +### Ordre obligatoire + +1. mettre à jour le fichier de story `.md` +2. mettre à jour `sprint-status.yaml` en dernier + +--- + + +## Anti-pattern : multi-sessions LLM sur une même story sans handoff + +### Risques + +- code déjà modifié alors que la story semble encore `ready-for-dev` +- duplication de travail ou écrasement de modifications +- diagnostic faussé par un état documentaire obsolète + +### Symptômes + +- la story indique un état de départ, mais le repo contient déjà l'implémentation partielle +- plusieurs sessions avancent sur la même story sans trace de reprise +- les diffs ne correspondent plus au statut affiché + +### Bonnes pratiques / mitigations + +- une session LLM ne travaille que sur une story active à la fois +- toute reprise commence par la lecture complète du fichier `.md` +- avant d'agir, vérifier la cohérence entre état du code, état du `.md` et état du sprint + +--- diff --git a/90_debug_et_postmortem.md b/90_debug_et_postmortem.md index 51c46c4..0d8c354 100644 --- a/90_debug_et_postmortem.md +++ b/90_debug_et_postmortem.md @@ -67,3 +67,29 @@ Si SQL Server est nécessaire : ### Règle à retenir > Éviter les bases lourdes nécessitant des capabilities système avancées dans des conteneurs LXC. + +--- + +## Suppression silencieuse due à deux éditions concurrentes sur le même fichier + +### Contexte + +Un même fichier a été modifié par deux mécanismes proches dans le temps : +édition en cours d’agent et passe outillée/linter/formatteur. + +### Symptômes + +- bloc de code disparu sans erreur explicite +- diff final incohérent avec l’intention de modification +- impression de “régression fantôme” après une édition pourtant correcte + +### Cause probable + +Deux processus ont réécrit le même fichier sans coordination, le second +écrasant silencieusement une partie du travail du premier. + +### Correctif / règle à retenir + +- éviter deux passes d’écriture concurrentes sur le même fichier +- relire le diff immédiatement après toute passe automatique +- privilégier une séquence stricte : édition, puis lint/format, puis vérification diff --git a/scripts/post-bmad-install.sh b/scripts/post-bmad-install.sh index 28bbbdd..ea02ea8 100755 --- a/scripts/post-bmad-install.sh +++ b/scripts/post-bmad-install.sh @@ -5,16 +5,7 @@ set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" - -# Résolution du chemin Lead_tech (même logique que aliases.sh) -if [ -d "$HOME/AI_RULES/_Assistant_Lead_Tech" ]; then - LEADTECH_PATH="$HOME/AI_RULES/_Assistant_Lead_Tech" -elif [ -d "/srv/projects/_Assistant_Lead_Tech" ]; then - LEADTECH_PATH="/srv/projects/_Assistant_Lead_Tech" -else - echo "Erreur : impossible de localiser le repo Lead_tech." >&2 - exit 1 -fi +TEMPLATES_DIR="$SCRIPT_DIR/../70_templates/bmad_post_install" # Projet courant PROJECT_ROOT="$(pwd)" @@ -22,224 +13,201 @@ PROJECT_NAME="$(basename "$PROJECT_ROOT")" AGENTS_DIR="$PROJECT_ROOT/_bmad/_config/agents" CLAUDE_MD="$PROJECT_ROOT/CLAUDE.md" -if [ ! -d "$AGENTS_DIR" ]; then - echo "Erreur : dossier _bmad/_config/agents/ introuvable dans $PROJECT_ROOT" - echo "Lance ce script depuis la racine d'un projet BMAD installé." - exit 1 -fi - -# Agents à patcher -# Tous les agents susceptibles d'identifier un pattern, anti-pattern ou décision réutilisable -PRODUCER_AGENTS=( - "bmm-dev" - "bmm-architect" - "bmm-sm" - "bmm-qa" - "bmm-quick-flow-solo-dev" - "bmm-analyst" - "bmm-pm" - "bmm-tech-writer" - "bmm-ux-designer" - "tea-tea" - "core-bmad-master" -) - -CAPITALIZE_MARKER="95_a_capitaliser.md" - -patch_agent() { - local agent="$1" - local file="$AGENTS_DIR/${agent}.customize.yaml" - - if [ ! -f "$file" ]; then - return 0 # agent non installé dans ce projet, on skip - fi - - # Idempotent : ne pas injecter si déjà présent - if grep -q "$CAPITALIZE_MARKER" "$file"; then - echo " [skip] $agent — memory déjà présente" - return 0 - fi - - # Injection après la ligne "memories: []" - # Si memories: [] → remplacer par le bloc memories avec la memory - if grep -q "^memories: \[\]" "$file"; then - # Construire la memory adaptée au rôle de l'agent - local memory - memory="$(build_memory "$agent")" - - # Remplacer memories: [] par le bloc injecté - # Utilise awk pour éviter les conflits avec les caractères spéciaux (|, <, >) dans sed - awk -v mem="$memory" ' - /^memories: \[\]/ { print "memories:"; print " - \"" mem "\""; next } - { print } - ' "$file" > "${file}.tmp" && mv "${file}.tmp" "$file" - - echo " [ok] $agent — memory injectée" - else - echo " [warn] $agent — format memories: inattendu, patch manuel requis" - fi -} - -build_memory() { - local agent="$1" - local base="When a reusable pattern, difficult bug fix, anti-pattern, or architecture decision emerges" - - case "$agent" in - bmm-dev|bmm-quick-flow-solo-dev) - echo "${base} during implementation, write a proposal to ~/AI_RULES/_Assistant_Lead_Tech/95_a_capitaliser.md (NUC: /srv/projects/_Assistant_Lead_Tech/95_a_capitaliser.md). Format: DATE — ${PROJECT_NAME} / FILE_UPDATE_PROPOSAL / Fichier cible: <10_backend_patterns_valides.md | 10_frontend_patterns_valides.md | 10_backend_risques_et_vigilance.md | 10_frontend_risques_et_vigilance.md | 90_debug_et_postmortem.md> / Pourquoi: / Proposition: . Never write directly to Lead_tech validated files." - ;; - bmm-architect) - echo "${base} during architecture or technical design, write a proposal to ~/AI_RULES/_Assistant_Lead_Tech/95_a_capitaliser.md (NUC: /srv/projects/_Assistant_Lead_Tech/95_a_capitaliser.md). Format: DATE — ${PROJECT_NAME} / FILE_UPDATE_PROPOSAL / Fichier cible: <40_decisions_et_archi.md | 10_backend_patterns_valides.md | 10_backend_risques_et_vigilance.md> / Pourquoi: / Proposition: . Never write directly to Lead_tech validated files." - ;; - bmm-sm) - echo "When a process improvement, recurring friction, or architecture decision emerges during sprint work, write a proposal to ~/AI_RULES/_Assistant_Lead_Tech/95_a_capitaliser.md (NUC: /srv/projects/_Assistant_Lead_Tech/95_a_capitaliser.md). Format: DATE — ${PROJECT_NAME} / FILE_UPDATE_PROPOSAL / Fichier cible: / Pourquoi: / Proposition: . Never write directly to Lead_tech validated files." - ;; - bmm-qa|tea-tea) - echo "When a reusable test pattern, tricky bug, or quality anti-pattern is identified, write a proposal to ~/AI_RULES/_Assistant_Lead_Tech/95_a_capitaliser.md (NUC: /srv/projects/_Assistant_Lead_Tech/95_a_capitaliser.md). Format: DATE — ${PROJECT_NAME} / FILE_UPDATE_PROPOSAL / Fichier cible: / Pourquoi: / Proposition: . Never write directly to Lead_tech validated files." - ;; - bmm-analyst) - echo "When a reusable analysis pattern, requirements anti-pattern, or domain insight emerges, write a proposal to ~/AI_RULES/_Assistant_Lead_Tech/95_a_capitaliser.md (NUC: /srv/projects/_Assistant_Lead_Tech/95_a_capitaliser.md). Format: DATE — ${PROJECT_NAME} / FILE_UPDATE_PROPOSAL / Fichier cible: <10_product_patterns_valides.md | 10_backend_patterns_valides.md | 40_decisions_et_archi.md> / Pourquoi: / Proposition: . Never write directly to Lead_tech validated files." - ;; - bmm-pm) - echo "When a product decision, prioritization pattern, or recurring friction is identified, write a proposal to ~/AI_RULES/_Assistant_Lead_Tech/95_a_capitaliser.md (NUC: /srv/projects/_Assistant_Lead_Tech/95_a_capitaliser.md). Format: DATE — ${PROJECT_NAME} / FILE_UPDATE_PROPOSAL / Fichier cible: <10_product_patterns_valides.md | 40_decisions_et_archi.md> / Pourquoi: / Proposition: . Never write directly to Lead_tech validated files." - ;; - bmm-ux-designer) - echo "When a reusable UX/UI pattern, interaction anti-pattern, or UX decision emerges, write a proposal to ~/AI_RULES/_Assistant_Lead_Tech/95_a_capitaliser.md (NUC: /srv/projects/_Assistant_Lead_Tech/95_a_capitaliser.md). Format: DATE — ${PROJECT_NAME} / FILE_UPDATE_PROPOSAL / Fichier cible: <10_ux_patterns_valides.md | 10_ux_risques_et_vigilance.md | 40_decisions_et_archi.md> / Pourquoi: / Proposition: . Never write directly to Lead_tech validated files." - ;; - bmm-tech-writer) - echo "When a reusable documentation pattern, writing convention, or recurring documentation friction emerges, write a proposal to ~/AI_RULES/_Assistant_Lead_Tech/95_a_capitaliser.md (NUC: /srv/projects/_Assistant_Lead_Tech/95_a_capitaliser.md). Format: DATE — ${PROJECT_NAME} / FILE_UPDATE_PROPOSAL / Fichier cible: <10_conventions_redaction.md | 40_decisions_et_archi.md> / Pourquoi: / Proposition: . Never write directly to Lead_tech validated files." - ;; - core-bmad-master) - echo "As the orchestrating agent, when any cross-cutting pattern, process improvement, recurring friction, or architectural decision emerges across the project, write a proposal to ~/AI_RULES/_Assistant_Lead_Tech/95_a_capitaliser.md (NUC: /srv/projects/_Assistant_Lead_Tech/95_a_capitaliser.md). Format: DATE — ${PROJECT_NAME} / FILE_UPDATE_PROPOSAL / Fichier cible: <10_backend_patterns_valides.md | 10_frontend_patterns_valides.md | 10_product_patterns_valides.md | 10_ux_patterns_valides.md | 10_backend_risques_et_vigilance.md | 10_frontend_risques_et_vigilance.md | 40_decisions_et_archi.md | 90_debug_et_postmortem.md> / Pourquoi: / Proposition: . Never write directly to Lead_tech validated files." - ;; - esac -} - -CAPITALIZE_MARKER_XML="Capitalisation Lead_tech" DEV_STORY_XML="$PROJECT_ROOT/_bmad/bmm/workflows/4-implementation/dev-story/instructions.xml" CODE_REVIEW_XML="$PROJECT_ROOT/_bmad/bmm/workflows/4-implementation/code-review/instructions.xml" DEV_STORY_CHECKLIST="$PROJECT_ROOT/_bmad/bmm/workflows/4-implementation/dev-story/checklist.md" CODE_REVIEW_CHECKLIST="$PROJECT_ROOT/_bmad/bmm/workflows/4-implementation/code-review/checklist.md" -patch_dev_story() { - local file="$DEV_STORY_XML" +PRODUCER_AGENTS_CONFIG="$TEMPLATES_DIR/config/producer_agents.tsv" +MEMORIES_DIR="$TEMPLATES_DIR/memories" +WORKFLOWS_DIR="$TEMPLATES_DIR/workflows" +CLAUDE_FRAGMENTS_DIR="$TEMPLATES_DIR/claude" + +CAPITALIZE_MARKER="95_a_capitaliser.md" +CAPITALIZE_MARKER_XML="Capitalisation Lead_tech" + +if [ ! -d "$AGENTS_DIR" ]; then + echo "Erreur : dossier _bmad/_config/agents/ introuvable dans $PROJECT_ROOT" >&2 + echo "Lance ce script depuis la racine d'un projet BMAD installé." >&2 + exit 1 +fi + +require_file() { + local file="$1" + if [ ! -f "$file" ]; then + echo "Erreur : fichier requis introuvable : $file" >&2 + exit 1 + fi +} + +escape_sed_replacement() { + printf '%s' "$1" | sed -e 's/[\/&]/\\&/g' +} + +render_template() { + local file="$1" + require_file "$file" + sed "s/__PROJECT_NAME__/$(escape_sed_replacement "$PROJECT_NAME")/g" "$file" +} + +patch_line_after_match() { + local file="$1" + local match="$2" + local fragment_file="$3" if [ ! -f "$file" ]; then - echo " [skip] dev-story/instructions.xml — fichier absent" + echo " [skip] $(basename "$file") — fichier absent" return 0 fi if grep -q "$CAPITALIZE_MARKER_XML" "$file"; then - echo " [skip] dev-story/instructions.xml — capitalisation déjà présente" + echo " [skip] $(basename "$file") — capitalisation déjà présente" return 0 fi - # Insérer le bloc capitalisation juste avant les Final validation gates - awk ' - // { - print " " - print " You MUST output this section \xe2\x80\x94 do NOT skip it silently" - print " ## \xf0\x9f\xa7\xa0 Capitalisation Lead_tech" - print "" - print " Review the full implementation for: reusable patterns, difficult bug fixes, anti-patterns, architecture decisions, or subtle nuances discovered during this story." - print " " - print " For EACH candidate (aim for 1-3): write a proposal to ~/AI_RULES/_Assistant_Lead_Tech/95_a_capitaliser.md ONLY \xe2\x80\x94 NEVER inside the project repo. FORMAT = \"DATE \xe2\x80\x94 '"$PROJECT_NAME"' / FILE_UPDATE_PROPOSAL / Fichier cible: <target> / Pourquoi: <reason> / Proposition: <content>\"" - print " Output explicitly: \"Rien \xc3\xa0 capitaliser pour cette story.\" \xe2\x80\x94 do NOT skip silently" - print "" + local fragment + fragment="$(render_template "$fragment_file")" + + awk -v match="$match" -v block="$fragment" ' + index($0, match) { + print + print block + next } { print } ' "$file" > "${file}.tmp" && mv "${file}.tmp" "$file" - echo " [ok] dev-story/instructions.xml — capitalisation injectée" + echo " [ok] $(basename "$file") — capitalisation injectée" } -patch_code_review() { - local file="$CODE_REVIEW_XML" +patch_block_before_match() { + local file="$1" + local match="$2" + local fragment_file="$3" if [ ! -f "$file" ]; then - echo " [skip] code-review/instructions.xml — fichier absent" + echo " [skip] $(basename "$file") — fichier absent" return 0 fi if grep -q "$CAPITALIZE_MARKER_XML" "$file"; then - echo " [skip] code-review/instructions.xml — capitalisation déjà présente" + echo " [skip] $(basename "$file") — capitalisation déjà présente" return 0 fi - # Insérer le bloc capitalisation après le output "✅ Review Complete!" - awk ' + local fragment + fragment="$(render_template "$fragment_file")" + + awk -v match="$match" -v block="$fragment" ' + index($0, match) { + print block + } + { print } + ' "$file" > "${file}.tmp" && mv "${file}.tmp" "$file" + + echo " [ok] $(basename "$file") — capitalisation injectée" +} + +patch_agent() { + local agent="$1" + local template_name="$2" + local file="$AGENTS_DIR/${agent}.customize.yaml" + local template_file="$MEMORIES_DIR/${template_name}.txt" + + if [ ! -f "$file" ]; then + return 0 + fi + + require_file "$template_file" + + if grep -q "$CAPITALIZE_MARKER" "$file"; then + echo " [skip] $agent — memory déjà présente" + return 0 + fi + + if ! grep -q "^memories: \[\]" "$file"; then + echo " [warn] $agent — format memories: inattendu, patch manuel requis" + return 0 + fi + + local memory + memory="$(render_template "$template_file")" + + awk -v mem="$memory" ' + /^memories: \[\]/ { print "memories:"; print " - \"" mem "\""; next } + { print } + ' "$file" > "${file}.tmp" && mv "${file}.tmp" "$file" + + echo " [ok] $agent — memory injectée" +} + +patch_agents() { + require_file "$PRODUCER_AGENTS_CONFIG" + + while IFS=$'\t' read -r agent template_name; do + if [ -z "${agent:-}" ] || [ "${agent#\#}" != "$agent" ]; then + continue + fi + patch_agent "$agent" "$template_name" + done < "$PRODUCER_AGENTS_CONFIG" +} + +patch_dev_story() { + patch_block_before_match \ + "$DEV_STORY_XML" \ + "" \ + "$WORKFLOWS_DIR/dev-story-capitalisation.xmlfrag" +} + +patch_code_review() { + local file="$CODE_REVIEW_XML" + local fragment_file="$WORKFLOWS_DIR/code-review-capitalisation.xmlfrag" + + if [ ! -f "$file" ]; then + echo " [skip] $(basename "$file") — fichier absent" + return 0 + fi + + if grep -q "$CAPITALIZE_MARKER_XML" "$file"; then + echo " [skip] $(basename "$file") — capitalisation déjà présente" + return 0 + fi + + local fragment + fragment="$(render_template "$fragment_file")" + + awk -v block="$fragment" ' /✅ Review Complete!/ { in_review_complete = 1 } in_review_complete && /<\/output>/ { print print "" - print " " - print " You MUST output this section \xe2\x80\x94 do NOT skip it silently" - print " ## \xf0\x9f\xa7\xa0 Capitalisation Lead_tech" - print "" - print " Review all findings for: anti-patterns found, recurring issues, architecture decisions confirmed or invalidated during this review." - print " " - print " For EACH candidate (aim for 1-3): write a proposal to ~/AI_RULES/_Assistant_Lead_Tech/95_a_capitaliser.md ONLY \xe2\x80\x94 NEVER inside the project repo. FORMAT = \"DATE \xe2\x80\x94 '"$PROJECT_NAME"' / FILE_UPDATE_PROPOSAL / Fichier cible: <target> / Pourquoi: <reason> / Proposition: <content>\"" - print " Output explicitly: \"Rien \xc3\xa0 capitaliser pour cette review.\" \xe2\x80\x94 do NOT skip silently" + print block in_review_complete = 0 next } { print } ' "$file" > "${file}.tmp" && mv "${file}.tmp" "$file" - echo " [ok] code-review/instructions.xml — capitalisation injectée" + echo " [ok] $(basename "$file") — capitalisation injectée" } patch_dev_story_checklist() { - local file="$DEV_STORY_CHECKLIST" - - if [ ! -f "$file" ]; then - echo " [skip] dev-story/checklist.md — fichier absent" - return 0 - fi - - if grep -q "$CAPITALIZE_MARKER_XML" "$file"; then - echo " [skip] dev-story/checklist.md — capitalisation déjà présente" - return 0 - fi - - awk ' - /\*\*User Communication Ready\*\*/ { - print - print "- [ ] **Capitalisation Lead_tech:** Section \"🧠 Capitalisation Lead_tech\" outputted — proposals written to \`95_a_capitaliser.md\` OR explicit \"Rien à capitaliser\" stated" - next - } - { print } - ' "$file" > "${file}.tmp" && mv "${file}.tmp" "$file" - - echo " [ok] dev-story/checklist.md — capitalisation injectée" + patch_line_after_match \ + "$DEV_STORY_CHECKLIST" \ + "**User Communication Ready**" \ + "$WORKFLOWS_DIR/dev-story-checklist.mdfrag" } patch_code_review_checklist() { - local file="$CODE_REVIEW_CHECKLIST" - - if [ ! -f "$file" ]; then - echo " [skip] code-review/checklist.md — fichier absent" - return 0 - fi - - if grep -q "$CAPITALIZE_MARKER_XML" "$file"; then - echo " [skip] code-review/checklist.md — capitalisation déjà présente" - return 0 - fi - - awk ' - /Story saved successfully/ { - print - print "- [ ] Capitalisation Lead_tech outputted — proposals written to \`95_a_capitaliser.md\` OR explicit \"Rien à capitaliser\" stated" - next - } - { print } - ' "$file" > "${file}.tmp" && mv "${file}.tmp" "$file" - - echo " [ok] code-review/checklist.md — capitalisation injectée" + patch_line_after_match \ + "$CODE_REVIEW_CHECKLIST" \ + "Story saved successfully" \ + "$WORKFLOWS_DIR/code-review-checklist.mdfrag" } patch_claude_md() { + local fragment_file="$CLAUDE_FRAGMENTS_DIR/leadtech-capitalisation.mdfrag" + if [ ! -f "$CLAUDE_MD" ]; then echo " [skip] CLAUDE.md — fichier absent" return 0 @@ -250,39 +218,7 @@ patch_claude_md() { return 0 fi - cat >> "$CLAUDE_MD" < - -Pourquoi : - - -Proposition : - -\`\`\` - -Règle : écrire dans \`95_a_capitaliser.md\` uniquement. Jamais directement dans les fichiers Lead_tech validés. -EOF - + render_template "$fragment_file" >> "$CLAUDE_MD" echo " [ok] CLAUDE.md — section capitalisation ajoutée" } @@ -291,12 +227,11 @@ echo "" echo "post-bmad-install — injection Lead_tech capitalisation" echo "Projet : $PROJECT_NAME ($PROJECT_ROOT)" echo "Agents : $AGENTS_DIR" +echo "Templates : $TEMPLATES_DIR" echo "" echo "Patch agents :" -for agent in "${PRODUCER_AGENTS[@]}"; do - patch_agent "$agent" -done +patch_agents echo "" echo "Patch workflows :"