mirror of
https://github.com/MaksTinyWorkshop/_Assistant_Lead_Tech
synced 2026-04-06 13:31:43 +02:00
Capitalise nouveaux patterns backend/frontend/BMAD et externalise les templates du post-install BMAD
This commit is contained in:
@@ -142,6 +142,11 @@ Dossier :
|
|||||||
80_bmad/
|
80_bmad/
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Fichiers principaux :
|
||||||
|
|
||||||
|
- `80_bmad/articulation_avec_lead_tech.md`
|
||||||
|
- `80_bmad/process_llm_et_parallelisation.md`
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Debug et post‑mortems
|
## Debug et post‑mortems
|
||||||
|
|||||||
@@ -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.
|
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)
|
- [Stripe — metadata sur `subscription_data`, pas sur la Session](#pattern-stripe-subscription-metadata)
|
||||||
- [Webhooks entrants — parsing unique (single constructWebhookEvent)](#pattern-webhook-parsing-unique)
|
- [Webhooks entrants — parsing unique (single constructWebhookEvent)](#pattern-webhook-parsing-unique)
|
||||||
- [Contracts-First — error codes comme contrat obligatoire](#pattern-contracts-error-codes)
|
- [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
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
<a id="pattern-redis-health-cache-court"></a>
|
||||||
|
## 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
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<a id="pattern-subscription-trial-vs-paid"></a>
|
||||||
|
## 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
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<a id="pattern-restauration-achats-stripe"></a>
|
||||||
|
## 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
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<a id="pattern-prisma-p2002-update-unique"></a>
|
||||||
|
## 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
|
### Notes importantes
|
||||||
|
|
||||||
- On préfère 5 patterns solides à 50 “bons conseils”.
|
- On préfère 5 patterns solides à 50 “bons conseils”.
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ Ce fichier recense des risques back-end susceptibles de provoquer :
|
|||||||
- régressions coûteuses,
|
- régressions coûteuses,
|
||||||
- incohérences de données.
|
- 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)
|
- [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)
|
- [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)
|
- [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
|
- 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)
|
- Évolutif vers Prometheus/OTel sans changer l'interface (abstraction dès le départ)
|
||||||
- Contexte technique : Redis / NestJS — 09-03-2026
|
- Contexte technique : Redis / NestJS — 09-03-2026
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<a id="risque-interface-provider-incomplete"></a>
|
||||||
|
## 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
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<a id="risque-upsert-n-plus-un-provider"></a>
|
||||||
|
## 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
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<a id="risque-stripe-list-has-more"></a>
|
||||||
|
## 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
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<a id="risque-trial-payant-concurrence"></a>
|
||||||
|
## 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
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<a id="risque-jest-clearallmocks-imbrique"></a>
|
||||||
|
## `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
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ Ce fichier recense des risques front-end susceptibles de provoquer :
|
|||||||
- dette technique rapide,
|
- dette technique rapide,
|
||||||
- régressions UX/perf/a11y.
|
- 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)
|
- [Performances : sur-renders + bundle](#risque-performances-sur-renders)
|
||||||
- [Accessibilité oubliée (a11y)](#risque-accessibilite-oubliee)
|
- [Accessibilité oubliée (a11y)](#risque-accessibilite-oubliee)
|
||||||
- [Catch silencieux — erreur inconnue sans feedback utilisateur](#risque-catch-silencieux)
|
- [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.
|
- **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
|
- Contexte technique : React Native / Expo — 09-03-2026
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<a id="risque-auto-reset-etat-degrade"></a>
|
||||||
|
## 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
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<a id="risque-refresh-store-fire-and-forget"></a>
|
||||||
|
## 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
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ Objectifs :
|
|||||||
- éviter de reposer les mêmes questions
|
- éviter de reposer les mêmes questions
|
||||||
- assumer les compromis
|
- 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 front-end est un logiciel en production](#decision-frontend-production)
|
||||||
- [Le back-end est un logiciel en production](#decision-backend-production)
|
- [Le back-end est un logiciel en production](#decision-backend-production)
|
||||||
- [Contrats d’API explicites et versionnés](#decision-contrats-api)
|
- [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)
|
- [Gestion standard des erreurs et des statuts HTTP](#decision-erreurs-http)
|
||||||
- [Migrations et évolution de schéma maîtrisées](#decision-migrations)
|
- [Migrations et évolution de schéma maîtrisées](#decision-migrations)
|
||||||
- [Observabilité minimale obligatoire](#decision-observabilite)
|
- [Observabilité minimale obligatoire](#decision-observabilite)
|
||||||
@@ -301,6 +303,89 @@ Minimum attendu :
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
<a id="decision-contrats-sso-zod"></a>
|
||||||
|
## 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é
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<a id="decision-user-views"></a>
|
||||||
|
## 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<User, "password">`) 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
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
<a id="decision-erreurs-http"></a>
|
<a id="decision-erreurs-http"></a>
|
||||||
## Gestion standard des erreurs et des statuts HTTP
|
## Gestion standard des erreurs et des statuts HTTP
|
||||||
|
|
||||||
|
|||||||
@@ -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 :
|
||||||
|
<raison en 1-2 phrases>
|
||||||
|
|
||||||
|
Proposition :
|
||||||
|
<contenu suggéré>
|
||||||
|
```
|
||||||
|
|
||||||
|
Règle : écrire dans `95_a_capitaliser.md` uniquement. Jamais directement dans les fichiers Lead_tech validés.
|
||||||
11
70_templates/bmad_post_install/config/producer_agents.tsv
Normal file
11
70_templates/bmad_post_install/config/producer_agents.tsv
Normal file
@@ -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
|
||||||
|
1
70_templates/bmad_post_install/memories/analyst.txt
Normal file
1
70_templates/bmad_post_install/memories/analyst.txt
Normal file
@@ -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: <reason> / Proposition: <content>. Never write directly to Lead_tech validated files.
|
||||||
1
70_templates/bmad_post_install/memories/architect.txt
Normal file
1
70_templates/bmad_post_install/memories/architect.txt
Normal file
@@ -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: <reason> / Proposition: <content>. Never write directly to Lead_tech validated files.
|
||||||
@@ -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: <reason> / Proposition: <content>. Never write directly to Lead_tech validated files.
|
||||||
@@ -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: <reason> / Proposition: <content>. Never write directly to Lead_tech validated files.
|
||||||
1
70_templates/bmad_post_install/memories/pm.txt
Normal file
1
70_templates/bmad_post_install/memories/pm.txt
Normal file
@@ -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: <reason> / Proposition: <content>. Never write directly to Lead_tech validated files.
|
||||||
1
70_templates/bmad_post_install/memories/qa.txt
Normal file
1
70_templates/bmad_post_install/memories/qa.txt
Normal file
@@ -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: <target file> / Pourquoi: <reason> / Proposition: <content>. Never write directly to Lead_tech validated files.
|
||||||
1
70_templates/bmad_post_install/memories/sm.txt
Normal file
1
70_templates/bmad_post_install/memories/sm.txt
Normal file
@@ -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: <target file> / Pourquoi: <reason> / Proposition: <content>. Never write directly to Lead_tech validated files.
|
||||||
1
70_templates/bmad_post_install/memories/tech_writer.txt
Normal file
1
70_templates/bmad_post_install/memories/tech_writer.txt
Normal file
@@ -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: <reason> / Proposition: <content>. Never write directly to Lead_tech validated files.
|
||||||
1
70_templates/bmad_post_install/memories/ux_designer.txt
Normal file
1
70_templates/bmad_post_install/memories/ux_designer.txt
Normal file
@@ -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: <reason> / Proposition: <content>. Never write directly to Lead_tech validated files.
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
<!-- Capitalisation Lead_tech -->
|
||||||
|
<critical>You MUST output this section — do NOT skip it silently</critical>
|
||||||
|
<output>## 🧠 Capitalisation Lead_tech
|
||||||
|
|
||||||
|
Review all findings for: anti-patterns found, recurring issues, architecture decisions confirmed or invalidated during this review.
|
||||||
|
</output>
|
||||||
|
<action>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>"</action>
|
||||||
|
<action if="nothing worth capitalizing">Output explicitly: "Rien à capitaliser pour cette review." — do NOT skip silently</action>
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
- [ ] Capitalisation Lead_tech outputted — proposals written to `95_a_capitaliser.md` OR explicit "Rien à capitaliser" stated
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
<!-- Capitalisation Lead_tech -->
|
||||||
|
<critical>You MUST output this section — do NOT skip it silently</critical>
|
||||||
|
<output>## 🧠 Capitalisation Lead_tech
|
||||||
|
|
||||||
|
Review the full implementation for: reusable patterns, difficult bug fixes, anti-patterns, architecture decisions, or subtle nuances discovered during this story.
|
||||||
|
</output>
|
||||||
|
<action>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>"</action>
|
||||||
|
<action if="nothing worth capitalizing">Output explicitly: "Rien à capitaliser pour cette story." — do NOT skip silently</action>
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
- [ ] **Capitalisation Lead_tech:** Section "🧠 Capitalisation Lead_tech" outputted — proposals written to `95_a_capitaliser.md` OR explicit "Rien à capitaliser" stated
|
||||||
98
80_bmad/process_llm_et_parallelisation.md
Normal file
98
80_bmad/process_llm_et_parallelisation.md
Normal file
@@ -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.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<a id="process-parallel-safe-template-story"></a>
|
||||||
|
## 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
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<a id="process-sync-story-md-sprint-status"></a>
|
||||||
|
## 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
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<a id="process-multi-sessions-sans-handoff"></a>
|
||||||
|
## 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
|
||||||
|
|
||||||
|
---
|
||||||
@@ -67,3 +67,29 @@ Si SQL Server est nécessaire :
|
|||||||
### Règle à retenir
|
### Règle à retenir
|
||||||
|
|
||||||
> Éviter les bases lourdes nécessitant des capabilities système avancées dans des conteneurs LXC.
|
> É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
|
||||||
|
|||||||
@@ -5,16 +5,7 @@
|
|||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
TEMPLATES_DIR="$SCRIPT_DIR/../70_templates/bmad_post_install"
|
||||||
# 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
|
|
||||||
|
|
||||||
# Projet courant
|
# Projet courant
|
||||||
PROJECT_ROOT="$(pwd)"
|
PROJECT_ROOT="$(pwd)"
|
||||||
@@ -22,224 +13,201 @@ PROJECT_NAME="$(basename "$PROJECT_ROOT")"
|
|||||||
AGENTS_DIR="$PROJECT_ROOT/_bmad/_config/agents"
|
AGENTS_DIR="$PROJECT_ROOT/_bmad/_config/agents"
|
||||||
CLAUDE_MD="$PROJECT_ROOT/CLAUDE.md"
|
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: <reason> / Proposition: <content>. 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: <reason> / Proposition: <content>. 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: <target file> / Pourquoi: <reason> / Proposition: <content>. 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: <target file> / Pourquoi: <reason> / Proposition: <content>. 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: <reason> / Proposition: <content>. 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: <reason> / Proposition: <content>. 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: <reason> / Proposition: <content>. 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: <reason> / Proposition: <content>. 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: <reason> / Proposition: <content>. 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"
|
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"
|
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"
|
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"
|
CODE_REVIEW_CHECKLIST="$PROJECT_ROOT/_bmad/bmm/workflows/4-implementation/code-review/checklist.md"
|
||||||
|
|
||||||
patch_dev_story() {
|
PRODUCER_AGENTS_CONFIG="$TEMPLATES_DIR/config/producer_agents.tsv"
|
||||||
local file="$DEV_STORY_XML"
|
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
|
if [ ! -f "$file" ]; then
|
||||||
echo " [skip] dev-story/instructions.xml — fichier absent"
|
echo " [skip] $(basename "$file") — fichier absent"
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if grep -q "$CAPITALIZE_MARKER_XML" "$file"; then
|
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
|
return 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Insérer le bloc capitalisation juste avant les Final validation gates
|
local fragment
|
||||||
awk '
|
fragment="$(render_template "$fragment_file")"
|
||||||
/<!-- Final validation gates -->/ {
|
|
||||||
print " <!-- Capitalisation Lead_tech -->"
|
awk -v match="$match" -v block="$fragment" '
|
||||||
print " <critical>You MUST output this section \xe2\x80\x94 do NOT skip it silently</critical>"
|
index($0, match) {
|
||||||
print " <output>## \xf0\x9f\xa7\xa0 Capitalisation Lead_tech"
|
print
|
||||||
print ""
|
print block
|
||||||
print " Review the full implementation for: reusable patterns, difficult bug fixes, anti-patterns, architecture decisions, or subtle nuances discovered during this story."
|
next
|
||||||
print " </output>"
|
|
||||||
print " <action>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>\"</action>"
|
|
||||||
print " <action if=\"nothing worth capitalizing\">Output explicitly: \"Rien \xc3\xa0 capitaliser pour cette story.\" \xe2\x80\x94 do NOT skip silently</action>"
|
|
||||||
print ""
|
|
||||||
}
|
}
|
||||||
{ print }
|
{ print }
|
||||||
' "$file" > "${file}.tmp" && mv "${file}.tmp" "$file"
|
' "$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() {
|
patch_block_before_match() {
|
||||||
local file="$CODE_REVIEW_XML"
|
local file="$1"
|
||||||
|
local match="$2"
|
||||||
|
local fragment_file="$3"
|
||||||
|
|
||||||
if [ ! -f "$file" ]; then
|
if [ ! -f "$file" ]; then
|
||||||
echo " [skip] code-review/instructions.xml — fichier absent"
|
echo " [skip] $(basename "$file") — fichier absent"
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if grep -q "$CAPITALIZE_MARKER_XML" "$file"; then
|
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
|
return 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Insérer le bloc capitalisation après le output "✅ Review Complete!"
|
local fragment
|
||||||
awk '
|
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" \
|
||||||
|
"<!-- Final validation gates -->" \
|
||||||
|
"$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 }
|
/✅ Review Complete!/ { in_review_complete = 1 }
|
||||||
in_review_complete && /<\/output>/ {
|
in_review_complete && /<\/output>/ {
|
||||||
print
|
print
|
||||||
print ""
|
print ""
|
||||||
print " <!-- Capitalisation Lead_tech -->"
|
print block
|
||||||
print " <critical>You MUST output this section \xe2\x80\x94 do NOT skip it silently</critical>"
|
|
||||||
print " <output>## \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 " </output>"
|
|
||||||
print " <action>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>\"</action>"
|
|
||||||
print " <action if=\"nothing worth capitalizing\">Output explicitly: \"Rien \xc3\xa0 capitaliser pour cette review.\" \xe2\x80\x94 do NOT skip silently</action>"
|
|
||||||
in_review_complete = 0
|
in_review_complete = 0
|
||||||
next
|
next
|
||||||
}
|
}
|
||||||
{ print }
|
{ print }
|
||||||
' "$file" > "${file}.tmp" && mv "${file}.tmp" "$file"
|
' "$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() {
|
patch_dev_story_checklist() {
|
||||||
local file="$DEV_STORY_CHECKLIST"
|
patch_line_after_match \
|
||||||
|
"$DEV_STORY_CHECKLIST" \
|
||||||
if [ ! -f "$file" ]; then
|
"**User Communication Ready**" \
|
||||||
echo " [skip] dev-story/checklist.md — fichier absent"
|
"$WORKFLOWS_DIR/dev-story-checklist.mdfrag"
|
||||||
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_code_review_checklist() {
|
patch_code_review_checklist() {
|
||||||
local file="$CODE_REVIEW_CHECKLIST"
|
patch_line_after_match \
|
||||||
|
"$CODE_REVIEW_CHECKLIST" \
|
||||||
if [ ! -f "$file" ]; then
|
"Story saved successfully" \
|
||||||
echo " [skip] code-review/checklist.md — fichier absent"
|
"$WORKFLOWS_DIR/code-review-checklist.mdfrag"
|
||||||
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_claude_md() {
|
patch_claude_md() {
|
||||||
|
local fragment_file="$CLAUDE_FRAGMENTS_DIR/leadtech-capitalisation.mdfrag"
|
||||||
|
|
||||||
if [ ! -f "$CLAUDE_MD" ]; then
|
if [ ! -f "$CLAUDE_MD" ]; then
|
||||||
echo " [skip] CLAUDE.md — fichier absent"
|
echo " [skip] CLAUDE.md — fichier absent"
|
||||||
return 0
|
return 0
|
||||||
@@ -250,39 +218,7 @@ patch_claude_md() {
|
|||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
cat >> "$CLAUDE_MD" <<EOF
|
render_template "$fragment_file" >> "$CLAUDE_MD"
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
# 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 :
|
|
||||||
<raison en 1-2 phrases>
|
|
||||||
|
|
||||||
Proposition :
|
|
||||||
<contenu suggéré>
|
|
||||||
\`\`\`
|
|
||||||
|
|
||||||
Règle : écrire dans \`95_a_capitaliser.md\` uniquement. Jamais directement dans les fichiers Lead_tech validés.
|
|
||||||
EOF
|
|
||||||
|
|
||||||
echo " [ok] CLAUDE.md — section capitalisation ajoutée"
|
echo " [ok] CLAUDE.md — section capitalisation ajoutée"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -291,12 +227,11 @@ echo ""
|
|||||||
echo "post-bmad-install — injection Lead_tech capitalisation"
|
echo "post-bmad-install — injection Lead_tech capitalisation"
|
||||||
echo "Projet : $PROJECT_NAME ($PROJECT_ROOT)"
|
echo "Projet : $PROJECT_NAME ($PROJECT_ROOT)"
|
||||||
echo "Agents : $AGENTS_DIR"
|
echo "Agents : $AGENTS_DIR"
|
||||||
|
echo "Templates : $TEMPLATES_DIR"
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
echo "Patch agents :"
|
echo "Patch agents :"
|
||||||
for agent in "${PRODUCER_AGENTS[@]}"; do
|
patch_agents
|
||||||
patch_agent "$agent"
|
|
||||||
done
|
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
echo "Patch workflows :"
|
echo "Patch workflows :"
|
||||||
|
|||||||
Reference in New Issue
Block a user