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
+
+ 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
+
+ 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 " "
- 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 " "
- 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 :"