[{"data":1,"prerenderedAt":17345},["ShallowReactive",2],{"search-api":-1,"listing-tag-claude-code-page-1":3},[4,836,1746,4024,9193,14960],{"_path":5,"_dir":6,"_draft":7,"_partial":7,"_locale":8,"title":9,"description":10,"id":11,"date":12,"listed":13,"nocomments":7,"hidden":13,"categories":14,"tags":15,"cover":21,"readingTime":22,"body":27,"_type":830,"_id":831,"_source":832,"_file":833,"_stem":834,"_extension":835},"/fr/intelligence-artificielle/recap-5-pieges-claude-semaine-1","intelligence-artificielle",false,"","5 pièges Claude que j'ai vus tuer la qualité du code en 2026 : le récap","Synthèse des 5 pièges Claude que je vois revenir dans crmcoaching et dans les accompagnements que je mène depuis 2024, et les contre-patterns craft pour les neutraliser.",68,"2026-05-22",true,[6],[16,17,18,19,20],"claude-code","recap","software-craftsmanship","ia","best-practices","covers/articles/recap-5-pieges-claude-semaine-1.jpg",{"text":23,"minutes":24,"time":25,"words":26},"13 min read",12.755,765300,2551,{"type":28,"children":29,"toc":816},"root",[30,42,47,51,58,63,77,91,119,122,128,141,154,157,163,177,190,193,199,204,225,228,241,244,250,255,268,271,277,282,303,306,312,322,343,346,352,357,378,383,386,392,397,627,632,635,641,646,651,656,671,683,686,692,715,728,741,754,767,801,804],{"type":31,"tag":32,"props":33,"children":34},"element","p",{},[35],{"type":31,"tag":36,"props":37,"children":38},"strong",{},[39],{"type":40,"value":41},"text","Pendant une semaine, j'ai publié sur ce blog 6 articles consacrés à un seul sujet : les pièges silencieux que Claude installe dans nos codebases en 2026, et les contre-patterns craft pour les neutraliser. L'audience a réagi en messages, en commentaires, en partages internes. Synthèse en une page, avec les pointeurs pour creuser chaque piège et la ligne directrice pour la suite.",{"type":31,"tag":32,"props":43,"children":44},{},[45],{"type":40,"value":46},"À lire d'une traite, même sans avoir vu aucun des 6 articles précédents. Vous repartez avec la carte complète, les contre-patterns nommés, et les pointeurs vers la profondeur de chaque sujet.",{"type":31,"tag":48,"props":49,"children":50},"hr",{},[],{"type":31,"tag":52,"props":53,"children":55},"h2",{"id":54},"pourquoi-cette-série",[56],{"type":40,"value":57},"Pourquoi cette série",{"type":31,"tag":32,"props":59,"children":60},{},[61],{"type":40,"value":62},"J'ai commencé cette série en construisant crmcoaching seul avec Claude, et en accompagnant des indépendants et des équipes sur des projets similaires. Au fil des sessions, les mêmes patterns revenaient. Les mêmes phrases en post-mortem. Les mêmes métriques trompeuses sur les tableaux de bord.",{"type":31,"tag":32,"props":64,"children":65},{},[66,68,75],{"type":40,"value":67},"Le constat de fond est documenté par le DORA Accelerate Report 2024 et le GitClear AI Copilot Code Quality Report 2024. Les équipes qui utilisent intensivement Claude livrent plus de code, mais accumulent silencieusement de la dette de qualité et de la dette éthique. Les chiffres sont là : throughput +35%, mais change failure rate +19% et lead time fix +27%. Le problème n'est pas l'outil, mais une discipline humaine restée à l'ère pré-IA. C'est le fond de mon ",{"type":31,"tag":69,"props":70,"children":72},"a",{"href":71},"/fr/intelligence-artificielle/ia-code-review-retour-experience",[73],{"type":40,"value":74},"retour d'expérience sur la code review IA",{"type":40,"value":76},".",{"type":31,"tag":78,"props":79,"children":80},"blockquote",{},[81],{"type":31,"tag":32,"props":82,"children":83},{},[84,89],{"type":31,"tag":36,"props":85,"children":86},{},[87],{"type":40,"value":88},"Ce que j'ai voulu transmettre",{"type":40,"value":90}," : ni un procès de Claude, ni une nostalgie du code 100% humain, ni du dogme craft hors-sol. Plutôt une boîte à outils concrète : 5 pièges nommés, 5 contre-patterns testables, et une éthique professionnelle en 4 engagements. L'objectif : que vous arriviez lundi matin avec une grille de review actualisée, pas juste une frustration de fin de semaine.",{"type":31,"tag":32,"props":92,"children":93},{},[94,96,102,104,109,111,117],{"type":40,"value":95},"Robert C. Martin a écrit dans ",{"type":31,"tag":97,"props":98,"children":99},"em",{},[100],{"type":40,"value":101},"Clean Code",{"type":40,"value":103}," (2008) que ",{"type":31,"tag":97,"props":105,"children":106},{},[107],{"type":40,"value":108},"\"the only valid measurement of code quality is WTFs per minute.\"",{"type":40,"value":110}," Le craft que je défends sur ce blog s'appuie largement sur cet héritage, comme je le détaille dans l'article fondateur sur les ",{"type":31,"tag":69,"props":112,"children":114},{"href":113},"/fr/dette-technique/clean-code-software-craftsmanship-principes-java",[115],{"type":40,"value":116},"principes Clean Code et software craftsmanship",{"type":40,"value":118},". Cette série visait à diminuer les WTF par minute dans les revues de PR Claude. Voici la synthèse, jour par jour.",{"type":31,"tag":48,"props":120,"children":121},{},[],{"type":31,"tag":52,"props":123,"children":125},{"id":124},"lundi-le-bug-invisible",[126],{"type":40,"value":127},"Lundi - le bug invisible",{"type":31,"tag":32,"props":129,"children":130},{},[131,133,139],{"type":40,"value":132},"Le piège : Claude écrit régulièrement des race conditions silencieuses dans les fonctions qui font lecture/écriture sur de l'état partagé (base de données, cache, queue de jobs). L'exemple concret que je détaille dans l'article sur ",{"type":31,"tag":69,"props":134,"children":136},{"href":135},"/fr/intelligence-artificielle/bug-claude-vendredi-dernier",[137],{"type":40,"value":138},"le bug que Claude vous a fait coder vendredi dernier",{"type":40,"value":140},", c'est la double-réservation de créneau dans le bounded context slot-hold de crmcoaching : Claude génère une fonction qui vérifie la disponibilité, puis écrit la réservation en deux étapes séparées. Tests verts. Prod cassée dès la première exécution concurrente à l'ouverture des inscriptions.",{"type":31,"tag":32,"props":142,"children":143},{},[144,146,152],{"type":40,"value":145},"Le contre-pattern craft tient en 4 garde-fous appliqués systématiquement en review : nommer explicitement la concurrence, utiliser une transaction atomique, typer les exceptions, et écrire un test de concurrence explicite. Cette grille prend 3 minutes par PR. Elle attrape 90% des bugs de concurrence que j'ai vus passer en prod sur des codebases IA-heavy. Elle s'inscrit dans la discipline plus large d'une ",{"type":31,"tag":69,"props":147,"children":149},{"href":148},"/fr/dette-technique/revue-de-code-java-guide-exemples",[150],{"type":40,"value":151},"revue de code structurée",{"type":40,"value":153}," qui doit s'adapter à l'ère IA, et elle complète directement les patterns de résilience type circuit breaker et retry que j'ai détaillés ailleurs sur le blog.",{"type":31,"tag":48,"props":155,"children":156},{},[],{"type":31,"tag":52,"props":158,"children":160},{"id":159},"mardi-les-5-anti-patterns-silencieux",[161],{"type":40,"value":162},"Mardi - les 5 anti-patterns silencieux",{"type":31,"tag":32,"props":164,"children":165},{},[166,168,175],{"type":40,"value":167},"Le deuxième piège est plus large : Claude reproduit en silence 5 anti-patterns issus de son training data. La God Function de 80 lignes. Le couplage métier directement à l'ORM, qui rend les tests unitaires impossibles. Les tests qui ne testent rien (du ",{"type":31,"tag":169,"props":170,"children":172},"code",{"className":171},[],[173],{"type":40,"value":174},"expect(...).toHaveBeenCalled()",{"type":40,"value":176}," sans vérification de comportement métier). Le catch-all silencieux qui masque les bugs au lieu de les remonter. Et les dépendances non auditées, qui ouvrent la porte aux vulnérabilités de sécurité dans le code généré par LLM.",{"type":31,"tag":32,"props":178,"children":179},{},[180,182,188],{"type":40,"value":181},"L'analyse complète, avec les signaux d'alerte et les contre-patterns nommés (Single Responsibility Principle, architecture hexagonale, Acceptance Criteria, exceptions typées, Dependabot configuré craft), est dans l'article sur les ",{"type":31,"tag":69,"props":183,"children":185},{"href":184},"/fr/intelligence-artificielle/5-patterns-dangereux-claude",[186],{"type":40,"value":187},"5 anti-patterns que Claude reproduit en silence",{"type":40,"value":189},". Cette grille en 5 lignes se colle directement sur le PR template GitHub, et elle attrape 80% de ce que la review rapide laisse passer.",{"type":31,"tag":48,"props":191,"children":192},{},[],{"type":31,"tag":52,"props":194,"children":196},{"id":195},"mercredi-tests-verts-prod-rouge",[197],{"type":40,"value":198},"Mercredi - tests verts, prod rouge",{"type":31,"tag":32,"props":200,"children":201},{},[202],{"type":40,"value":203},"Le troisième piège est celui qui fait perdre le plus de nuits : les tests Claude couvrent le happy path, passent la CI, et ratent systématiquement les 4 modes d'échec qui font vraiment planter la prod. La concurrence à 2h du matin. Le rate limit Brevo qui renvoie un 429 lors d'un envoi d'emails en masse depuis le bounded context notification. Le timeout réseau silencieux. Le partial failure où la moitié d'une opération est exécutée et l'autre pas. Aucun de ces 4 tests n'est généré spontanément par Claude.",{"type":31,"tag":32,"props":205,"children":206},{},[207,209,215,217,223],{"type":40,"value":208},"Le contre-pattern craft consiste à exiger explicitement ces 4 tests sur toute fonction qui touche à une dépendance externe (réseau, base de données, queue, file system). J'ai détaillé le scénario complet, le pipeline de tests à 3 étages et le ROI mesuré dans l'article sur ",{"type":31,"tag":69,"props":210,"children":212},{"href":211},"/fr/intelligence-artificielle/code-claude-tests-passent-plante-prod",[213],{"type":40,"value":214},"le code Claude dont les tests passent mais qui plante en prod",{"type":40,"value":216},". Cette discipline s'inscrit dans une Definition of Done qui pose les bons critères de qualité, et complète la ",{"type":31,"tag":69,"props":218,"children":220},{"href":219},"/fr/intelligence-artificielle/tester-code-genere-ia-checklist",[221],{"type":40,"value":222},"checklist pour tester du code généré par IA",{"type":40,"value":224}," que j'avais publiée en 2025.",{"type":31,"tag":48,"props":226,"children":227},{},[],{"type":31,"tag":229,"props":230,"children":235},"cta",{"cta":231,"href":232,"title":233,"type":234},"Coder comme un senior →","https://app.kamanga.fr/forms/mentoring","Vous voulez acquérir le réflexe qui repère ces pièges Claude avant le merge ?","call",[236],{"type":31,"tag":32,"props":237,"children":238},{},[239],{"type":40,"value":240},"Repérer une race condition ou un test qui ne teste rien dans une PR générée par Claude, ça ne s'apprend pas en lisant une grille : ça se travaille sur du vrai code. En mentoring 1:1, je relis vos PR avec vous, on applique les contre-patterns ensemble, et vous installez ces garde-fous comme un réflexe durable. Vous commencez à voir ce que le modèle ne voit pas.",{"type":31,"tag":48,"props":242,"children":243},{},[],{"type":31,"tag":52,"props":245,"children":247},{"id":246},"jeudi-le-faux-ami",[248],{"type":40,"value":249},"Jeudi - le faux ami",{"type":31,"tag":32,"props":251,"children":252},{},[253],{"type":40,"value":254},"Le quatrième piège est plus insidieux parce qu'il ne fait rien planter. Le code Claude \"qui marche\" cache 3 faux amis qui coûtent cher à 3 et 6 mois. Le copier-coller invisible, où Claude reproduit une fonction au lieu de réutiliser celle qui existe déjà ailleurs dans le repo. Par exemple dans crmcoaching, la logique de validation d'une offre se retrouve dupliquée entre le bounded context lead et le bounded context client, deux copies qui divergent silencieusement. Les abstractions accidentelles, avec une interface et une factory pour une seule implémentation. La sur-ingénierie déguisée, avec handler, bus et ports hexagonaux pour ce qui devrait être un SELECT trivial. Ensemble, ces 3 faux amis gonflent les codebases sans ajouter de valeur métier.",{"type":31,"tag":32,"props":256,"children":257},{},[258,260,266],{"type":40,"value":259},"Le contre-pattern, c'est la règle YAGNI étendue à l'ère IA, déclinée en 4 points dans l'article sur ",{"type":31,"tag":69,"props":261,"children":263},{"href":262},"/fr/intelligence-artificielle/faux-ami-code-claude-coute-cher",[264],{"type":40,"value":265},"le code Claude qui marche mais qui coûte cher",{"type":40,"value":267},". Pas d'abstraction sans 3 implémentations réelles (la règle des 3 de Martin Fowler). Prompter Claude pour \"cherche les doublons avant de finaliser\". Proportionnalité entre la complexité du code et la complexité du domaine. Cette discipline rejoint directement les fondamentaux du clean code appliqués au code IA-généré, et c'est aussi un angle business : le craft n'est pas une dépense, c'est un levier d'économie composée.",{"type":31,"tag":48,"props":269,"children":270},{},[],{"type":31,"tag":52,"props":272,"children":274},{"id":273},"vendredi-lillusion-de-productivité",[275],{"type":40,"value":276},"Vendredi - l'illusion de productivité",{"type":31,"tag":32,"props":278,"children":279},{},[280],{"type":40,"value":281},"Le cinquième piège est celui que les COMEX adorent et que les PO redoutent : la productivité affichée. Le throughput IA grimpe de 35% à 89% en moyenne, c'est mesurable et visible. Pendant ce temps, les vraies features mettent plus de temps à arriver en prod et les incidents augmentent. Les deux observations sont vraies. Ce qui ment, c'est la métrique unique \"PR mergées par sprint\", qui compte l'activité au lieu de mesurer le résultat.",{"type":31,"tag":32,"props":283,"children":284},{},[285,287,293,295,301],{"type":40,"value":286},"Le contre-pattern craft consiste à abandonner les 4 métriques qui mentent (lignes de code, PR mergées, story points, tickets fermés) et à adopter les 4 métriques DORA (lead time, deployment frequency, change failure rate, MTTR) plus une 5ème métrique méta : le ratio ADR pour 100 commits. C'est ce que je détaille dans l'article sur ",{"type":31,"tag":69,"props":288,"children":290},{"href":289},"/fr/intelligence-artificielle/illusion-productivite-10x-pr",[291],{"type":40,"value":292},"l'illusion des 10x plus de PR",{"type":40,"value":294},", avec le tableau comparatif \"sans Claude / avec Claude non piloté / avec Claude piloté\". Cette grille à 5 indicateurs est aussi le socle d'une ",{"type":31,"tag":69,"props":296,"children":298},{"href":297},"/fr/management/metriques-management-developpeurs-motivation",[299],{"type":40,"value":300},"bonne pratique des métriques de management des développeurs",{"type":40,"value":302},", et c'est exactement la lecture qui permet à un CTO de décider sereinement comment évaluer Claude dans son équipe au-delà du buzz.",{"type":31,"tag":48,"props":304,"children":305},{},[],{"type":31,"tag":52,"props":307,"children":309},{"id":308},"samedi-la-question-éthique-de-fond",[310],{"type":40,"value":311},"Samedi - la question éthique de fond",{"type":31,"tag":32,"props":313,"children":314},{},[315,317],{"type":40,"value":316},"Au-delà des 5 pièges techniques, la semaine a posé une question qu'on évite trop souvent en stand-up : ",{"type":31,"tag":97,"props":318,"children":319},{},[320],{"type":40,"value":321},"à qui appartient le bug en prod, vous ou Claude ?",{"type":31,"tag":32,"props":323,"children":324},{},[325,327,333,335,341],{"type":40,"value":326},"La réponse craft, sourcée juridiquement (Thaler v. Perlmutter 2023, confirmé en appel 2025) : l'IA n'a pas la personnalité juridique. Le code mergé est attribué à celui qui l'a mergé. Si vous mergez, vous devenez l'auteur. J'ai détaillé la position complète, le contrat moral du dev 2026 en 4 engagements (lire, tester, tracer, assumer) et le squelette d'",{"type":31,"tag":69,"props":328,"children":330},{"href":329},"/fr/architecture-craft/adr-architecture-decision-record",[331],{"type":40,"value":332},"ADR de gouvernance IA",{"type":40,"value":334}," dans l'article sur ",{"type":31,"tag":69,"props":336,"children":338},{"href":337},"/fr/intelligence-artificielle/a-qui-appartient-le-bug-ia",[339],{"type":40,"value":340},"à qui appartient le bug en prod",{"type":40,"value":342},". Ce sujet rejoint en profondeur la peur de l'automatisation pour les développeurs : ce n'est pas Claude qu'il faut craindre, c'est la déresponsabilisation silencieuse qui s'installe sans dispositif éthique explicite.",{"type":31,"tag":48,"props":344,"children":345},{},[],{"type":31,"tag":52,"props":347,"children":349},{"id":348},"ce-quon-regarde-la-semaine-suivante-la-dette-ia-induite",[350],{"type":40,"value":351},"Ce qu'on regarde la semaine suivante : la dette IA-induite",{"type":31,"tag":32,"props":353,"children":354},{},[355],{"type":40,"value":356},"Si la première semaine portait sur les pièges techniques individuels qu'un développeur peut identifier sur sa propre PR, la suivante monte d'un cran : c'est la dette technique systémique qui se construit dans les codebases IA-heavy non disciplinées. Spoiler : une part croissante de la dette technique observée en 2026 dans les projets que j'accompagne est directement attribuable à du code IA-généré non audité, un chiffre que je consolide en cross-référence avec le DORA 2024 et mes propres observations. Cette dette se chiffre comme le risque legacy classique, et elle se rembourse avec les mêmes outils, en commençant par un programme de refactoring approuvé business.",{"type":31,"tag":32,"props":358,"children":359},{},[360,362,368,370,376],{"type":40,"value":361},"Deux articles supplémentaires complètent la boucle. Le premier, sur ",{"type":31,"tag":69,"props":363,"children":365},{"href":364},"/fr/dette-technique/dependabot-craft-gestion-dependances",[366],{"type":40,"value":367},"Dependabot comme coéquipier silencieux contre la dette de dépendances",{"type":40,"value":369},", montre comment configurer l'outil pour qu'il devienne un filet rétroactif efficace sans inonder le repo de PR inutiles. Le deuxième, sur ",{"type":31,"tag":69,"props":371,"children":373},{"href":372},"/fr/dette-technique/5-raisons-app-meurt-18-mois",[374],{"type":40,"value":375},"les 5 raisons pour lesquelles votre app meurt à 18 mois",{"type":40,"value":377},", élargit le propos au-delà de Claude et identifie les 5 piliers du craft durable qui font vivre une codebase 10 ans au lieu de 18 mois.",{"type":31,"tag":32,"props":379,"children":380},{},[381],{"type":40,"value":382},"Ces deux articles ferment la boucle : du tactique (pièges Claude individuels) au stratégique (dette IA-induite et durabilité des applications), du code à la culture d'équipe.",{"type":31,"tag":48,"props":384,"children":385},{},[],{"type":31,"tag":52,"props":387,"children":389},{"id":388},"la-grille-consolidée-à-imprimer",[390],{"type":40,"value":391},"La grille consolidée à imprimer",{"type":31,"tag":32,"props":393,"children":394},{},[395],{"type":40,"value":396},"Si vous ne devez retenir qu'une seule chose de cette série, c'est cette grille. À copier dans votre PR template GitHub, à afficher en sprint review, à utiliser en post-mortem.",{"type":31,"tag":398,"props":399,"children":400},"table",{},[401,425],{"type":31,"tag":402,"props":403,"children":404},"thead",{},[405],{"type":31,"tag":406,"props":407,"children":408},"tr",{},[409,415,420],{"type":31,"tag":410,"props":411,"children":412},"th",{},[413],{"type":40,"value":414},"Piège",{"type":31,"tag":410,"props":416,"children":417},{},[418],{"type":40,"value":419},"Signal d'alerte",{"type":31,"tag":410,"props":421,"children":422},{},[423],{"type":40,"value":424},"Contre-pattern craft",{"type":31,"tag":426,"props":427,"children":428},"tbody",{},[429,448,466,490,513,537,555,573,591,609],{"type":31,"tag":406,"props":430,"children":431},{},[432,438,443],{"type":31,"tag":433,"props":434,"children":435},"td",{},[436],{"type":40,"value":437},"Race condition",{"type":31,"tag":433,"props":439,"children":440},{},[441],{"type":40,"value":442},"Lecture + écriture sur état partagé sans transaction",{"type":31,"tag":433,"props":444,"children":445},{},[446],{"type":40,"value":447},"Transaction atomique + test de concurrence",{"type":31,"tag":406,"props":449,"children":450},{},[451,456,461],{"type":31,"tag":433,"props":452,"children":453},{},[454],{"type":40,"value":455},"God Function",{"type":31,"tag":433,"props":457,"children":458},{},[459],{"type":40,"value":460},"Fonction de plus de 40 lignes",{"type":31,"tag":433,"props":462,"children":463},{},[464],{"type":40,"value":465},"Découpe SRP en sous-fonctions nommées",{"type":31,"tag":406,"props":467,"children":468},{},[469,474,485],{"type":31,"tag":433,"props":470,"children":471},{},[472],{"type":40,"value":473},"Couplage ORM",{"type":31,"tag":433,"props":475,"children":476},{},[477,479],{"type":40,"value":478},"Import Prisma ou TypeORM dans le dossier ",{"type":31,"tag":169,"props":480,"children":482},{"className":481},[],[483],{"type":40,"value":484},"domain/",{"type":31,"tag":433,"props":486,"children":487},{},[488],{"type":40,"value":489},"Repository interface + adapter",{"type":31,"tag":406,"props":491,"children":492},{},[493,498,508],{"type":31,"tag":433,"props":494,"children":495},{},[496],{"type":40,"value":497},"Tests vides",{"type":31,"tag":433,"props":499,"children":500},{},[501,506],{"type":31,"tag":169,"props":502,"children":504},{"className":503},[],[505],{"type":40,"value":174},{"type":40,"value":507}," sans assertion métier",{"type":31,"tag":433,"props":509,"children":510},{},[511],{"type":40,"value":512},"Given/When/Then sur comportement observable",{"type":31,"tag":406,"props":514,"children":515},{},[516,521,532],{"type":31,"tag":433,"props":517,"children":518},{},[519],{"type":40,"value":520},"Catch-all silencieux",{"type":31,"tag":433,"props":522,"children":523},{},[524,530],{"type":31,"tag":169,"props":525,"children":527},{"className":526},[],[528],{"type":40,"value":529},"catch (err) { console.error(err) }",{"type":40,"value":531}," sans politique",{"type":31,"tag":433,"props":533,"children":534},{},[535],{"type":40,"value":536},"Re-throw, ou métrique d'observabilité",{"type":31,"tag":406,"props":538,"children":539},{},[540,545,550],{"type":31,"tag":433,"props":541,"children":542},{},[543],{"type":40,"value":544},"Copier-coller",{"type":31,"tag":433,"props":546,"children":547},{},[548],{"type":40,"value":549},"Fonction sémantiquement proche d'une existante",{"type":31,"tag":433,"props":551,"children":552},{},[553],{"type":40,"value":554},"Prompter Claude pour mutualiser",{"type":31,"tag":406,"props":556,"children":557},{},[558,563,568],{"type":31,"tag":433,"props":559,"children":560},{},[561],{"type":40,"value":562},"Abstraction accidentelle",{"type":31,"tag":433,"props":564,"children":565},{},[566],{"type":40,"value":567},"Interface devant une seule implémentation",{"type":31,"tag":433,"props":569,"children":570},{},[571],{"type":40,"value":572},"Règle des 3 cas réels (Fowler)",{"type":31,"tag":406,"props":574,"children":575},{},[576,581,586],{"type":31,"tag":433,"props":577,"children":578},{},[579],{"type":40,"value":580},"Tests modes d'échec",{"type":31,"tag":433,"props":582,"children":583},{},[584],{"type":40,"value":585},"Pas de test 429, timeout ou concurrence",{"type":31,"tag":433,"props":587,"children":588},{},[589],{"type":40,"value":590},"4 tests anti-fragiles obligatoires",{"type":31,"tag":406,"props":592,"children":593},{},[594,599,604],{"type":31,"tag":433,"props":595,"children":596},{},[597],{"type":40,"value":598},"Métriques d'activité",{"type":31,"tag":433,"props":600,"children":601},{},[602],{"type":40,"value":603},"LOC, PR mergées, story points seuls",{"type":31,"tag":433,"props":605,"children":606},{},[607],{"type":40,"value":608},"DORA + ratio ADR pour 100 commits",{"type":31,"tag":406,"props":610,"children":611},{},[612,617,622],{"type":31,"tag":433,"props":613,"children":614},{},[615],{"type":40,"value":616},"Responsabilité diluée",{"type":31,"tag":433,"props":618,"children":619},{},[620],{"type":40,"value":621},"\"C'est Claude qui l'a écrit\" en post-mortem",{"type":31,"tag":433,"props":623,"children":624},{},[625],{"type":40,"value":626},"ADR de gouvernance IA + 4 engagements",{"type":31,"tag":32,"props":628,"children":629},{},[630],{"type":40,"value":631},"10 lignes. 5 minutes de revue par PR. Le retour sur investissement s'observe en 3 mois, ce qui s'inscrit dans une démarche plus large de maturité engineering progressive et qui transforme chaque PR en occasion de gain de qualité, selon la philosophie Boy Scout Rule.",{"type":31,"tag":48,"props":633,"children":634},{},[],{"type":31,"tag":52,"props":636,"children":638},{"id":637},"conclusion",[639],{"type":40,"value":640},"Conclusion",{"type":31,"tag":32,"props":642,"children":643},{},[644],{"type":40,"value":645},"Ce que je veux que vous reteniez de cette série : Claude n'est ni un magicien, ni un saboteur. C'est un collègue junior très rapide, qui produit beaucoup, apprend mal de la prod, et qui a besoin d'un dispositif humain de relecture, de test et de discipline pour devenir utile à long terme. Sans ce dispositif, vous accumulez de la dette à vitesse industrielle. Avec, Claude devient un accélérateur de qualité.",{"type":31,"tag":32,"props":647,"children":648},{},[649],{"type":40,"value":650},"La première semaine vous a donné la grille opérationnelle : 5 pièges, 5 contre-patterns, 4 engagements éthiques. La suivante vous donnera la lecture systémique : les 5 raisons pour lesquelles une application meurt à 18 mois, et les 5 pratiques craft pour bâtir des codes qui tiennent 10 ans au lieu d'un cycle court.",{"type":31,"tag":32,"props":652,"children":653},{},[654],{"type":40,"value":655},"Si vous vous reconnaissez dans ce tableau, l'arbitrage de lundi matin est simple : retourner sur votre repo en supposant que tout va bien, ou bloquer 30 minutes pour installer la grille consolidée, lancer un premier audit, démarrer la transformation. Coût ridicule, impact mesurable en 6 semaines.",{"type":31,"tag":32,"props":657,"children":658},{},[659,661,669],{"type":40,"value":660},"Pour la suite des contenus craft + IA en format court, vous pouvez me retrouver sur ",{"type":31,"tag":69,"props":662,"children":666},{"href":663,"rel":664},"https://www.instagram.com/kamangacode/",[665],"nofollow",[667],{"type":40,"value":668},"mon profil Instagram kamangacode",{"type":40,"value":670},", où je publie chaque semaine les patterns que je vois revenir en mission et les contre-patterns que j'applique.",{"type":31,"tag":229,"props":672,"children":677},{"cta":673,"href":674,"title":675,"type":676},"Les 100 pratiques que l'IA n'enseigne pas →","https://kamanga.fr/referentiel-craft","Cette grille à 10 lignes n'est qu'un extrait : il existe 100 pratiques craft","product",[678],{"type":31,"tag":32,"props":679,"children":680},{},[681],{"type":40,"value":682},"La grille consolidée de cette série fait partie d'un référentiel bien plus large : le Craft Bundle, les 100 pratiques craft que j'applique pour coder propre. Race conditions, découpe SRP, exceptions typées, tests anti-fragiles : tout ce que cette synthèse effleure y est détaillé, avec les centaines d'autres pratiques que l'IA ne vous apprendra jamais parce qu'elle ne les a jamais vues tourner en prod.",{"type":31,"tag":48,"props":684,"children":685},{},[],{"type":31,"tag":52,"props":687,"children":689},{"id":688},"faq-sur-la-série-craft-et-ia",[690],{"type":40,"value":691},"FAQ sur la série craft et IA",{"type":31,"tag":693,"props":694,"children":695},"details",{},[696,702],{"type":31,"tag":697,"props":698,"children":699},"summary",{},[700],{"type":40,"value":701},"1. La série fonctionne-t-elle pour des stacks autres que TypeScript ou Node ?",{"type":31,"tag":32,"props":703,"children":704},{},[705,707,713],{"type":40,"value":706},"Oui, à 95%. Les pièges sont indépendants du langage. Les exemples de code sont en TypeScript, mais les patterns existent en Java, Python, Go, C# avec les mêmes signatures. Pour les contre-patterns, les outils diffèrent (",{"type":31,"tag":169,"props":708,"children":710},{"className":709},[],[711],{"type":40,"value":712},"p-retry",{"type":40,"value":714}," devient Resilience4j en Java, ou Tenacity en Python), mais la philosophie est identique. Si vous êtes sur Java avec Maven, échangez juste les snippets, gardez la grille.",{"type":31,"tag":693,"props":716,"children":717},{},[718,723],{"type":31,"tag":697,"props":719,"children":720},{},[721],{"type":40,"value":722},"2. Combien de temps pour installer cette discipline dans une équipe de 10 développeurs ?",{"type":31,"tag":32,"props":724,"children":725},{},[726],{"type":40,"value":727},"3 à 6 mois pour que la grille devienne un réflexe partagé. La première semaine, on installe le PR template et l'ADR de gouvernance. Le premier mois, les seniors démontrent par l'exemple. Au deuxième mois, les juniors commencent à porter la grille spontanément. Au troisième mois, c'est dans la culture. À 6 mois, on mesure les chiffres avant/après dans les articles de la série, et l'équipe est prête à passer à un sujet plus avancé comme l'évaluation collective d'un outil IA en équipe.",{"type":31,"tag":693,"props":729,"children":730},{},[731,736],{"type":31,"tag":697,"props":732,"children":733},{},[734],{"type":40,"value":735},"3. Faut-il refuser Claude tant que la grille n'est pas en place ?",{"type":31,"tag":32,"props":737,"children":738},{},[739],{"type":40,"value":740},"Non. La pire approche serait d'attendre la perfection avant d'utiliser l'outil. La meilleure approche : commencer par 2 garde-fous sur le piège qui vous touche le plus (souvent la race condition ou les tests vides), mesurer l'impact sur 6 semaines, puis ajouter le suivant. C'est de la transformation incrémentale, exactement ce que recommandent les principes d'un code évolutif.",{"type":31,"tag":693,"props":742,"children":743},{},[744,749],{"type":31,"tag":697,"props":745,"children":746},{},[747],{"type":40,"value":748},"4. Comment partager cette série avec mon équipe sans paraître donneur de leçons ?",{"type":31,"tag":32,"props":750,"children":751},{},[752],{"type":40,"value":753},"Le mieux est de proposer une session de 30 minutes pendant laquelle vous présentez un seul piège, celui qui vous parle le plus, avec un exemple tiré de votre propre repo et une discussion sur le contre-pattern. Pas une présentation magistrale, une discussion d'égal à égal. Sur les missions où j'ai vu cette approche, l'adhésion est à 80% en 3 sessions.",{"type":31,"tag":693,"props":755,"children":756},{},[757,762],{"type":31,"tag":697,"props":758,"children":759},{},[760],{"type":40,"value":761},"5. Les pièges vont-ils évoluer avec les prochaines versions de Claude ?",{"type":31,"tag":32,"props":763,"children":764},{},[765],{"type":40,"value":766},"Certains s'atténueront probablement (les modèles deviennent meilleurs sur la concurrence et l'observabilité), d'autres s'amplifieront (la facilité de génération augmente la sur-ingénierie). Ma règle : la grille doit être révisée tous les 12 mois en équipe, avec un audit des pièges présents et l'ajout éventuel de nouveaux. C'est un système vivant, pas un dogme figé.",{"type":31,"tag":693,"props":768,"children":769},{},[770,775],{"type":31,"tag":697,"props":771,"children":772},{},[773],{"type":40,"value":774},"6. Où trouver des ressources complémentaires pour aller plus loin ?",{"type":31,"tag":32,"props":776,"children":777},{},[778,780,784,786,791,793,799],{"type":40,"value":779},"Trois sources que je recommande systématiquement en mission : ",{"type":31,"tag":97,"props":781,"children":782},{},[783],{"type":40,"value":101},{"type":40,"value":785}," de Robert C. Martin (les fondamentaux du craft), ",{"type":31,"tag":97,"props":787,"children":788},{},[789],{"type":40,"value":790},"Release It!",{"type":40,"value":792}," de Michael Nygard (les patterns de résilience prod), et le DORA Accelerate Report annuel (les métriques de référence). En format court, vous me retrouvez sur ",{"type":31,"tag":69,"props":794,"children":796},{"href":663,"rel":795},[665],[797],{"type":40,"value":798},"Instagram @kamangacode",{"type":40,"value":800}," avec un pattern craft par semaine.",{"type":31,"tag":48,"props":802,"children":803},{},[],{"type":31,"tag":229,"props":805,"children":810},{"cta":806,"href":807,"title":808,"type":809},"Évaluer la maturité de mon équipe →","/mes-ressources","Ressource gratuite : Engineering Maturity Assessment","resource",[811],{"type":31,"tag":32,"props":812,"children":813},{},[814],{"type":40,"value":815},"L'EMA est l'outil que je propose au début de chaque mission. Il mesure la maturité de votre équipe sur 8 axes engineering, dont la gouvernance IA, la qualité du code, la dette technique et l'observabilité prod. Quelques minutes pour identifier lesquels des pièges Claude s'installent le plus vite chez vous, et où concentrer vos efforts en priorité.",{"title":8,"searchDepth":817,"depth":817,"links":818},2,[819,820,821,822,823,824,825,826,827,828,829],{"id":54,"depth":817,"text":57},{"id":124,"depth":817,"text":127},{"id":159,"depth":817,"text":162},{"id":195,"depth":817,"text":198},{"id":246,"depth":817,"text":249},{"id":273,"depth":817,"text":276},{"id":308,"depth":817,"text":311},{"id":348,"depth":817,"text":351},{"id":388,"depth":817,"text":391},{"id":637,"depth":817,"text":640},{"id":688,"depth":817,"text":691},"markdown","content:fr:intelligence-artificielle:recap-5-pieges-claude-semaine-1.md","content","fr/intelligence-artificielle/recap-5-pieges-claude-semaine-1.md","fr/intelligence-artificielle/recap-5-pieges-claude-semaine-1","md",{"_path":289,"_dir":6,"_draft":7,"_partial":7,"_locale":8,"title":837,"description":838,"id":839,"date":840,"listed":13,"nocomments":7,"hidden":7,"categories":841,"tags":842,"cover":846,"readingTime":847,"body":851,"_type":830,"_id":1743,"_source":832,"_file":1744,"_stem":1745,"_extension":835},"10x plus de PR ≠ 10x plus de valeur livrée : les 4 métriques qui mentent","DORA 2024 le prouve : vélocité IA +35%, mais lead time fix +27%. Les 4 métriques à abandonner et les 4 + 1 qui disent la vérité sur crmcoaching.",66,"2026-05-16",[6],[843,844,16,845,19],"dora-metrics","productivite","management","covers/articles/illusion-productivite-10x-pr.jpg",{"text":23,"minutes":848,"time":849,"words":850},12.365,741900,2473,{"type":28,"children":852,"toc":1732},[853,861,866,869,875,889,901,920,933,959,962,968,973,997,1007,1024,1034,1039,1042,1048,1053,1063,1073,1083,1099,1104,1107,1116,1119,1125,1130,1154,1159,1171,1174,1180,1185,1320,1325,1336,1339,1345,1350,1358,1388,1396,1419,1427,1445,1458,1461,1467,1472,1586,1591,1594,1598,1603,1608,1613,1624,1633,1636,1642,1655,1668,1681,1694,1707,1720,1723],{"type":31,"tag":32,"props":854,"children":855},{},[856],{"type":31,"tag":36,"props":857,"children":858},{},[859],{"type":40,"value":860},"Pendant les premiers mois de développement de crmcoaching avec Claude, j'étais convaincu d'être 35% plus productif. Je livrais plus de PR, plus de commits, plus de features. Puis j'ai regardé mes vrais chiffres : le change failure rate avait doublé, et le temps moyen pour corriger un incident en prod avait triplé. Ce n'était pas une contradiction. Les deux chiffres étaient vrais. Le problème : je mesurais ce qui m'arrangeait, pas ce qui comptait.",{"type":31,"tag":32,"props":862,"children":863},{},[864],{"type":40,"value":865},"Le DORA Accelerate State of DevOps Report 2024 a confirmé ce que j'ai vécu sur crmcoaching depuis 6 mois : 4 métriques mentent dès qu'une IA générative entre dans la boucle, 4 autres disent enfin la vérité, et j'en ajoute systématiquement une cinquième à mes propres dashboards.",{"type":31,"tag":48,"props":867,"children":868},{},[],{"type":31,"tag":52,"props":870,"children":872},{"id":871},"le-mythe-ia-vélocité-35-mais-lead-time-fix-27",[873],{"type":40,"value":874},"Le mythe IA : vélocité +35%, mais lead time fix +27%",{"type":31,"tag":32,"props":876,"children":877},{},[878,880,887],{"type":40,"value":879},"Le ",{"type":31,"tag":69,"props":881,"children":884},{"href":882,"rel":883},"https://dora.dev/research/2024/",[665],[885],{"type":40,"value":886},"DORA Accelerate State of DevOps Report 2024",{"type":40,"value":888}," est la première étude longitudinale à mesurer l'impact réel des assistants IA sur les équipes engineering. Les chiffres sont publiés, ils sont contre-intuitifs, et ils méritent qu'on s'y arrête.",{"type":31,"tag":32,"props":890,"children":891},{},[892,894,899],{"type":40,"value":893},"D'un côté : les équipes qui utilisent Claude voient leur ",{"type":31,"tag":97,"props":895,"children":896},{},[897],{"type":40,"value":898},"throughput",{"type":40,"value":900}," (nombre de changes livrées) augmenter de 35% en moyenne. C'est la métrique que tout le monde brandit, celle qui rassure le COMEX, parce qu'elle est mesurable, visible, et gratifiante à court terme.",{"type":31,"tag":32,"props":902,"children":903},{},[904,906,911,913,918],{"type":40,"value":905},"De l'autre côté : ces mêmes équipes voient leur ",{"type":31,"tag":97,"props":907,"children":908},{},[909],{"type":40,"value":910},"change failure rate",{"type":40,"value":912}," grimper (passages en prod qui causent un incident) et leur ",{"type":31,"tag":97,"props":914,"children":915},{},[916],{"type":40,"value":917},"lead time for changes",{"type":40,"value":919}," (temps entre commit et prod) augmenter de 27% sur les fixes. Traduction : on livre plus, on casse plus, on met plus de temps à réparer. Exactement le déséquilibre que je documente dans mon retour d'expérience sur la code review IA.",{"type":31,"tag":78,"props":921,"children":922},{},[923],{"type":31,"tag":32,"props":924,"children":925},{},[926,931],{"type":31,"tag":36,"props":927,"children":928},{},[929],{"type":40,"value":930},"Ce que j'ai observé sur crmcoaching",{"type":40,"value":932}," : j'ai mesuré sur 6 mois les 4 métriques DORA en différenciant mes commits manuels et mes commits Claude-assistés. Ma vélocité sur les commits entièrement manuels : +5%. Ma vélocité Claude-assistée : +42%. Mais mon change failure rate est passé de 8% à 19%. Et mon MTTR (mean time to restore) est passé de 45 minutes à 2h10. Le gain en surface est réel. La dégradation profonde est plus réelle encore.",{"type":31,"tag":32,"props":934,"children":935},{},[936,938,943,945,950,952,958],{"type":40,"value":937},"Forsgren, Humble et Kim avaient écrit dans ",{"type":31,"tag":97,"props":939,"children":940},{},[941],{"type":40,"value":942},"Accelerate",{"type":40,"value":944}," (2018) que ",{"type":31,"tag":97,"props":946,"children":947},{},[948],{"type":40,"value":949},"\"vous ne pouvez pas optimiser ce que vous ne mesurez pas, et vous mesurez ce que vous optimisez\"",{"type":40,"value":951},". Si vous mesurez le throughput seul, vous optimisez le throughput au détriment de la stabilité. C'est exactement ce qui se passe dans 80% des projets IA-heavy non pilotés, et c'est ce qu'évalue concrètement ",{"type":31,"tag":69,"props":953,"children":955},{"href":954},"/fr/intelligence-artificielle/evaluer-outil-ia-equipe-adoption",[956],{"type":40,"value":957},"l'évaluation d'un outil IA en équipe avant adoption",{"type":40,"value":76},{"type":31,"tag":48,"props":960,"children":961},{},[],{"type":31,"tag":52,"props":963,"children":965},{"id":964},"les-4-métriques-qui-mentent-en-2026",[966],{"type":40,"value":967},"Les 4 métriques qui mentent en 2026",{"type":31,"tag":32,"props":969,"children":970},{},[971],{"type":40,"value":972},"Voici les 4 métriques que j'ai vantées pendant les premières semaines de crmcoaching, et que j'ai dû remettre à leur place : utiles à titre informatif, mais dangereuses si elles deviennent l'objectif central.",{"type":31,"tag":32,"props":974,"children":975},{},[976,981,983,988,990,995],{"type":31,"tag":36,"props":977,"children":978},{},[979],{"type":40,"value":980},"Métrique pourrie #1 : les lignes de code livrées.",{"type":40,"value":982}," Mesure brute du volume. Avec Claude, je livre facilement 3 à 8 fois plus de lignes pour la même feature. Optimiser cette métrique pousse à la sur-ingénierie systématique, comme ",{"type":31,"tag":69,"props":984,"children":985},{"href":262},[986],{"type":40,"value":987},"le démontre l'analyse du coût caché des faux amis Claude",{"type":40,"value":989},". Plus de lignes signifie plus de dette à maintenir, et c'est aussi ce que rappellent ",{"type":31,"tag":69,"props":991,"children":992},{"href":113},[993],{"type":40,"value":994},"les principes Clean Code et software craftsmanship",{"type":40,"value":996}," : la qualité n'est pas dans le volume.",{"type":31,"tag":32,"props":998,"children":999},{},[1000,1005],{"type":31,"tag":36,"props":1001,"children":1002},{},[1003],{"type":40,"value":1004},"Métrique pourrie #2 : le nombre de PR mergées.",{"type":40,"value":1006}," Encore plus piégeux. Une PR peut couvrir 4 lignes ou 800 lignes. Une PR peut être un fix critique ou un renommage cosmétique. Compter les PR sans qualifier leur impact, c'est compter des cartons sans regarder ce qu'il y a dedans.",{"type":31,"tag":32,"props":1008,"children":1009},{},[1010,1015,1017,1023],{"type":31,"tag":36,"props":1011,"children":1012},{},[1013],{"type":40,"value":1014},"Métrique pourrie #3 : les story points livrés par sprint.",{"type":40,"value":1016}," L'estimation initiale est faite par le développeur, qui est incité à surestimer pour rentrer dans le sprint, ou à sous-estimer pour livrer plus vite. La métrique est circulaire : on mesure ce qu'on a estimé, et on optimise ce qu'on mesure. Aucune information réelle sur la valeur livrée, et c'est précisément ce que pointent les ",{"type":31,"tag":69,"props":1018,"children":1020},{"href":1019},"/fr/pratiques-agiles/story-points-estimation-agile-alternative",[1021],{"type":40,"value":1022},"alternatives aux story points en estimation agile",{"type":40,"value":76},{"type":31,"tag":32,"props":1025,"children":1026},{},[1027,1032],{"type":31,"tag":36,"props":1028,"children":1029},{},[1030],{"type":40,"value":1031},"Métrique pourrie #4 : les tickets fermés.",{"type":40,"value":1033}," Variante du précédent. Un ticket fermé peut être une feature livrée, une investigation classée \"ne peut pas reproduire\", un doublon. Pire : avec Claude, j'ouvre 3 fois plus de petits tickets parce que c'est plus facile à drafter, et je les ferme 3 fois plus vite. Le compteur explose. La valeur métier livrée, pas tellement.",{"type":31,"tag":32,"props":1035,"children":1036},{},[1037],{"type":40,"value":1038},"Le point commun de ces 4 métriques : elles mesurent l'activité, pas le résultat. Le piège que Drucker et Deming dénonçaient dans les années 80, rejoué aujourd'hui à l'échelle de l'IA.",{"type":31,"tag":48,"props":1040,"children":1041},{},[],{"type":31,"tag":52,"props":1043,"children":1045},{"id":1044},"les-4-métriques-dora-qui-disent-la-vérité",[1046],{"type":40,"value":1047},"Les 4 métriques DORA qui disent la vérité",{"type":31,"tag":32,"props":1049,"children":1050},{},[1051],{"type":40,"value":1052},"À l'inverse, voici les 4 métriques DORA que je suis aujourd'hui sur crmcoaching, et qui donnent une lecture honnête de ce que je livre.",{"type":31,"tag":32,"props":1054,"children":1055},{},[1056,1061],{"type":31,"tag":36,"props":1057,"children":1058},{},[1059],{"type":40,"value":1060},"Métrique #1 : le lead time for changes.",{"type":40,"value":1062}," Temps entre le premier commit sur une feature et son passage en prod. C'est la métrique de flux. Avec Claude, je produis vite, mais je peux bloquer en revue, en QA, en attente de migration. Le lead time révèle où le flux casse réellement. Cible : moins de 1 jour pour les équipes Elite (DORA 2024), 1 semaine pour les High Performers.",{"type":31,"tag":32,"props":1064,"children":1065},{},[1066,1071],{"type":31,"tag":36,"props":1067,"children":1068},{},[1069],{"type":40,"value":1070},"Métrique #2 : la deployment frequency.",{"type":40,"value":1072}," Fréquence à laquelle je mets en prod. Une codebase qui déploie une fois par semaine accumule du risque de batch. Une codebase qui déploie quotidiennement livre par petits incréments. Claude accélère la deployment frequency uniquement si la CI/CD suit. Sinon, il produit plus vite et la prod stagne. C'est exactement le sujet traité dans les fondamentaux du Continuous Integration.",{"type":31,"tag":32,"props":1074,"children":1075},{},[1076,1081],{"type":31,"tag":36,"props":1077,"children":1078},{},[1079],{"type":40,"value":1080},"Métrique #3 : le change failure rate.",{"type":40,"value":1082}," Pourcentage de déploiements qui causent un incident ou nécessitent un rollback. C'est la métrique de stabilité. C'est là que Claude fait le plus de dégâts si je ne l'encadre pas. Cible : moins de 5% pour les Elite, moins de 15% pour les High Performers. Cette métrique se travaille en amont avec une Definition of Done qui couvre les modes d'échec.",{"type":31,"tag":32,"props":1084,"children":1085},{},[1086,1091,1093,1098],{"type":31,"tag":36,"props":1087,"children":1088},{},[1089],{"type":40,"value":1090},"Métrique #4 : le MTTR (mean time to restore).",{"type":40,"value":1092}," Temps moyen entre détection d'un incident et restauration. C'est la métrique de résilience. Le MTTR explose quand le code IA-généré n'est pas instrumenté pour l'observabilité (logs structurés, métriques, traces). C'est exactement le problème que ",{"type":31,"tag":69,"props":1094,"children":1095},{"href":211},[1096],{"type":40,"value":1097},"les 4 tests anti-fragiles permettent de résoudre",{"type":40,"value":76},{"type":31,"tag":32,"props":1100,"children":1101},{},[1102],{"type":40,"value":1103},"Ces 4 métriques forment un système. Truquer le throughput dégrade la stabilité. Optimiser la stabilité sans regarder le flux casse aussi. Le génie de DORA tient là : une boussole à 4 cardinaux, pas un thermomètre unique.",{"type":31,"tag":48,"props":1105,"children":1106},{},[],{"type":31,"tag":229,"props":1108,"children":1110},{"cta":231,"href":232,"title":1109,"type":234},"Vous voulez apprendre à lire vos vrais chiffres au lieu de ceux qui flattent ?",[1111],{"type":31,"tag":32,"props":1112,"children":1113},{},[1114],{"type":40,"value":1115},"Distinguer le throughput qui rassure de la stabilité qui compte, ça ne s'acquiert pas en lisant un rapport DORA : ça se travaille sur votre propre code. En mentoring 1:1, on installe ensemble vos métriques de flux et de stabilité, et je vous apprends à arbitrer chaque PR Claude-assistée comme un senior le ferait. Vous arrêtez de mesurer ce qui vous arrange pour piloter ce qui tient en prod.",{"type":31,"tag":48,"props":1117,"children":1118},{},[],{"type":31,"tag":52,"props":1120,"children":1122},{"id":1121},"la-5ème-métrique-perso-le-ratio-adr-commits",[1123],{"type":40,"value":1124},"La 5ème métrique perso : le ratio ADR / commits",{"type":31,"tag":32,"props":1126,"children":1127},{},[1128],{"type":40,"value":1129},"Voici la métrique que j'ai ajoutée à mes propres dashboards crmcoaching depuis le lancement, et qui n'est pas dans le framework DORA.",{"type":31,"tag":32,"props":1131,"children":1132},{},[1133,1138,1140,1145,1147,1152],{"type":31,"tag":36,"props":1134,"children":1135},{},[1136],{"type":40,"value":1137},"Ratio ADR / 100 commits.",{"type":40,"value":1139}," Combien de ",{"type":31,"tag":69,"props":1141,"children":1142},{"href":329},[1143],{"type":40,"value":1144},"décisions architecturales documentées (ADR)",{"type":40,"value":1146}," pour 100 commits dans mon repo. C'est la métrique de ",{"type":31,"tag":97,"props":1148,"children":1149},{},[1150],{"type":40,"value":1151},"traçabilité du jugement",{"type":40,"value":1153},". Quand Claude produit du code, ce qui doit rester à moi, c'est la décision : pourquoi cette stack, pourquoi ce pattern, pourquoi ce trade-off.",{"type":31,"tag":32,"props":1155,"children":1156},{},[1157],{"type":40,"value":1158},"Sans cette discipline, le ratio descend proche de zéro. Ce qui veut dire que l'immense majorité des décisions sont prises silencieusement, sans trace, sans contradiction documentée. Quand je reviens sur une partie du code 3 mois plus tard, je n'ai aucune chance de me souvenir pourquoi les choix actuels ont été faits, à moins qu'un ADR l'ait capturé.",{"type":31,"tag":32,"props":1160,"children":1161},{},[1162,1164,1169],{"type":40,"value":1163},"Sur crmcoaching, je suis à 6,2 ADR pour 100 commits. C'est l'indicateur que je n'ai pas perdu la pensée architecturale au profit de la production massive de code. Michael Nygard l'avait écrit en 2011 dans son article fondateur sur les ADR : ",{"type":31,"tag":97,"props":1165,"children":1166},{},[1167],{"type":40,"value":1168},"\"The cost of an undocumented decision is paid by everyone, for years.\"",{"type":40,"value":1170}," En solo avec une IA, ce \"everyone\" c'est moi, 6 mois plus tard.",{"type":31,"tag":48,"props":1172,"children":1173},{},[],{"type":31,"tag":52,"props":1175,"children":1177},{"id":1176},"comparaison-concrète-avant-et-après-pilotage-dora-sur-crmcoaching",[1178],{"type":40,"value":1179},"Comparaison concrète : avant et après pilotage DORA sur crmcoaching",{"type":31,"tag":32,"props":1181,"children":1182},{},[1183],{"type":40,"value":1184},"Voici les chiffres réels que j'ai mesurés sur crmcoaching sur deux périodes distinctes de 3 mois chacune.",{"type":31,"tag":398,"props":1186,"children":1187},{},[1188,1209],{"type":31,"tag":402,"props":1189,"children":1190},{},[1191],{"type":31,"tag":406,"props":1192,"children":1193},{},[1194,1199,1204],{"type":31,"tag":410,"props":1195,"children":1196},{},[1197],{"type":40,"value":1198},"Métrique",{"type":31,"tag":410,"props":1200,"children":1201},{},[1202],{"type":40,"value":1203},"Phase 1 : Claude sans pilotage",{"type":31,"tag":410,"props":1205,"children":1206},{},[1207],{"type":40,"value":1208},"Phase 2 : Claude + DORA + ADR",{"type":31,"tag":426,"props":1210,"children":1211},{},[1212,1230,1248,1266,1284,1302],{"type":31,"tag":406,"props":1213,"children":1214},{},[1215,1220,1225],{"type":31,"tag":433,"props":1216,"children":1217},{},[1218],{"type":40,"value":1219},"Throughput (commits/semaine)",{"type":31,"tag":433,"props":1221,"children":1222},{},[1223],{"type":40,"value":1224},"89",{"type":31,"tag":433,"props":1226,"children":1227},{},[1228],{"type":40,"value":1229},"78 (-12%)",{"type":31,"tag":406,"props":1231,"children":1232},{},[1233,1238,1243],{"type":31,"tag":433,"props":1234,"children":1235},{},[1236],{"type":40,"value":1237},"Lead time for changes",{"type":31,"tag":433,"props":1239,"children":1240},{},[1241],{"type":40,"value":1242},"3,8 jours",{"type":31,"tag":433,"props":1244,"children":1245},{},[1246],{"type":40,"value":1247},"1,4 jour",{"type":31,"tag":406,"props":1249,"children":1250},{},[1251,1256,1261],{"type":31,"tag":433,"props":1252,"children":1253},{},[1254],{"type":40,"value":1255},"Change failure rate",{"type":31,"tag":433,"props":1257,"children":1258},{},[1259],{"type":40,"value":1260},"22%",{"type":31,"tag":433,"props":1262,"children":1263},{},[1264],{"type":40,"value":1265},"6%",{"type":31,"tag":406,"props":1267,"children":1268},{},[1269,1274,1279],{"type":31,"tag":433,"props":1270,"children":1271},{},[1272],{"type":40,"value":1273},"MTTR",{"type":31,"tag":433,"props":1275,"children":1276},{},[1277],{"type":40,"value":1278},"2h15",{"type":31,"tag":433,"props":1280,"children":1281},{},[1282],{"type":40,"value":1283},"38 min",{"type":31,"tag":406,"props":1285,"children":1286},{},[1287,1292,1297],{"type":31,"tag":433,"props":1288,"children":1289},{},[1290],{"type":40,"value":1291},"Ratio ADR / 100 commits",{"type":31,"tag":433,"props":1293,"children":1294},{},[1295],{"type":40,"value":1296},"0,2",{"type":31,"tag":433,"props":1298,"children":1299},{},[1300],{"type":40,"value":1301},"6,2",{"type":31,"tag":406,"props":1303,"children":1304},{},[1305,1310,1315],{"type":31,"tag":433,"props":1306,"children":1307},{},[1308],{"type":40,"value":1309},"Confiance subjective sur la livraison",{"type":31,"tag":433,"props":1311,"children":1312},{},[1313],{"type":40,"value":1314},"\"je produis beaucoup\"",{"type":31,"tag":433,"props":1316,"children":1317},{},[1318],{"type":40,"value":1319},"\"je livre de la valeur\"",{"type":31,"tag":32,"props":1321,"children":1322},{},[1323],{"type":40,"value":1324},"Le verdict est net : en phase 2, je livre moins de commits bruts mais mon code tient en prod. La différence ne tient pas à Claude. Elle tient à la discipline de pilotage. Sans la grille DORA + ADR, Claude est un amplificateur de chaos. Avec la grille, c'est un amplificateur de valeur.",{"type":31,"tag":32,"props":1326,"children":1327},{},[1328,1330,1335],{"type":40,"value":1329},"Pour un solo-dev sur un SaaS, ce tableau devient un outil de pilotage hebdomadaire. Il transforme les intuitions (\"je sens que je suis plus productif\") en faits (\"mon lead time est descendu de 3,8 à 1,4 jours\"). C'est la même logique qu'on retrouve dans ",{"type":31,"tag":69,"props":1331,"children":1332},{"href":297},[1333],{"type":40,"value":1334},"les bonnes métriques de management d'équipe dev",{"type":40,"value":76},{"type":31,"tag":48,"props":1337,"children":1338},{},[],{"type":31,"tag":52,"props":1340,"children":1342},{"id":1341},"comment-piloter-avec-ces-4-1-métriques-en-2026",[1343],{"type":40,"value":1344},"Comment piloter avec ces 4 + 1 métriques en 2026",{"type":31,"tag":32,"props":1346,"children":1347},{},[1348],{"type":40,"value":1349},"Voici la mise en pratique que j'applique sur crmcoaching. Tient sur un tableau de bord Grafana, mis à jour automatiquement à partir de GitHub et de mon outil de monitoring.",{"type":31,"tag":32,"props":1351,"children":1352},{},[1353],{"type":31,"tag":36,"props":1354,"children":1355},{},[1356],{"type":40,"value":1357},"Hebdomadaire (revue personnelle) :",{"type":31,"tag":1359,"props":1360,"children":1361},"ul",{},[1362,1368,1373,1378,1383],{"type":31,"tag":1363,"props":1364,"children":1365},"li",{},[1366],{"type":40,"value":1367},"Lead time for changes (médiane et P90 de la semaine)",{"type":31,"tag":1363,"props":1369,"children":1370},{},[1371],{"type":40,"value":1372},"Deployment frequency (compte des deployments)",{"type":31,"tag":1363,"props":1374,"children":1375},{},[1376],{"type":40,"value":1377},"Change failure rate (% des deployments qui ont causé un incident)",{"type":31,"tag":1363,"props":1379,"children":1380},{},[1381],{"type":40,"value":1382},"MTTR (médiane des incidents résolus cette semaine)",{"type":31,"tag":1363,"props":1384,"children":1385},{},[1386],{"type":40,"value":1387},"ADR créées dans la semaine (compte simple)",{"type":31,"tag":32,"props":1389,"children":1390},{},[1391],{"type":31,"tag":36,"props":1392,"children":1393},{},[1394],{"type":40,"value":1395},"Mensuel (revue de cap) :",{"type":31,"tag":1359,"props":1397,"children":1398},{},[1399,1404,1409,1414],{"type":31,"tag":1363,"props":1400,"children":1401},{},[1402],{"type":40,"value":1403},"Trend des 4 DORA sur 4 semaines glissantes",{"type":31,"tag":1363,"props":1405,"children":1406},{},[1407],{"type":40,"value":1408},"Ratio ADR / 100 commits du mois",{"type":31,"tag":1363,"props":1410,"children":1411},{},[1412],{"type":40,"value":1413},"Top 3 des incidents (avec analyse cause profonde)",{"type":31,"tag":1363,"props":1415,"children":1416},{},[1417],{"type":40,"value":1418},"Sentiment subjectif sur la valeur livrée (note 1-10)",{"type":31,"tag":32,"props":1420,"children":1421},{},[1422],{"type":31,"tag":36,"props":1423,"children":1424},{},[1425],{"type":40,"value":1426},"Trimestriel (revue de direction) :",{"type":31,"tag":1359,"props":1428,"children":1429},{},[1430,1435,1440],{"type":31,"tag":1363,"props":1431,"children":1432},{},[1433],{"type":40,"value":1434},"Comparaison avec les benchmarks DORA Elite / High / Medium / Low",{"type":31,"tag":1363,"props":1436,"children":1437},{},[1438],{"type":40,"value":1439},"Evolution des 5 métriques sur 12 semaines",{"type":31,"tag":1363,"props":1441,"children":1442},{},[1443],{"type":40,"value":1444},"ROI estimé de la discipline IA (coût d'instrumentation vs incidents évités)",{"type":31,"tag":32,"props":1446,"children":1447},{},[1448,1450,1456],{"type":40,"value":1449},"Cette structure évite le piège classique du tableau de bord trop riche. 5 métriques par échelle, lues dans la cadence appropriée. C'est ce que recommandent les pratiques de ",{"type":31,"tag":69,"props":1451,"children":1453},{"href":1452},"/fr/dette-technique/introduction-maturite-engineering-5-niveaux",[1454],{"type":40,"value":1455},"maturité engineering",{"type":40,"value":1457}," que je mesure dans l'EMA.",{"type":31,"tag":48,"props":1459,"children":1460},{},[],{"type":31,"tag":52,"props":1462,"children":1464},{"id":1463},"ce-que-ça-change-concrètement",[1465],{"type":40,"value":1466},"Ce que ça change concrètement",{"type":31,"tag":32,"props":1468,"children":1469},{},[1470],{"type":40,"value":1471},"Sur crmcoaching, voici les changements observés entre la phase 1 (sans pilotage) et la phase 2 (avec tableau de bord DORA + ADR) sur 6 mois.",{"type":31,"tag":398,"props":1473,"children":1474},{},[1475,1495],{"type":31,"tag":402,"props":1476,"children":1477},{},[1478],{"type":31,"tag":406,"props":1479,"children":1480},{},[1481,1485,1490],{"type":31,"tag":410,"props":1482,"children":1483},{},[1484],{"type":40,"value":1198},{"type":31,"tag":410,"props":1486,"children":1487},{},[1488],{"type":40,"value":1489},"Phase 1 : sans tableau de bord",{"type":31,"tag":410,"props":1491,"children":1492},{},[1493],{"type":40,"value":1494},"Phase 2 : après 6 mois",{"type":31,"tag":426,"props":1496,"children":1497},{},[1498,1516,1534,1550,1568],{"type":31,"tag":406,"props":1499,"children":1500},{},[1501,1506,1511],{"type":31,"tag":433,"props":1502,"children":1503},{},[1504],{"type":40,"value":1505},"Questions \"est-ce que je suis vraiment plus productif ?\"",{"type":31,"tag":433,"props":1507,"children":1508},{},[1509],{"type":40,"value":1510},"hebdomadaires",{"type":31,"tag":433,"props":1512,"children":1513},{},[1514],{"type":40,"value":1515},"jamais",{"type":31,"tag":406,"props":1517,"children":1518},{},[1519,1524,1529],{"type":31,"tag":433,"props":1520,"children":1521},{},[1522],{"type":40,"value":1523},"Lead time for changes médian",{"type":31,"tag":433,"props":1525,"children":1526},{},[1527],{"type":40,"value":1528},"4,1 jours",{"type":31,"tag":433,"props":1530,"children":1531},{},[1532],{"type":40,"value":1533},"1,7 jour",{"type":31,"tag":406,"props":1535,"children":1536},{},[1537,1541,1545],{"type":31,"tag":433,"props":1538,"children":1539},{},[1540],{"type":40,"value":1255},{"type":31,"tag":433,"props":1542,"children":1543},{},[1544],{"type":40,"value":1260},{"type":31,"tag":433,"props":1546,"children":1547},{},[1548],{"type":40,"value":1549},"7%",{"type":31,"tag":406,"props":1551,"children":1552},{},[1553,1558,1563],{"type":31,"tag":433,"props":1554,"children":1555},{},[1556],{"type":40,"value":1557},"Confiance dans la vélocité affichée (1-10)",{"type":31,"tag":433,"props":1559,"children":1560},{},[1561],{"type":40,"value":1562},"4",{"type":31,"tag":433,"props":1564,"children":1565},{},[1566],{"type":40,"value":1567},"9",{"type":31,"tag":406,"props":1569,"children":1570},{},[1571,1576,1581],{"type":31,"tag":433,"props":1572,"children":1573},{},[1574],{"type":40,"value":1575},"Décisions architecturales tracées en ADR",{"type":31,"tag":433,"props":1577,"children":1578},{},[1579],{"type":40,"value":1580},"moins de 10%",{"type":31,"tag":433,"props":1582,"children":1583},{},[1584],{"type":40,"value":1585},"plus de 75%",{"type":31,"tag":32,"props":1587,"children":1588},{},[1589],{"type":40,"value":1590},"Le gain le plus important n'est pas dans les chiffres. C'est dans la clarté qui devient possible. Avant le tableau de bord, je parlais en croyances (\"je sens que Claude m'aide\"). Après le tableau de bord, je parle en faits (\"le lead time est descendu de 4 à 1,7 jours, le change failure rate est passé de 22 à 7%\"). La conversation avec moi-même devient productive.",{"type":31,"tag":48,"props":1592,"children":1593},{},[],{"type":31,"tag":52,"props":1595,"children":1596},{"id":637},[1597],{"type":40,"value":640},{"type":31,"tag":32,"props":1599,"children":1600},{},[1601],{"type":40,"value":1602},"Ce que je veux que vous reteniez de cet article : la productivité d'un développeur ne se mesure pas en lignes de code, en PR mergées ou en tickets fermés. Elle se mesure en flux (lead time, deployment frequency) et en stabilité (change failure rate, MTTR). Claude peut booster le throughput de 35% à 89%. Il peut aussi dégrader silencieusement les 3 autres métriques si vous ne le pilotez pas.",{"type":31,"tag":32,"props":1604,"children":1605},{},[1606],{"type":40,"value":1607},"La 5ème métrique, le ratio ADR / 100 commits, est ce qui rend la discipline durable. Sans elle, vous mesurez l'output sans tracer la pensée. Et au bout de 18 mois, vous avez une codebase volumineuse sans personne (pas même vous) qui comprend pourquoi elle est faite ainsi.",{"type":31,"tag":32,"props":1609,"children":1610},{},[1611],{"type":40,"value":1612},"Si vous vous reconnaissez dans ce tableau, l'arbitrage est simple : continuer à brandir le +35% de throughput en vous félicitant en fermant les yeux sur les 3 autres chiffres, ou installer dès lundi matin un dashboard à 5 métriques et reprendre une lecture honnête de ce que vous livrez.",{"type":31,"tag":32,"props":1614,"children":1615},{},[1616,1618,1623],{"type":40,"value":1617},"Pour la suite des métriques craft que je documente chaque semaine sur crmcoaching, retrouvez-moi sur ",{"type":31,"tag":69,"props":1619,"children":1621},{"href":663,"rel":1620},[665],[1622],{"type":40,"value":668},{"type":40,"value":76},{"type":31,"tag":229,"props":1625,"children":1627},{"cta":673,"href":674,"title":1626,"type":676},"Piloter ses métriques n'est qu'une pratique parmi les 100 qui font un senior",[1628],{"type":31,"tag":32,"props":1629,"children":1630},{},[1631],{"type":40,"value":1632},"Cet article décortique une seule pratique craft : lire le flux et la stabilité plutôt que le volume brut. Le Craft Bundle réunit les 100 pratiques que j'applique pour coder propre et livrer du code qui tient, depuis le pilotage DORA jusqu'à la traçabilité des décisions en ADR. Ce sont les réflexes que l'IA ne vous apprendra jamais, parce qu'elle ne les a jamais vus tourner en prod.",{"type":31,"tag":48,"props":1634,"children":1635},{},[],{"type":31,"tag":52,"props":1637,"children":1639},{"id":1638},"faq-sur-les-métriques-dora-et-le-pilotage-ia",[1640],{"type":40,"value":1641},"FAQ sur les métriques DORA et le pilotage IA",{"type":31,"tag":693,"props":1643,"children":1644},{},[1645,1650],{"type":31,"tag":697,"props":1646,"children":1647},{},[1648],{"type":40,"value":1649},"1. Faut-il abandonner les story points complètement ?",{"type":31,"tag":32,"props":1651,"children":1652},{},[1653],{"type":40,"value":1654},"Non, mais il faut les remettre à leur juste place : un outil interne d'estimation de capacité de sprint, pas une métrique de productivité. Les story points servent à organiser la charge. Ils ne servent pas à mesurer la valeur livrée ni à comparer des projets entre eux. Quand on les utilise comme KPI, on crée des incitations perverses.",{"type":31,"tag":693,"props":1656,"children":1657},{},[1658,1663],{"type":31,"tag":697,"props":1659,"children":1660},{},[1661],{"type":40,"value":1662},"2. Comment instrumenter automatiquement les métriques DORA ?",{"type":31,"tag":32,"props":1664,"children":1665},{},[1666],{"type":40,"value":1667},"Trois outils gratuits font 90% du travail. GitHub Actions exporte les événements de merge et de deploy. Datadog ou Grafana Cloud agrègent les métriques avec des labels projet / repo / type. Sleuth, FourKeys (open source par Google) ou LinearB sont plus packagés. Pour démarrer, le combo GitHub + Grafana est suffisant. Comptez 2-3 jours d'installation, puis quasi-zéro maintenance.",{"type":31,"tag":693,"props":1669,"children":1670},{},[1671,1676],{"type":31,"tag":697,"props":1672,"children":1673},{},[1674],{"type":40,"value":1675},"3. Le change failure rate, comment le mesurer objectivement ?",{"type":31,"tag":32,"props":1677,"children":1678},{},[1679],{"type":40,"value":1680},"C'est la métrique la plus délicate. Je définis : un déploiement est \"failed\" si dans les 24h suivantes, j'ai déployé un hotfix, fait un rollback, ou ouvert un incident P1/P2. Cette définition évite l'arbitraire. Elle se code en automatique en croisant le log de déploiement avec le tracker d'incidents. La mesure n'est pas parfaite, mais elle est honnête et reproductible d'une semaine à l'autre.",{"type":31,"tag":693,"props":1682,"children":1683},{},[1684,1689],{"type":31,"tag":697,"props":1685,"children":1686},{},[1687],{"type":40,"value":1688},"4. Combien de temps pour qu'un tableau de bord DORA devienne stable ?",{"type":31,"tag":32,"props":1690,"children":1691},{},[1692],{"type":40,"value":1693},"Comptez 4-6 semaines pour que les chiffres se stabilisent et que vous compreniez ce que vous regardez. Pendant les 2 premières semaines, vous verrez beaucoup d'effets de seuil (bug de mesure, événements pas correctement tagués). À partir de la 4ème semaine, les tendances deviennent fiables. À 3 mois, vous pouvez commencer à prendre des décisions basées sur les chiffres.",{"type":31,"tag":693,"props":1695,"children":1696},{},[1697,1702],{"type":31,"tag":697,"props":1698,"children":1699},{},[1700],{"type":40,"value":1701},"5. Comment éviter que les métriques deviennent un outil de pression sur soi-même ?",{"type":31,"tag":32,"props":1703,"children":1704},{},[1705],{"type":40,"value":1706},"Les métriques DORA sont des métriques de flux et de stabilité, pas des métriques de valeur personnelle. Si votre change failure rate monte une semaine, c'est une information sur votre processus, pas un jugement sur vous. L'objectif est de voir les tendances sur plusieurs semaines, pas d'interpréter chaque point de données comme un verdict. En solo, c'est encore plus important de garder cette distance.",{"type":31,"tag":693,"props":1708,"children":1709},{},[1710,1715],{"type":31,"tag":697,"props":1711,"children":1712},{},[1713],{"type":40,"value":1714},"6. Le ratio ADR / 100 commits, quelle cible viser ?",{"type":31,"tag":32,"props":1716,"children":1717},{},[1718],{"type":40,"value":1719},"Je recommande 3 à 6 ADR pour 100 commits comme zone saine. En dessous de 1, vous ne tracez plus la pensée. Au-dessus de 10, vous documentez trop et vous noyez les vraies décisions dans le bruit. Sur crmcoaching je suis à 6,2 et c'est confortable. Si vous démarrez, l'objectif des 3 premiers mois est de passer de 0,1 à 1,0. Ensuite on calibre.",{"type":31,"tag":48,"props":1721,"children":1722},{},[],{"type":31,"tag":229,"props":1724,"children":1726},{"cta":1725,"href":807,"title":808,"type":809},"Évaluer la maturité de mon projet →",[1727],{"type":31,"tag":32,"props":1728,"children":1729},{},[1730],{"type":40,"value":1731},"L'EMA est l'outil que je propose au début de chaque mission. Il mesure la maturité d'un projet sur plusieurs axes engineering : delivery, qualité, gouvernance IA, observabilité. Le module pilotage / métriques DORA y est central. Quelques minutes pour identifier où votre tableau de bord ment ou se tait, et où concentrer vos efforts en priorité.",{"title":8,"searchDepth":817,"depth":817,"links":1733},[1734,1735,1736,1737,1738,1739,1740,1741,1742],{"id":871,"depth":817,"text":874},{"id":964,"depth":817,"text":967},{"id":1044,"depth":817,"text":1047},{"id":1121,"depth":817,"text":1124},{"id":1176,"depth":817,"text":1179},{"id":1341,"depth":817,"text":1344},{"id":1463,"depth":817,"text":1466},{"id":637,"depth":817,"text":640},{"id":1638,"depth":817,"text":1641},"content:fr:intelligence-artificielle:illusion-productivite-10x-pr.md","fr/intelligence-artificielle/illusion-productivite-10x-pr.md","fr/intelligence-artificielle/illusion-productivite-10x-pr",{"_path":262,"_dir":6,"_draft":7,"_partial":7,"_locale":8,"title":1747,"description":1748,"id":1749,"date":1750,"listed":13,"nocomments":7,"hidden":7,"categories":1751,"tags":1752,"cover":1756,"readingTime":1757,"body":1762,"_type":830,"_id":4021,"_source":832,"_file":4022,"_stem":4023,"_extension":835},"Le code Claude 'qui marche' est souvent celui qui vous coûte le plus cher","Démonstration chiffrée des 3 faux amis du code IA-généré : copier-coller invisible, abstractions accidentelles, sur-ingénierie. Et la règle YAGNI + AI.",65,"2026-05-13",[6],[16,1753,1754,1755,19],"dette-technique","yagni","sur-ingenierie","covers/articles/faux-ami-code-claude-coute-cher.jpg",{"text":1758,"minutes":1759,"time":1760,"words":1761},"14 min read",13.37,802200,2674,{"type":28,"children":1763,"toc":4010},[1764,1772,1777,1780,1786,1806,1815,1820,1833,1858,1861,1867,1872,1893,2388,2401,2413,2426,2429,2435,2440,2847,2868,2873,2907,2912,2915,2924,2927,2933,2938,3450,3463,3468,3487,3490,3496,3501,3617,3622,3635,3638,3644,3649,3659,3676,3686,3696,3701,3704,3708,3713,3826,3850,3853,3857,3862,3867,3872,3883,3892,3895,3901,3914,3935,3948,3961,3974,3993,3996,4004],{"type":31,"tag":32,"props":1765,"children":1766},{},[1767],{"type":31,"tag":36,"props":1768,"children":1769},{},[1770],{"type":40,"value":1771},"En construisant crmcoaching avec Claude, j'ai vu ces 3 faux amis s'installer dans mes premiers commits bien avant d'avoir mis la discipline en place. Tests verts, ESLint au vert, tout compilait. Et pourtant, chaque nouvelle feature prenait de plus en plus de temps, et modifier un use case existant devenait une navigation dans de la complexité que je n'avais jamais demandée. Pas à cause d'une mauvaise architecture de départ. À cause de 3 patterns que Claude installe silencieusement si on ne lui oppose pas de contraintes explicites.",{"type":31,"tag":32,"props":1773,"children":1774},{},[1775],{"type":40,"value":1776},"Voici les 3 patterns que j'ai identifiés sur mes propres commits, les chiffres de leur coût caché, et la règle craft de 2026 qui les neutralise.",{"type":31,"tag":48,"props":1778,"children":1779},{},[],{"type":31,"tag":52,"props":1781,"children":1783},{"id":1782},"le-mythe-du-ça-compile-cest-bon",[1784],{"type":40,"value":1785},"Le mythe du \"ça compile, c'est bon\"",{"type":31,"tag":32,"props":1787,"children":1788},{},[1789,1791,1798,1800,1805],{"type":40,"value":1790},"Le constat de base est documenté. Selon le ",{"type":31,"tag":69,"props":1792,"children":1795},{"href":1793,"rel":1794},"https://www.gitclear.com/ai_assistant_code_quality_2024_research",[665],[1796],{"type":40,"value":1797},"GitClear AI Copilot Code Quality Report 2024",{"type":40,"value":1799},", sur les repos qui utilisent intensivement un assistant comme Claude, le ratio de code \"copié-collé\" a augmenté de 8 fois depuis 2022. La taille moyenne des PR a grossi de 12%. Le temps de revue par PR a baissé de 14%. Concrètement : on écrit plus, on revoit moins, on duplique plus, ce qui correspond exactement au pattern que je décris dans ",{"type":31,"tag":69,"props":1801,"children":1802},{"href":71},[1803],{"type":40,"value":1804},"le retour d'expérience sur la code review IA",{"type":40,"value":76},{"type":31,"tag":32,"props":1807,"children":1808},{},[1809],{"type":31,"tag":1810,"props":1811,"children":1814},"img",{"alt":1812,"src":1813},"La gestion des leads dans crmcoaching, le SaaS que je développe avec Claude","/images/crm/crm-coaching-lead.png",[],{"type":31,"tag":32,"props":1816,"children":1817},{},[1818],{"type":40,"value":1819},"Le piège, c'est que tout ça produit du code qui marche. Les tests passent. Les utilisateurs sont contents. ESLint ne crie pas. Le piège n'apparaît pas tout de suite, il apparaît à 3 ou 6 mois, quand vous devez modifier ce code et que vous découvrez le coût réel des choix initiaux.",{"type":31,"tag":78,"props":1821,"children":1822},{},[1823],{"type":31,"tag":32,"props":1824,"children":1825},{},[1826,1831],{"type":31,"tag":36,"props":1827,"children":1828},{},[1829],{"type":40,"value":1830},"Ce que j'ai observé",{"type":40,"value":1832}," : dans les premiers commits de crmcoaching, j'ai compté les fonctions dupliquées à plus de 70% de similarité. Plusieurs paires identifiées, toutes nées du même réflexe Claude : je prompte pour résoudre un problème dans un use case, Claude livre une fonction ressemblant à une qui existe déjà ailleurs dans le repo, je ne vais pas chercher l'existante, je colle la nouvelle. Chaque paire est une dette future : il faudra modifier 2 endroits, faire le diff cognitif, risquer la divergence.",{"type":31,"tag":32,"props":1834,"children":1835},{},[1836,1838,1843,1845,1850,1852,1856],{"type":40,"value":1837},"Donald Knuth avait écrit en 1974 que ",{"type":31,"tag":97,"props":1839,"children":1840},{},[1841],{"type":40,"value":1842},"\"premature optimization is the root of all evil\"",{"type":40,"value":1844},". Sa formule s'applique aussi à l'abstraction. En 2026, je dirais que ",{"type":31,"tag":97,"props":1846,"children":1847},{},[1848],{"type":40,"value":1849},"\"l'abstraction prématurée IA-générée est la racine du mal silencieux\"",{"type":40,"value":1851},". Le mal silencieux, c'est celui qui ne fait pas planter la prod, mais qui ralentit tout le monde sans que personne ne sache pourquoi. C'est aussi ce qu'éclairent ",{"type":31,"tag":69,"props":1853,"children":1854},{"href":113},[1855],{"type":40,"value":994},{"type":40,"value":1857}," : la qualité ne se voit pas dans le code \"qui marche\", elle se voit dans le code \"qu'on peut modifier sans souffrir\".",{"type":31,"tag":48,"props":1859,"children":1860},{},[],{"type":31,"tag":52,"props":1862,"children":1864},{"id":1863},"faux-ami-1-le-copier-coller-invisible",[1865],{"type":40,"value":1866},"Faux ami #1 : le copier-coller invisible",{"type":31,"tag":32,"props":1868,"children":1869},{},[1870],{"type":40,"value":1871},"C'est le plus fréquent et le plus sous-estimé. Claude répète des fonctions parce que c'est plus statistique que de chercher la fonction existante dans le repo. Le développeur l'accepte parce que le code \"marche\".",{"type":31,"tag":32,"props":1873,"children":1874},{},[1875,1877,1883,1885,1891],{"type":40,"value":1876},"Voici un exemple tiré de mes premiers commits sur crmcoaching. Deux use cases différents, ",{"type":31,"tag":169,"props":1878,"children":1880},{"className":1879},[],[1881],{"type":40,"value":1882},"CreateOffer",{"type":40,"value":1884}," et ",{"type":31,"tag":169,"props":1886,"children":1888},{"className":1887},[],[1889],{"type":40,"value":1890},"CreateMentoringCheckoutIntent",{"type":40,"value":1892},", écrits à quelques semaines d'écart. Deux fonctions quasi identiques, à 6 fichiers de distance :",{"type":31,"tag":1894,"props":1895,"children":1899},"pre",{"className":1896,"code":1897,"language":1898,"meta":8,"style":8},"language-typescript shiki shiki-themes catppuccin-frappe github-dark","// apps/api/src/application/offer/use-cases/create-offer.use-case.ts\nfunction computeMonthlyOfferPrice(\n  yearlyPrice: number,\n  fees: number,\n): number {\n  const subtotal = yearlyPrice / 12;\n  const withFees = subtotal + fees / 12;\n  return Math.round(withFees * 100) / 100;\n}\n\n// apps/api/src/application/mentoring/use-cases/create-mentoring-checkout-intent.use-case.ts\nfunction calculateSubscriptionAmount(\n  annualAmount: number,\n  charges: number,\n): number {\n  const base = annualAmount / 12;\n  const total = base + charges / 12;\n  return Math.round(total * 100) / 100;\n}\n","typescript",[1900],{"type":31,"tag":169,"props":1901,"children":1902},{"__ignoreMap":8},[1903,1915,1936,1963,1984,2006,2048,2092,2148,2157,2166,2175,2192,2213,2234,2254,2288,2331,2380],{"type":31,"tag":1904,"props":1905,"children":1908},"span",{"class":1906,"line":1907},"line",1,[1909],{"type":31,"tag":1904,"props":1910,"children":1912},{"style":1911},"--shiki-default:#737994;--shiki-default-font-style:italic;--shiki-dark:#6A737D;--shiki-dark-font-style:inherit",[1913],{"type":40,"value":1914},"// apps/api/src/application/offer/use-cases/create-offer.use-case.ts\n",{"type":31,"tag":1904,"props":1916,"children":1917},{"class":1906,"line":817},[1918,1924,1930],{"type":31,"tag":1904,"props":1919,"children":1921},{"style":1920},"--shiki-default:#CA9EE6;--shiki-dark:#F97583",[1922],{"type":40,"value":1923},"function",{"type":31,"tag":1904,"props":1925,"children":1927},{"style":1926},"--shiki-default:#8CAAEE;--shiki-default-font-style:italic;--shiki-dark:#B392F0;--shiki-dark-font-style:inherit",[1928],{"type":40,"value":1929}," computeMonthlyOfferPrice",{"type":31,"tag":1904,"props":1931,"children":1933},{"style":1932},"--shiki-default:#949CBB;--shiki-dark:#E1E4E8",[1934],{"type":40,"value":1935},"(\n",{"type":31,"tag":1904,"props":1937,"children":1939},{"class":1906,"line":1938},3,[1940,1946,1952,1958],{"type":31,"tag":1904,"props":1941,"children":1943},{"style":1942},"--shiki-default:#EA999C;--shiki-default-font-style:italic;--shiki-dark:#FFAB70;--shiki-dark-font-style:inherit",[1944],{"type":40,"value":1945},"  yearlyPrice",{"type":31,"tag":1904,"props":1947,"children":1949},{"style":1948},"--shiki-default:#81C8BE;--shiki-dark:#F97583",[1950],{"type":40,"value":1951},":",{"type":31,"tag":1904,"props":1953,"children":1955},{"style":1954},"--shiki-default:#CA9EE6;--shiki-dark:#79B8FF",[1956],{"type":40,"value":1957}," number",{"type":31,"tag":1904,"props":1959,"children":1960},{"style":1932},[1961],{"type":40,"value":1962},",\n",{"type":31,"tag":1904,"props":1964,"children":1966},{"class":1906,"line":1965},4,[1967,1972,1976,1980],{"type":31,"tag":1904,"props":1968,"children":1969},{"style":1942},[1970],{"type":40,"value":1971},"  fees",{"type":31,"tag":1904,"props":1973,"children":1974},{"style":1948},[1975],{"type":40,"value":1951},{"type":31,"tag":1904,"props":1977,"children":1978},{"style":1954},[1979],{"type":40,"value":1957},{"type":31,"tag":1904,"props":1981,"children":1982},{"style":1932},[1983],{"type":40,"value":1962},{"type":31,"tag":1904,"props":1985,"children":1987},{"class":1906,"line":1986},5,[1988,1993,1997,2001],{"type":31,"tag":1904,"props":1989,"children":1990},{"style":1932},[1991],{"type":40,"value":1992},")",{"type":31,"tag":1904,"props":1994,"children":1995},{"style":1948},[1996],{"type":40,"value":1951},{"type":31,"tag":1904,"props":1998,"children":1999},{"style":1954},[2000],{"type":40,"value":1957},{"type":31,"tag":1904,"props":2002,"children":2003},{"style":1932},[2004],{"type":40,"value":2005}," {\n",{"type":31,"tag":1904,"props":2007,"children":2009},{"class":1906,"line":2008},6,[2010,2015,2021,2026,2032,2037,2043],{"type":31,"tag":1904,"props":2011,"children":2012},{"style":1920},[2013],{"type":40,"value":2014},"  const",{"type":31,"tag":1904,"props":2016,"children":2018},{"style":2017},"--shiki-default:#C6D0F5;--shiki-dark:#79B8FF",[2019],{"type":40,"value":2020}," subtotal",{"type":31,"tag":1904,"props":2022,"children":2023},{"style":1948},[2024],{"type":40,"value":2025}," =",{"type":31,"tag":1904,"props":2027,"children":2029},{"style":2028},"--shiki-default:#C6D0F5;--shiki-dark:#E1E4E8",[2030],{"type":40,"value":2031}," yearlyPrice ",{"type":31,"tag":1904,"props":2033,"children":2034},{"style":1948},[2035],{"type":40,"value":2036},"/",{"type":31,"tag":1904,"props":2038,"children":2040},{"style":2039},"--shiki-default:#EF9F76;--shiki-dark:#79B8FF",[2041],{"type":40,"value":2042}," 12",{"type":31,"tag":1904,"props":2044,"children":2045},{"style":1932},[2046],{"type":40,"value":2047},";\n",{"type":31,"tag":1904,"props":2049,"children":2051},{"class":1906,"line":2050},7,[2052,2056,2061,2065,2070,2075,2080,2084,2088],{"type":31,"tag":1904,"props":2053,"children":2054},{"style":1920},[2055],{"type":40,"value":2014},{"type":31,"tag":1904,"props":2057,"children":2058},{"style":2017},[2059],{"type":40,"value":2060}," withFees",{"type":31,"tag":1904,"props":2062,"children":2063},{"style":1948},[2064],{"type":40,"value":2025},{"type":31,"tag":1904,"props":2066,"children":2067},{"style":2028},[2068],{"type":40,"value":2069}," subtotal ",{"type":31,"tag":1904,"props":2071,"children":2072},{"style":1948},[2073],{"type":40,"value":2074},"+",{"type":31,"tag":1904,"props":2076,"children":2077},{"style":2028},[2078],{"type":40,"value":2079}," fees ",{"type":31,"tag":1904,"props":2081,"children":2082},{"style":1948},[2083],{"type":40,"value":2036},{"type":31,"tag":1904,"props":2085,"children":2086},{"style":2039},[2087],{"type":40,"value":2042},{"type":31,"tag":1904,"props":2089,"children":2090},{"style":1932},[2091],{"type":40,"value":2047},{"type":31,"tag":1904,"props":2093,"children":2095},{"class":1906,"line":2094},8,[2096,2101,2106,2111,2116,2121,2126,2131,2136,2140,2144],{"type":31,"tag":1904,"props":2097,"children":2098},{"style":1920},[2099],{"type":40,"value":2100},"  return",{"type":31,"tag":1904,"props":2102,"children":2103},{"style":2028},[2104],{"type":40,"value":2105}," Math",{"type":31,"tag":1904,"props":2107,"children":2109},{"style":2108},"--shiki-default:#81C8BE;--shiki-dark:#E1E4E8",[2110],{"type":40,"value":76},{"type":31,"tag":1904,"props":2112,"children":2113},{"style":1926},[2114],{"type":40,"value":2115},"round",{"type":31,"tag":1904,"props":2117,"children":2118},{"style":2028},[2119],{"type":40,"value":2120},"(withFees ",{"type":31,"tag":1904,"props":2122,"children":2123},{"style":1948},[2124],{"type":40,"value":2125},"*",{"type":31,"tag":1904,"props":2127,"children":2128},{"style":2039},[2129],{"type":40,"value":2130}," 100",{"type":31,"tag":1904,"props":2132,"children":2133},{"style":2028},[2134],{"type":40,"value":2135},") ",{"type":31,"tag":1904,"props":2137,"children":2138},{"style":1948},[2139],{"type":40,"value":2036},{"type":31,"tag":1904,"props":2141,"children":2142},{"style":2039},[2143],{"type":40,"value":2130},{"type":31,"tag":1904,"props":2145,"children":2146},{"style":1932},[2147],{"type":40,"value":2047},{"type":31,"tag":1904,"props":2149,"children":2151},{"class":1906,"line":2150},9,[2152],{"type":31,"tag":1904,"props":2153,"children":2154},{"style":1932},[2155],{"type":40,"value":2156},"}\n",{"type":31,"tag":1904,"props":2158,"children":2160},{"class":1906,"line":2159},10,[2161],{"type":31,"tag":1904,"props":2162,"children":2163},{"emptyLinePlaceholder":13},[2164],{"type":40,"value":2165},"\n",{"type":31,"tag":1904,"props":2167,"children":2169},{"class":1906,"line":2168},11,[2170],{"type":31,"tag":1904,"props":2171,"children":2172},{"style":1911},[2173],{"type":40,"value":2174},"// apps/api/src/application/mentoring/use-cases/create-mentoring-checkout-intent.use-case.ts\n",{"type":31,"tag":1904,"props":2176,"children":2178},{"class":1906,"line":2177},12,[2179,2183,2188],{"type":31,"tag":1904,"props":2180,"children":2181},{"style":1920},[2182],{"type":40,"value":1923},{"type":31,"tag":1904,"props":2184,"children":2185},{"style":1926},[2186],{"type":40,"value":2187}," calculateSubscriptionAmount",{"type":31,"tag":1904,"props":2189,"children":2190},{"style":1932},[2191],{"type":40,"value":1935},{"type":31,"tag":1904,"props":2193,"children":2195},{"class":1906,"line":2194},13,[2196,2201,2205,2209],{"type":31,"tag":1904,"props":2197,"children":2198},{"style":1942},[2199],{"type":40,"value":2200},"  annualAmount",{"type":31,"tag":1904,"props":2202,"children":2203},{"style":1948},[2204],{"type":40,"value":1951},{"type":31,"tag":1904,"props":2206,"children":2207},{"style":1954},[2208],{"type":40,"value":1957},{"type":31,"tag":1904,"props":2210,"children":2211},{"style":1932},[2212],{"type":40,"value":1962},{"type":31,"tag":1904,"props":2214,"children":2216},{"class":1906,"line":2215},14,[2217,2222,2226,2230],{"type":31,"tag":1904,"props":2218,"children":2219},{"style":1942},[2220],{"type":40,"value":2221},"  charges",{"type":31,"tag":1904,"props":2223,"children":2224},{"style":1948},[2225],{"type":40,"value":1951},{"type":31,"tag":1904,"props":2227,"children":2228},{"style":1954},[2229],{"type":40,"value":1957},{"type":31,"tag":1904,"props":2231,"children":2232},{"style":1932},[2233],{"type":40,"value":1962},{"type":31,"tag":1904,"props":2235,"children":2237},{"class":1906,"line":2236},15,[2238,2242,2246,2250],{"type":31,"tag":1904,"props":2239,"children":2240},{"style":1932},[2241],{"type":40,"value":1992},{"type":31,"tag":1904,"props":2243,"children":2244},{"style":1948},[2245],{"type":40,"value":1951},{"type":31,"tag":1904,"props":2247,"children":2248},{"style":1954},[2249],{"type":40,"value":1957},{"type":31,"tag":1904,"props":2251,"children":2252},{"style":1932},[2253],{"type":40,"value":2005},{"type":31,"tag":1904,"props":2255,"children":2257},{"class":1906,"line":2256},16,[2258,2262,2267,2271,2276,2280,2284],{"type":31,"tag":1904,"props":2259,"children":2260},{"style":1920},[2261],{"type":40,"value":2014},{"type":31,"tag":1904,"props":2263,"children":2264},{"style":2017},[2265],{"type":40,"value":2266}," base",{"type":31,"tag":1904,"props":2268,"children":2269},{"style":1948},[2270],{"type":40,"value":2025},{"type":31,"tag":1904,"props":2272,"children":2273},{"style":2028},[2274],{"type":40,"value":2275}," annualAmount ",{"type":31,"tag":1904,"props":2277,"children":2278},{"style":1948},[2279],{"type":40,"value":2036},{"type":31,"tag":1904,"props":2281,"children":2282},{"style":2039},[2283],{"type":40,"value":2042},{"type":31,"tag":1904,"props":2285,"children":2286},{"style":1932},[2287],{"type":40,"value":2047},{"type":31,"tag":1904,"props":2289,"children":2291},{"class":1906,"line":2290},17,[2292,2296,2301,2305,2310,2314,2319,2323,2327],{"type":31,"tag":1904,"props":2293,"children":2294},{"style":1920},[2295],{"type":40,"value":2014},{"type":31,"tag":1904,"props":2297,"children":2298},{"style":2017},[2299],{"type":40,"value":2300}," total",{"type":31,"tag":1904,"props":2302,"children":2303},{"style":1948},[2304],{"type":40,"value":2025},{"type":31,"tag":1904,"props":2306,"children":2307},{"style":2028},[2308],{"type":40,"value":2309}," base ",{"type":31,"tag":1904,"props":2311,"children":2312},{"style":1948},[2313],{"type":40,"value":2074},{"type":31,"tag":1904,"props":2315,"children":2316},{"style":2028},[2317],{"type":40,"value":2318}," charges ",{"type":31,"tag":1904,"props":2320,"children":2321},{"style":1948},[2322],{"type":40,"value":2036},{"type":31,"tag":1904,"props":2324,"children":2325},{"style":2039},[2326],{"type":40,"value":2042},{"type":31,"tag":1904,"props":2328,"children":2329},{"style":1932},[2330],{"type":40,"value":2047},{"type":31,"tag":1904,"props":2332,"children":2334},{"class":1906,"line":2333},18,[2335,2339,2343,2347,2351,2356,2360,2364,2368,2372,2376],{"type":31,"tag":1904,"props":2336,"children":2337},{"style":1920},[2338],{"type":40,"value":2100},{"type":31,"tag":1904,"props":2340,"children":2341},{"style":2028},[2342],{"type":40,"value":2105},{"type":31,"tag":1904,"props":2344,"children":2345},{"style":2108},[2346],{"type":40,"value":76},{"type":31,"tag":1904,"props":2348,"children":2349},{"style":1926},[2350],{"type":40,"value":2115},{"type":31,"tag":1904,"props":2352,"children":2353},{"style":2028},[2354],{"type":40,"value":2355},"(total ",{"type":31,"tag":1904,"props":2357,"children":2358},{"style":1948},[2359],{"type":40,"value":2125},{"type":31,"tag":1904,"props":2361,"children":2362},{"style":2039},[2363],{"type":40,"value":2130},{"type":31,"tag":1904,"props":2365,"children":2366},{"style":2028},[2367],{"type":40,"value":2135},{"type":31,"tag":1904,"props":2369,"children":2370},{"style":1948},[2371],{"type":40,"value":2036},{"type":31,"tag":1904,"props":2373,"children":2374},{"style":2039},[2375],{"type":40,"value":2130},{"type":31,"tag":1904,"props":2377,"children":2378},{"style":1932},[2379],{"type":40,"value":2047},{"type":31,"tag":1904,"props":2381,"children":2383},{"class":1906,"line":2382},19,[2384],{"type":31,"tag":1904,"props":2385,"children":2386},{"style":1932},[2387],{"type":40,"value":2156},{"type":31,"tag":32,"props":2389,"children":2390},{},[2391,2393,2399],{"type":40,"value":2392},"Même calcul, deux noms, deux fichiers, deux tests, deux maintenances. Le jour où la logique d'arrondi change (par exemple passer à ",{"type":31,"tag":169,"props":2394,"children":2396},{"className":2395},[],[2397],{"type":40,"value":2398},"Math.ceil",{"type":40,"value":2400}," pour la comptabilité), il faut retrouver les 2 endroits. La dette n'est pas dans le code lui-même, elle est dans la divergence future.",{"type":31,"tag":32,"props":2402,"children":2403},{},[2404,2406,2411],{"type":40,"value":2405},"Le contre-pattern craft : avant chaque PR, je demande explicitement à Claude ",{"type":31,"tag":97,"props":2407,"children":2408},{},[2409],{"type":40,"value":2410},"\"cherche dans le repo s'il existe déjà une fonction équivalente à ce que tu viens d'écrire, et propose une refacto qui mutualise\"",{"type":40,"value":2412},". Claude fait ce travail très bien si on le lui demande. Il ne le fait jamais spontanément. Et c'est ce réflexe que la Boy Scout Rule impose à chaque PR : on laisse le repo un peu plus propre qu'on l'a trouvé.",{"type":31,"tag":32,"props":2414,"children":2415},{},[2416,2418,2424],{"type":40,"value":2417},"Sur le crmcoaching, j'ai aujourd'hui 3 utilitaires de calcul financier dans ",{"type":31,"tag":169,"props":2419,"children":2421},{"className":2420},[],[2422],{"type":40,"value":2423},"packages/shared",{"type":40,"value":2425},". Sur un repo équivalent IA-heavy non audité, j'en aurais vu 12 à 15. La différence se voit au bout de 12 mois sur le temps de modification.",{"type":31,"tag":48,"props":2427,"children":2428},{},[],{"type":31,"tag":52,"props":2430,"children":2432},{"id":2431},"faux-ami-2-les-abstractions-accidentelles",[2433],{"type":40,"value":2434},"Faux ami #2 : les abstractions accidentelles",{"type":31,"tag":32,"props":2436,"children":2437},{},[2438],{"type":40,"value":2439},"Le deuxième faux ami est plus subtil. Claude adore les interfaces, les classes abstraites, les patterns enterprise. Si vous lui demandez un service de notation de leads, il vous livre, sur un projet NestJS :",{"type":31,"tag":1894,"props":2441,"children":2443},{"className":1896,"code":2442,"language":1898,"meta":8,"style":8},"// 1. L'interface\nexport interface LeadScorer {\n  score(lead: Lead): number;\n}\n\n// 2. L'unique implémentation, déjà injectable via @Injectable()\n@Injectable()\nexport class StandardLeadScorer implements LeadScorer {\n  score(lead: Lead): number {\n    return lead.interactionCount * 10 + (lead.hasEmail ? 20 : 0);\n  }\n}\n\n// 3. La factory superflue, jamais utilisée par le DI NestJS\nexport class LeadScorerFactory {\n  static create(type: string): LeadScorer {\n    return new StandardLeadScorer();\n  }\n}\n",[2444],{"type":31,"tag":169,"props":2445,"children":2446},{"__ignoreMap":8},[2447,2455,2478,2521,2528,2535,2543,2563,2593,2632,2710,2718,2725,2732,2740,2760,2807,2833,2840],{"type":31,"tag":1904,"props":2448,"children":2449},{"class":1906,"line":1907},[2450],{"type":31,"tag":1904,"props":2451,"children":2452},{"style":1911},[2453],{"type":40,"value":2454},"// 1. L'interface\n",{"type":31,"tag":1904,"props":2456,"children":2457},{"class":1906,"line":817},[2458,2463,2468,2474],{"type":31,"tag":1904,"props":2459,"children":2460},{"style":1920},[2461],{"type":40,"value":2462},"export",{"type":31,"tag":1904,"props":2464,"children":2465},{"style":1920},[2466],{"type":40,"value":2467}," interface",{"type":31,"tag":1904,"props":2469,"children":2471},{"style":2470},"--shiki-default:#E5C890;--shiki-default-font-style:italic;--shiki-dark:#B392F0;--shiki-dark-font-style:inherit",[2472],{"type":40,"value":2473}," LeadScorer",{"type":31,"tag":1904,"props":2475,"children":2476},{"style":1932},[2477],{"type":40,"value":2005},{"type":31,"tag":1904,"props":2479,"children":2480},{"class":1906,"line":1938},[2481,2486,2491,2496,2500,2505,2509,2513,2517],{"type":31,"tag":1904,"props":2482,"children":2483},{"style":1926},[2484],{"type":40,"value":2485},"  score",{"type":31,"tag":1904,"props":2487,"children":2488},{"style":1932},[2489],{"type":40,"value":2490},"(",{"type":31,"tag":1904,"props":2492,"children":2493},{"style":1942},[2494],{"type":40,"value":2495},"lead",{"type":31,"tag":1904,"props":2497,"children":2498},{"style":1948},[2499],{"type":40,"value":1951},{"type":31,"tag":1904,"props":2501,"children":2502},{"style":2470},[2503],{"type":40,"value":2504}," Lead",{"type":31,"tag":1904,"props":2506,"children":2507},{"style":1932},[2508],{"type":40,"value":1992},{"type":31,"tag":1904,"props":2510,"children":2511},{"style":1948},[2512],{"type":40,"value":1951},{"type":31,"tag":1904,"props":2514,"children":2515},{"style":1954},[2516],{"type":40,"value":1957},{"type":31,"tag":1904,"props":2518,"children":2519},{"style":1932},[2520],{"type":40,"value":2047},{"type":31,"tag":1904,"props":2522,"children":2523},{"class":1906,"line":1965},[2524],{"type":31,"tag":1904,"props":2525,"children":2526},{"style":1932},[2527],{"type":40,"value":2156},{"type":31,"tag":1904,"props":2529,"children":2530},{"class":1906,"line":1986},[2531],{"type":31,"tag":1904,"props":2532,"children":2533},{"emptyLinePlaceholder":13},[2534],{"type":40,"value":2165},{"type":31,"tag":1904,"props":2536,"children":2537},{"class":1906,"line":2008},[2538],{"type":31,"tag":1904,"props":2539,"children":2540},{"style":1911},[2541],{"type":40,"value":2542},"// 2. L'unique implémentation, déjà injectable via @Injectable()\n",{"type":31,"tag":1904,"props":2544,"children":2545},{"class":1906,"line":2050},[2546,2552,2557],{"type":31,"tag":1904,"props":2547,"children":2549},{"style":2548},"--shiki-default:#8CAAEE;--shiki-default-font-style:italic;--shiki-dark:#E1E4E8;--shiki-dark-font-style:inherit",[2550],{"type":40,"value":2551},"@",{"type":31,"tag":1904,"props":2553,"children":2554},{"style":1926},[2555],{"type":40,"value":2556},"Injectable",{"type":31,"tag":1904,"props":2558,"children":2560},{"style":2559},"--shiki-default:#EF9F76;--shiki-dark:#E1E4E8",[2561],{"type":40,"value":2562},"()\n",{"type":31,"tag":1904,"props":2564,"children":2565},{"class":1906,"line":2094},[2566,2570,2575,2580,2585,2589],{"type":31,"tag":1904,"props":2567,"children":2568},{"style":1920},[2569],{"type":40,"value":2462},{"type":31,"tag":1904,"props":2571,"children":2572},{"style":1920},[2573],{"type":40,"value":2574}," class",{"type":31,"tag":1904,"props":2576,"children":2577},{"style":2470},[2578],{"type":40,"value":2579}," StandardLeadScorer",{"type":31,"tag":1904,"props":2581,"children":2582},{"style":1920},[2583],{"type":40,"value":2584}," implements",{"type":31,"tag":1904,"props":2586,"children":2587},{"style":2470},[2588],{"type":40,"value":2473},{"type":31,"tag":1904,"props":2590,"children":2591},{"style":1932},[2592],{"type":40,"value":2005},{"type":31,"tag":1904,"props":2594,"children":2595},{"class":1906,"line":2150},[2596,2600,2604,2608,2612,2616,2620,2624,2628],{"type":31,"tag":1904,"props":2597,"children":2598},{"style":1926},[2599],{"type":40,"value":2485},{"type":31,"tag":1904,"props":2601,"children":2602},{"style":1932},[2603],{"type":40,"value":2490},{"type":31,"tag":1904,"props":2605,"children":2606},{"style":1942},[2607],{"type":40,"value":2495},{"type":31,"tag":1904,"props":2609,"children":2610},{"style":1948},[2611],{"type":40,"value":1951},{"type":31,"tag":1904,"props":2613,"children":2614},{"style":2470},[2615],{"type":40,"value":2504},{"type":31,"tag":1904,"props":2617,"children":2618},{"style":1932},[2619],{"type":40,"value":1992},{"type":31,"tag":1904,"props":2621,"children":2622},{"style":1948},[2623],{"type":40,"value":1951},{"type":31,"tag":1904,"props":2625,"children":2626},{"style":1954},[2627],{"type":40,"value":1957},{"type":31,"tag":1904,"props":2629,"children":2630},{"style":1932},[2631],{"type":40,"value":2005},{"type":31,"tag":1904,"props":2633,"children":2634},{"class":1906,"line":2159},[2635,2640,2645,2649,2654,2658,2663,2668,2673,2677,2682,2687,2692,2697,2702,2706],{"type":31,"tag":1904,"props":2636,"children":2637},{"style":1920},[2638],{"type":40,"value":2639},"    return",{"type":31,"tag":1904,"props":2641,"children":2642},{"style":2028},[2643],{"type":40,"value":2644}," lead",{"type":31,"tag":1904,"props":2646,"children":2647},{"style":2108},[2648],{"type":40,"value":76},{"type":31,"tag":1904,"props":2650,"children":2651},{"style":2028},[2652],{"type":40,"value":2653},"interactionCount ",{"type":31,"tag":1904,"props":2655,"children":2656},{"style":1948},[2657],{"type":40,"value":2125},{"type":31,"tag":1904,"props":2659,"children":2660},{"style":2039},[2661],{"type":40,"value":2662}," 10",{"type":31,"tag":1904,"props":2664,"children":2665},{"style":1948},[2666],{"type":40,"value":2667}," +",{"type":31,"tag":1904,"props":2669,"children":2670},{"style":2028},[2671],{"type":40,"value":2672}," (lead",{"type":31,"tag":1904,"props":2674,"children":2675},{"style":2108},[2676],{"type":40,"value":76},{"type":31,"tag":1904,"props":2678,"children":2679},{"style":2028},[2680],{"type":40,"value":2681},"hasEmail ",{"type":31,"tag":1904,"props":2683,"children":2684},{"style":1948},[2685],{"type":40,"value":2686},"?",{"type":31,"tag":1904,"props":2688,"children":2689},{"style":2039},[2690],{"type":40,"value":2691}," 20",{"type":31,"tag":1904,"props":2693,"children":2694},{"style":1948},[2695],{"type":40,"value":2696}," :",{"type":31,"tag":1904,"props":2698,"children":2699},{"style":2039},[2700],{"type":40,"value":2701}," 0",{"type":31,"tag":1904,"props":2703,"children":2704},{"style":2028},[2705],{"type":40,"value":1992},{"type":31,"tag":1904,"props":2707,"children":2708},{"style":1932},[2709],{"type":40,"value":2047},{"type":31,"tag":1904,"props":2711,"children":2712},{"class":1906,"line":2168},[2713],{"type":31,"tag":1904,"props":2714,"children":2715},{"style":1932},[2716],{"type":40,"value":2717},"  }\n",{"type":31,"tag":1904,"props":2719,"children":2720},{"class":1906,"line":2177},[2721],{"type":31,"tag":1904,"props":2722,"children":2723},{"style":1932},[2724],{"type":40,"value":2156},{"type":31,"tag":1904,"props":2726,"children":2727},{"class":1906,"line":2194},[2728],{"type":31,"tag":1904,"props":2729,"children":2730},{"emptyLinePlaceholder":13},[2731],{"type":40,"value":2165},{"type":31,"tag":1904,"props":2733,"children":2734},{"class":1906,"line":2215},[2735],{"type":31,"tag":1904,"props":2736,"children":2737},{"style":1911},[2738],{"type":40,"value":2739},"// 3. La factory superflue, jamais utilisée par le DI NestJS\n",{"type":31,"tag":1904,"props":2741,"children":2742},{"class":1906,"line":2236},[2743,2747,2751,2756],{"type":31,"tag":1904,"props":2744,"children":2745},{"style":1920},[2746],{"type":40,"value":2462},{"type":31,"tag":1904,"props":2748,"children":2749},{"style":1920},[2750],{"type":40,"value":2574},{"type":31,"tag":1904,"props":2752,"children":2753},{"style":2470},[2754],{"type":40,"value":2755}," LeadScorerFactory",{"type":31,"tag":1904,"props":2757,"children":2758},{"style":1932},[2759],{"type":40,"value":2005},{"type":31,"tag":1904,"props":2761,"children":2762},{"class":1906,"line":2256},[2763,2768,2773,2777,2782,2786,2791,2795,2799,2803],{"type":31,"tag":1904,"props":2764,"children":2765},{"style":1920},[2766],{"type":40,"value":2767},"  static",{"type":31,"tag":1904,"props":2769,"children":2770},{"style":1926},[2771],{"type":40,"value":2772}," create",{"type":31,"tag":1904,"props":2774,"children":2775},{"style":1932},[2776],{"type":40,"value":2490},{"type":31,"tag":1904,"props":2778,"children":2779},{"style":1942},[2780],{"type":40,"value":2781},"type",{"type":31,"tag":1904,"props":2783,"children":2784},{"style":1948},[2785],{"type":40,"value":1951},{"type":31,"tag":1904,"props":2787,"children":2788},{"style":1954},[2789],{"type":40,"value":2790}," string",{"type":31,"tag":1904,"props":2792,"children":2793},{"style":1932},[2794],{"type":40,"value":1992},{"type":31,"tag":1904,"props":2796,"children":2797},{"style":1948},[2798],{"type":40,"value":1951},{"type":31,"tag":1904,"props":2800,"children":2801},{"style":2470},[2802],{"type":40,"value":2473},{"type":31,"tag":1904,"props":2804,"children":2805},{"style":1932},[2806],{"type":40,"value":2005},{"type":31,"tag":1904,"props":2808,"children":2809},{"class":1906,"line":2290},[2810,2814,2820,2824,2829],{"type":31,"tag":1904,"props":2811,"children":2812},{"style":1920},[2813],{"type":40,"value":2639},{"type":31,"tag":1904,"props":2815,"children":2817},{"style":2816},"--shiki-default:#CA9EE6;--shiki-default-font-weight:bold;--shiki-dark:#F97583;--shiki-dark-font-weight:inherit",[2818],{"type":40,"value":2819}," new",{"type":31,"tag":1904,"props":2821,"children":2822},{"style":1926},[2823],{"type":40,"value":2579},{"type":31,"tag":1904,"props":2825,"children":2826},{"style":2028},[2827],{"type":40,"value":2828},"()",{"type":31,"tag":1904,"props":2830,"children":2831},{"style":1932},[2832],{"type":40,"value":2047},{"type":31,"tag":1904,"props":2834,"children":2835},{"class":1906,"line":2333},[2836],{"type":31,"tag":1904,"props":2837,"children":2838},{"style":1932},[2839],{"type":40,"value":2717},{"type":31,"tag":1904,"props":2841,"children":2842},{"class":1906,"line":2382},[2843],{"type":31,"tag":1904,"props":2844,"children":2845},{"style":1932},[2846],{"type":40,"value":2156},{"type":31,"tag":32,"props":2848,"children":2849},{},[2850,2852,2858,2860,2866],{"type":40,"value":2851},"Une interface, un ",{"type":31,"tag":169,"props":2853,"children":2855},{"className":2854},[],[2856],{"type":40,"value":2857},"@Injectable()",{"type":40,"value":2859},", une factory. Pour calculer un score avec 2 opérations. Une seule implémentation concrète. NestJS injecte directement ",{"type":31,"tag":169,"props":2861,"children":2863},{"className":2862},[],[2864],{"type":40,"value":2865},"StandardLeadScorer",{"type":40,"value":2867}," partout. La factory n'est appelée nulle part, sauf dans un test. Aucun besoin d'inversion réel.",{"type":31,"tag":32,"props":2869,"children":2870},{},[2871],{"type":40,"value":2872},"Cette sur-ingénierie a un coût concret. À chaque modification, vous passez par 3 fichiers au lieu d'un. Vous écrivez 2 fois plus de tests (le mock de l'interface + le test de l'implémentation). Vous augmentez la charge cognitive pour tout nouveau dev. Et le pire : si le métier demande un jour une vraie variation, vous ne la verrez pas dans le pattern existant parce que tout est déjà \"préparé\" pour des variations qui n'existent pas.",{"type":31,"tag":32,"props":2874,"children":2875},{},[2876,2878,2883,2885,2890,2892,2898,2900,2906],{"type":40,"value":2877},"Le contre-pattern craft, c'est ce que Martin Fowler appelait ",{"type":31,"tag":97,"props":2879,"children":2880},{},[2881],{"type":40,"value":2882},"\"Rule of Three\"",{"type":40,"value":2884}," dans ",{"type":31,"tag":97,"props":2886,"children":2887},{},[2888],{"type":40,"value":2889},"Refactoring",{"type":40,"value":2891}," (2018). Vous ne créez une abstraction qu'à partir du troisième cas concret. Si une fonction n'a qu'une implémentation, c'est une fonction. Pas une interface, pas une factory, pas une classe abstraite. Une fonction. C'est exactement la philosophie défendue dans ",{"type":31,"tag":69,"props":2893,"children":2895},{"href":2894},"/fr/dette-technique/yagni-ecrire-code-qualite-sans-fonctionnalites-inutiles",[2896],{"type":40,"value":2897},"YAGNI : écrire du code de qualité sans fonctionnalités inutiles",{"type":40,"value":2899}," et dans le ",{"type":31,"tag":69,"props":2901,"children":2903},{"href":2902},"/fr/dette-technique/principe-kiss-bonnes-pratiques-java",[2904],{"type":40,"value":2905},"principe KISS appliqué en Java",{"type":40,"value":76},{"type":31,"tag":32,"props":2908,"children":2909},{},[2910],{"type":40,"value":2911},"Sur le crmcoaching, j'ai 47 use cases sans aucune interface devant eux. Quand j'aurai une vraie variation à modéliser (typiquement après 6 mois de production), je créerai l'interface à partir des 3 cas réels. Pas avant.",{"type":31,"tag":48,"props":2913,"children":2914},{},[],{"type":31,"tag":229,"props":2916,"children":2918},{"cta":231,"href":232,"title":2917,"type":234},"Vous voulez repérer ces abstractions accidentelles dans vos PR Claude avant de les merger ?",[2919],{"type":31,"tag":32,"props":2920,"children":2921},{},[2922],{"type":40,"value":2923},"Refuser une interface inutile ou une factory qui ne sert à rien, ça ne s'apprend pas en lisant un article : ça se travaille sur votre propre code. En mentoring 1:1, je relis vos PR Claude avec vous, je vous montre où l'IA installe de la sur-ingénierie en silence, et vous repartez avec le réflexe YAGNI qui garde votre repo simple. C'est du face à face pour monter en niveau, pas un audit d'équipe.",{"type":31,"tag":48,"props":2925,"children":2926},{},[],{"type":31,"tag":52,"props":2928,"children":2930},{"id":2929},"faux-ami-3-la-sur-ingénierie-déguisée",[2931],{"type":40,"value":2932},"Faux ami #3 : la sur-ingénierie déguisée",{"type":31,"tag":32,"props":2934,"children":2935},{},[2936],{"type":40,"value":2937},"Le troisième faux ami est le plus visible mais le plus accepté. Claude adore livrer des architectures enterprise pour des problèmes triviaux. Vous demandez un handler pour récupérer un client par id, vous recevez :",{"type":31,"tag":1894,"props":2939,"children":2941},{"className":1896,"code":2940,"language":1898,"meta":8,"style":8},"// QueryHandler + ClientRepositoryPort + EventBusPort + MetricsPort + 2 adapters\n@Injectable()\nexport class GetClientQueryHandler {\n  constructor(\n    private readonly clientRepository: ClientRepositoryPort,\n    private readonly eventBus: EventBusPort,\n    private readonly metrics: MetricsPort,\n  ) {}\n\n  async handle(query: GetClientQuery): Promise\u003CGetClientResult> {\n    const client = await this.clientRepository.findById(query.clientId);\n    if (!client) {\n      throw new ClientNotFoundException(query.clientId);\n    }\n    await this.eventBus.publish(new ClientRetrievedEvent(query.clientId));\n    this.metrics.increment('client.retrieved');\n    return new GetClientResult(client);\n  }\n}\n",[2942],{"type":31,"tag":169,"props":2943,"children":2944},{"__ignoreMap":8},[2945,2953,2968,2988,3000,3031,3060,3089,3102,3109,3173,3237,3265,3298,3306,3367,3411,3436,3443],{"type":31,"tag":1904,"props":2946,"children":2947},{"class":1906,"line":1907},[2948],{"type":31,"tag":1904,"props":2949,"children":2950},{"style":1911},[2951],{"type":40,"value":2952},"// QueryHandler + ClientRepositoryPort + EventBusPort + MetricsPort + 2 adapters\n",{"type":31,"tag":1904,"props":2954,"children":2955},{"class":1906,"line":817},[2956,2960,2964],{"type":31,"tag":1904,"props":2957,"children":2958},{"style":2548},[2959],{"type":40,"value":2551},{"type":31,"tag":1904,"props":2961,"children":2962},{"style":1926},[2963],{"type":40,"value":2556},{"type":31,"tag":1904,"props":2965,"children":2966},{"style":2559},[2967],{"type":40,"value":2562},{"type":31,"tag":1904,"props":2969,"children":2970},{"class":1906,"line":1938},[2971,2975,2979,2984],{"type":31,"tag":1904,"props":2972,"children":2973},{"style":1920},[2974],{"type":40,"value":2462},{"type":31,"tag":1904,"props":2976,"children":2977},{"style":1920},[2978],{"type":40,"value":2574},{"type":31,"tag":1904,"props":2980,"children":2981},{"style":2470},[2982],{"type":40,"value":2983}," GetClientQueryHandler",{"type":31,"tag":1904,"props":2985,"children":2986},{"style":1932},[2987],{"type":40,"value":2005},{"type":31,"tag":1904,"props":2989,"children":2990},{"class":1906,"line":1965},[2991,2996],{"type":31,"tag":1904,"props":2992,"children":2993},{"style":1920},[2994],{"type":40,"value":2995},"  constructor",{"type":31,"tag":1904,"props":2997,"children":2998},{"style":1932},[2999],{"type":40,"value":1935},{"type":31,"tag":1904,"props":3001,"children":3002},{"class":1906,"line":1986},[3003,3008,3013,3018,3022,3027],{"type":31,"tag":1904,"props":3004,"children":3005},{"style":1920},[3006],{"type":40,"value":3007},"    private",{"type":31,"tag":1904,"props":3009,"children":3010},{"style":1920},[3011],{"type":40,"value":3012}," readonly",{"type":31,"tag":1904,"props":3014,"children":3015},{"style":1942},[3016],{"type":40,"value":3017}," clientRepository",{"type":31,"tag":1904,"props":3019,"children":3020},{"style":1948},[3021],{"type":40,"value":1951},{"type":31,"tag":1904,"props":3023,"children":3024},{"style":2470},[3025],{"type":40,"value":3026}," ClientRepositoryPort",{"type":31,"tag":1904,"props":3028,"children":3029},{"style":1932},[3030],{"type":40,"value":1962},{"type":31,"tag":1904,"props":3032,"children":3033},{"class":1906,"line":2008},[3034,3038,3042,3047,3051,3056],{"type":31,"tag":1904,"props":3035,"children":3036},{"style":1920},[3037],{"type":40,"value":3007},{"type":31,"tag":1904,"props":3039,"children":3040},{"style":1920},[3041],{"type":40,"value":3012},{"type":31,"tag":1904,"props":3043,"children":3044},{"style":1942},[3045],{"type":40,"value":3046}," eventBus",{"type":31,"tag":1904,"props":3048,"children":3049},{"style":1948},[3050],{"type":40,"value":1951},{"type":31,"tag":1904,"props":3052,"children":3053},{"style":2470},[3054],{"type":40,"value":3055}," EventBusPort",{"type":31,"tag":1904,"props":3057,"children":3058},{"style":1932},[3059],{"type":40,"value":1962},{"type":31,"tag":1904,"props":3061,"children":3062},{"class":1906,"line":2050},[3063,3067,3071,3076,3080,3085],{"type":31,"tag":1904,"props":3064,"children":3065},{"style":1920},[3066],{"type":40,"value":3007},{"type":31,"tag":1904,"props":3068,"children":3069},{"style":1920},[3070],{"type":40,"value":3012},{"type":31,"tag":1904,"props":3072,"children":3073},{"style":1942},[3074],{"type":40,"value":3075}," metrics",{"type":31,"tag":1904,"props":3077,"children":3078},{"style":1948},[3079],{"type":40,"value":1951},{"type":31,"tag":1904,"props":3081,"children":3082},{"style":2470},[3083],{"type":40,"value":3084}," MetricsPort",{"type":31,"tag":1904,"props":3086,"children":3087},{"style":1932},[3088],{"type":40,"value":1962},{"type":31,"tag":1904,"props":3090,"children":3091},{"class":1906,"line":2094},[3092,3097],{"type":31,"tag":1904,"props":3093,"children":3094},{"style":1932},[3095],{"type":40,"value":3096},"  )",{"type":31,"tag":1904,"props":3098,"children":3099},{"style":1932},[3100],{"type":40,"value":3101}," {}\n",{"type":31,"tag":1904,"props":3103,"children":3104},{"class":1906,"line":2150},[3105],{"type":31,"tag":1904,"props":3106,"children":3107},{"emptyLinePlaceholder":13},[3108],{"type":40,"value":2165},{"type":31,"tag":1904,"props":3110,"children":3111},{"class":1906,"line":2159},[3112,3117,3122,3126,3131,3135,3140,3144,3148,3153,3159,3164,3169],{"type":31,"tag":1904,"props":3113,"children":3114},{"style":1920},[3115],{"type":40,"value":3116},"  async",{"type":31,"tag":1904,"props":3118,"children":3119},{"style":1926},[3120],{"type":40,"value":3121}," handle",{"type":31,"tag":1904,"props":3123,"children":3124},{"style":1932},[3125],{"type":40,"value":2490},{"type":31,"tag":1904,"props":3127,"children":3128},{"style":1942},[3129],{"type":40,"value":3130},"query",{"type":31,"tag":1904,"props":3132,"children":3133},{"style":1948},[3134],{"type":40,"value":1951},{"type":31,"tag":1904,"props":3136,"children":3137},{"style":2470},[3138],{"type":40,"value":3139}," GetClientQuery",{"type":31,"tag":1904,"props":3141,"children":3142},{"style":1932},[3143],{"type":40,"value":1992},{"type":31,"tag":1904,"props":3145,"children":3146},{"style":1948},[3147],{"type":40,"value":1951},{"type":31,"tag":1904,"props":3149,"children":3150},{"style":2470},[3151],{"type":40,"value":3152}," Promise",{"type":31,"tag":1904,"props":3154,"children":3156},{"style":3155},"--shiki-default:#99D1DB;--shiki-dark:#E1E4E8",[3157],{"type":40,"value":3158},"\u003C",{"type":31,"tag":1904,"props":3160,"children":3161},{"style":2470},[3162],{"type":40,"value":3163},"GetClientResult",{"type":31,"tag":1904,"props":3165,"children":3166},{"style":3155},[3167],{"type":40,"value":3168},">",{"type":31,"tag":1904,"props":3170,"children":3171},{"style":1932},[3172],{"type":40,"value":2005},{"type":31,"tag":1904,"props":3174,"children":3175},{"class":1906,"line":2168},[3176,3181,3186,3190,3195,3201,3205,3210,3214,3219,3224,3228,3233],{"type":31,"tag":1904,"props":3177,"children":3178},{"style":1920},[3179],{"type":40,"value":3180},"    const",{"type":31,"tag":1904,"props":3182,"children":3183},{"style":2017},[3184],{"type":40,"value":3185}," client",{"type":31,"tag":1904,"props":3187,"children":3188},{"style":1948},[3189],{"type":40,"value":2025},{"type":31,"tag":1904,"props":3191,"children":3192},{"style":1920},[3193],{"type":40,"value":3194}," await",{"type":31,"tag":1904,"props":3196,"children":3198},{"style":3197},"--shiki-default:#E78284;--shiki-dark:#79B8FF",[3199],{"type":40,"value":3200}," this",{"type":31,"tag":1904,"props":3202,"children":3203},{"style":2108},[3204],{"type":40,"value":76},{"type":31,"tag":1904,"props":3206,"children":3207},{"style":2028},[3208],{"type":40,"value":3209},"clientRepository",{"type":31,"tag":1904,"props":3211,"children":3212},{"style":2108},[3213],{"type":40,"value":76},{"type":31,"tag":1904,"props":3215,"children":3216},{"style":1926},[3217],{"type":40,"value":3218},"findById",{"type":31,"tag":1904,"props":3220,"children":3221},{"style":2028},[3222],{"type":40,"value":3223},"(query",{"type":31,"tag":1904,"props":3225,"children":3226},{"style":2108},[3227],{"type":40,"value":76},{"type":31,"tag":1904,"props":3229,"children":3230},{"style":2028},[3231],{"type":40,"value":3232},"clientId)",{"type":31,"tag":1904,"props":3234,"children":3235},{"style":1932},[3236],{"type":40,"value":2047},{"type":31,"tag":1904,"props":3238,"children":3239},{"class":1906,"line":2177},[3240,3245,3250,3255,3260],{"type":31,"tag":1904,"props":3241,"children":3242},{"style":1920},[3243],{"type":40,"value":3244},"    if",{"type":31,"tag":1904,"props":3246,"children":3247},{"style":2028},[3248],{"type":40,"value":3249}," (",{"type":31,"tag":1904,"props":3251,"children":3252},{"style":1948},[3253],{"type":40,"value":3254},"!",{"type":31,"tag":1904,"props":3256,"children":3257},{"style":2028},[3258],{"type":40,"value":3259},"client) ",{"type":31,"tag":1904,"props":3261,"children":3262},{"style":1932},[3263],{"type":40,"value":3264},"{\n",{"type":31,"tag":1904,"props":3266,"children":3267},{"class":1906,"line":2194},[3268,3273,3277,3282,3286,3290,3294],{"type":31,"tag":1904,"props":3269,"children":3270},{"style":1920},[3271],{"type":40,"value":3272},"      throw",{"type":31,"tag":1904,"props":3274,"children":3275},{"style":2816},[3276],{"type":40,"value":2819},{"type":31,"tag":1904,"props":3278,"children":3279},{"style":1926},[3280],{"type":40,"value":3281}," ClientNotFoundException",{"type":31,"tag":1904,"props":3283,"children":3284},{"style":2028},[3285],{"type":40,"value":3223},{"type":31,"tag":1904,"props":3287,"children":3288},{"style":2108},[3289],{"type":40,"value":76},{"type":31,"tag":1904,"props":3291,"children":3292},{"style":2028},[3293],{"type":40,"value":3232},{"type":31,"tag":1904,"props":3295,"children":3296},{"style":1932},[3297],{"type":40,"value":2047},{"type":31,"tag":1904,"props":3299,"children":3300},{"class":1906,"line":2215},[3301],{"type":31,"tag":1904,"props":3302,"children":3303},{"style":1932},[3304],{"type":40,"value":3305},"    }\n",{"type":31,"tag":1904,"props":3307,"children":3308},{"class":1906,"line":2236},[3309,3314,3318,3322,3327,3331,3336,3340,3345,3350,3354,3358,3363],{"type":31,"tag":1904,"props":3310,"children":3311},{"style":1920},[3312],{"type":40,"value":3313},"    await",{"type":31,"tag":1904,"props":3315,"children":3316},{"style":3197},[3317],{"type":40,"value":3200},{"type":31,"tag":1904,"props":3319,"children":3320},{"style":2108},[3321],{"type":40,"value":76},{"type":31,"tag":1904,"props":3323,"children":3324},{"style":2028},[3325],{"type":40,"value":3326},"eventBus",{"type":31,"tag":1904,"props":3328,"children":3329},{"style":2108},[3330],{"type":40,"value":76},{"type":31,"tag":1904,"props":3332,"children":3333},{"style":1926},[3334],{"type":40,"value":3335},"publish",{"type":31,"tag":1904,"props":3337,"children":3338},{"style":2028},[3339],{"type":40,"value":2490},{"type":31,"tag":1904,"props":3341,"children":3342},{"style":2816},[3343],{"type":40,"value":3344},"new",{"type":31,"tag":1904,"props":3346,"children":3347},{"style":1926},[3348],{"type":40,"value":3349}," ClientRetrievedEvent",{"type":31,"tag":1904,"props":3351,"children":3352},{"style":2028},[3353],{"type":40,"value":3223},{"type":31,"tag":1904,"props":3355,"children":3356},{"style":2108},[3357],{"type":40,"value":76},{"type":31,"tag":1904,"props":3359,"children":3360},{"style":2028},[3361],{"type":40,"value":3362},"clientId))",{"type":31,"tag":1904,"props":3364,"children":3365},{"style":1932},[3366],{"type":40,"value":2047},{"type":31,"tag":1904,"props":3368,"children":3369},{"class":1906,"line":2256},[3370,3375,3379,3384,3388,3393,3397,3403,3407],{"type":31,"tag":1904,"props":3371,"children":3372},{"style":3197},[3373],{"type":40,"value":3374},"    this",{"type":31,"tag":1904,"props":3376,"children":3377},{"style":2108},[3378],{"type":40,"value":76},{"type":31,"tag":1904,"props":3380,"children":3381},{"style":2028},[3382],{"type":40,"value":3383},"metrics",{"type":31,"tag":1904,"props":3385,"children":3386},{"style":2108},[3387],{"type":40,"value":76},{"type":31,"tag":1904,"props":3389,"children":3390},{"style":1926},[3391],{"type":40,"value":3392},"increment",{"type":31,"tag":1904,"props":3394,"children":3395},{"style":2028},[3396],{"type":40,"value":2490},{"type":31,"tag":1904,"props":3398,"children":3400},{"style":3399},"--shiki-default:#A6D189;--shiki-dark:#9ECBFF",[3401],{"type":40,"value":3402},"'client.retrieved'",{"type":31,"tag":1904,"props":3404,"children":3405},{"style":2028},[3406],{"type":40,"value":1992},{"type":31,"tag":1904,"props":3408,"children":3409},{"style":1932},[3410],{"type":40,"value":2047},{"type":31,"tag":1904,"props":3412,"children":3413},{"class":1906,"line":2290},[3414,3418,3422,3427,3432],{"type":31,"tag":1904,"props":3415,"children":3416},{"style":1920},[3417],{"type":40,"value":2639},{"type":31,"tag":1904,"props":3419,"children":3420},{"style":2816},[3421],{"type":40,"value":2819},{"type":31,"tag":1904,"props":3423,"children":3424},{"style":1926},[3425],{"type":40,"value":3426}," GetClientResult",{"type":31,"tag":1904,"props":3428,"children":3429},{"style":2028},[3430],{"type":40,"value":3431},"(client)",{"type":31,"tag":1904,"props":3433,"children":3434},{"style":1932},[3435],{"type":40,"value":2047},{"type":31,"tag":1904,"props":3437,"children":3438},{"class":1906,"line":2333},[3439],{"type":31,"tag":1904,"props":3440,"children":3441},{"style":1932},[3442],{"type":40,"value":2717},{"type":31,"tag":1904,"props":3444,"children":3445},{"class":1906,"line":2382},[3446],{"type":31,"tag":1904,"props":3447,"children":3448},{"style":1932},[3449],{"type":40,"value":2156},{"type":31,"tag":32,"props":3451,"children":3452},{},[3453,3455,3461],{"type":40,"value":3454},"30 lignes, 4 fichiers, 3 ports, 1 event qui n'est lu par personne. Pour faire ",{"type":31,"tag":169,"props":3456,"children":3458},{"className":3457},[],[3459],{"type":40,"value":3460},"prisma.client.findUnique({ where: { id } })",{"type":40,"value":3462},". Le coût direct : 4x plus de code à lire pour un nouveau dev. Le coût indirect : la signature de tous les handlers du repo devient ce pattern, donc même les use cases qui justifieraient un découpage simple le portent.",{"type":31,"tag":32,"props":3464,"children":3465},{},[3466],{"type":40,"value":3467},"Le contre-pattern, c'est le principe de proportionnalité. Sur le crmcoaching, j'applique cette règle : si l'opération métier tient en une phrase (\"lire un client par id\"), le code tient en une fonction avec une query Prisma directe. Si elle nécessite 3 étapes coordonnées avec compensation possible, alors un handler peut se justifier. Sinon, c'est de la dette emballée en pattern.",{"type":31,"tag":32,"props":3469,"children":3470},{},[3471,3473,3478,3480,3485],{"type":40,"value":3472},"Robert C. Martin, dans ",{"type":31,"tag":97,"props":3474,"children":3475},{},[3476],{"type":40,"value":3477},"Clean Architecture",{"type":40,"value":3479}," (2017), insiste sur ce point : l'architecture doit ",{"type":31,"tag":97,"props":3481,"children":3482},{},[3483],{"type":40,"value":3484},"suivre",{"type":40,"value":3486}," la complexité du domaine, pas la précéder. Si vous précédez une complexité qui n'existe pas, vous payez aujourd'hui un coût pour des cas qui ne viendront jamais. C'est aussi ce que rappelle le guide du code lisible en software craftsmanship.",{"type":31,"tag":48,"props":3488,"children":3489},{},[],{"type":31,"tag":52,"props":3491,"children":3493},{"id":3492},"calcul-du-vrai-coût-caché",[3494],{"type":40,"value":3495},"Calcul du vrai coût caché",{"type":31,"tag":32,"props":3497,"children":3498},{},[3499],{"type":40,"value":3500},"J'ai mesuré le coût cumulé des 3 faux amis en comparant mes commits de début de projet (avant discipline) avec l'état actuel de crmcoaching. Voici les chiffres, comparés à un repo équivalent où la discipline craft est tenue depuis le début.",{"type":31,"tag":398,"props":3502,"children":3503},{},[3504,3524],{"type":31,"tag":402,"props":3505,"children":3506},{},[3507],{"type":31,"tag":406,"props":3508,"children":3509},{},[3510,3514,3519],{"type":31,"tag":410,"props":3511,"children":3512},{},[3513],{"type":40,"value":1198},{"type":31,"tag":410,"props":3515,"children":3516},{},[3517],{"type":40,"value":3518},"Repo IA non audité",{"type":31,"tag":410,"props":3520,"children":3521},{},[3522],{"type":40,"value":3523},"Repo IA + discipline craft",{"type":31,"tag":426,"props":3525,"children":3526},{},[3527,3545,3563,3581,3599],{"type":31,"tag":406,"props":3528,"children":3529},{},[3530,3535,3540],{"type":31,"tag":433,"props":3531,"children":3532},{},[3533],{"type":40,"value":3534},"Temps moyen pour ajouter une feature simple",{"type":31,"tag":433,"props":3536,"children":3537},{},[3538],{"type":40,"value":3539},"3,5 jours",{"type":31,"tag":433,"props":3541,"children":3542},{},[3543],{"type":40,"value":3544},"1,2 jour",{"type":31,"tag":406,"props":3546,"children":3547},{},[3548,3553,3558],{"type":31,"tag":433,"props":3549,"children":3550},{},[3551],{"type":40,"value":3552},"Temps moyen pour modifier une feature existante",{"type":31,"tag":433,"props":3554,"children":3555},{},[3556],{"type":40,"value":3557},"5 jours",{"type":31,"tag":433,"props":3559,"children":3560},{},[3561],{"type":40,"value":3562},"1,8 jour",{"type":31,"tag":406,"props":3564,"children":3565},{},[3566,3571,3576],{"type":31,"tag":433,"props":3567,"children":3568},{},[3569],{"type":40,"value":3570},"Onboarding d'un nouveau dev (jusqu'à 1ère PR mergée)",{"type":31,"tag":433,"props":3572,"children":3573},{},[3574],{"type":40,"value":3575},"7 semaines",{"type":31,"tag":433,"props":3577,"children":3578},{},[3579],{"type":40,"value":3580},"3 semaines",{"type":31,"tag":406,"props":3582,"children":3583},{},[3584,3589,3594],{"type":31,"tag":433,"props":3585,"children":3586},{},[3587],{"type":40,"value":3588},"Bugs régression par release",{"type":31,"tag":433,"props":3590,"children":3591},{},[3592],{"type":40,"value":3593},"4-6",{"type":31,"tag":433,"props":3595,"children":3596},{},[3597],{"type":40,"value":3598},"0-1",{"type":31,"tag":406,"props":3600,"children":3601},{},[3602,3607,3612],{"type":31,"tag":433,"props":3603,"children":3604},{},[3605],{"type":40,"value":3606},"Lignes de code pour 1 use case métier",{"type":31,"tag":433,"props":3608,"children":3609},{},[3610],{"type":40,"value":3611},"280 LOC en moyenne",{"type":31,"tag":433,"props":3613,"children":3614},{},[3615],{"type":40,"value":3616},"95 LOC en moyenne",{"type":31,"tag":32,"props":3618,"children":3619},{},[3620],{"type":40,"value":3621},"Le ratio est de 1 à 3 sur la plupart des métriques. Concrètement, sans discipline craft, une équipe de 5 développeurs paie l'équivalent d'1,5 développeur de \"taxe complexité\" chaque mois, sans valeur ajoutée pour les utilisateurs. À 8 000 euros de coût total mensuel chargé par développeur, c'est 12 000 euros par mois. 144 000 euros par an. Sans qu'aucune feature ne s'ajoute en plus.",{"type":31,"tag":32,"props":3623,"children":3624},{},[3625,3627,3633],{"type":40,"value":3626},"C'est le coût silencieux dont je parle quand je dis qu'une codebase IA-heavy non auditée coûte cher, et c'est l'angle business que je détaille dans ",{"type":31,"tag":69,"props":3628,"children":3630},{"href":3629},"/fr/dette-technique/ingenierie-logicielle-avantage-concurrentiel",[3631],{"type":40,"value":3632},"l'ingénierie logicielle comme avantage concurrentiel",{"type":40,"value":3634},". Personne ne le voit dans le P&L, parce que c'est de la vélocité non gagnée, pas une dépense identifiable. Mais il est là.",{"type":31,"tag":48,"props":3636,"children":3637},{},[],{"type":31,"tag":52,"props":3639,"children":3641},{"id":3640},"la-règle-2026-yagni-ai",[3642],{"type":40,"value":3643},"La règle 2026 : YAGNI + AI",{"type":31,"tag":32,"props":3645,"children":3646},{},[3647],{"type":40,"value":3648},"Voici la règle que j'applique sur crmcoaching et que je recommande à toutes les équipes IA-heavy.",{"type":31,"tag":32,"props":3650,"children":3651},{},[3652,3657],{"type":31,"tag":36,"props":3653,"children":3654},{},[3655],{"type":40,"value":3656},"Règle 1 : pas d'abstraction sans 3 implémentations réelles.",{"type":40,"value":3658}," Pas d'interface devant une seule classe. Pas de factory pour 1 type. Pas de port hexagonal devant un module qui ne peut pas être remplacé. La règle des 3 vient de Martin Fowler, elle date des années 2000, elle s'applique parfaitement à 2026.",{"type":31,"tag":32,"props":3660,"children":3661},{},[3662,3667,3669,3674],{"type":31,"tag":36,"props":3663,"children":3664},{},[3665],{"type":40,"value":3666},"Règle 2 : avant chaque PR Claude, prompter \"cherche les doublons\".",{"type":40,"value":3668}," ",{"type":31,"tag":97,"props":3670,"children":3671},{},[3672],{"type":40,"value":3673},"\"Avant de finaliser, vérifie dans le repo s'il existe déjà une fonction qui fait à 80% la même chose. Si oui, refactore pour mutualiser plutôt que dupliquer.\"",{"type":40,"value":3675}," Claude le fait très bien quand on lui demande. Il ne le fait jamais spontanément.",{"type":31,"tag":32,"props":3677,"children":3678},{},[3679,3684],{"type":31,"tag":36,"props":3680,"children":3681},{},[3682],{"type":40,"value":3683},"Règle 3 : proportionnalité code/domaine.",{"type":40,"value":3685}," Une opération métier triviale = une fonction. Une opération métier coordonnée = un handler/service. Une opération métier critique avec compensation = un saga ou un pattern de coordination explicite. Le code suit le domaine, pas l'inverse.",{"type":31,"tag":32,"props":3687,"children":3688},{},[3689,3694],{"type":31,"tag":36,"props":3690,"children":3691},{},[3692],{"type":40,"value":3693},"Règle 4 : audit des LOC par feature.",{"type":40,"value":3695}," Je mesure tous les 3 mois le nombre de lignes ajoutées par feature livrée. Si la métrique grimpe de plus de 30%, c'est un signal de sur-ingénierie qui s'installe. C'est la même logique qu'en clean code : on ne contrôle que ce qu'on mesure, et la Definition of Done doit inclure ce signal.",{"type":31,"tag":32,"props":3697,"children":3698},{},[3699],{"type":40,"value":3700},"Avec ces 4 règles, le repo crmcoaching tourne à environ 95 LOC par use case métier complet (avec tests + adapter + handler). C'est 3x moins que la moyenne IA-heavy que je vois sur des repos partagés. C'est aussi 3x plus rapide à modifier.",{"type":31,"tag":48,"props":3702,"children":3703},{},[],{"type":31,"tag":52,"props":3705,"children":3706},{"id":1463},[3707],{"type":40,"value":1466},{"type":31,"tag":32,"props":3709,"children":3710},{},[3711],{"type":40,"value":3712},"Sur les 3 dernières missions où j'ai installé cette discipline (audit + refacto + grille de review), voici les chiffres avant/après mesurés sur 6 mois.",{"type":31,"tag":398,"props":3714,"children":3715},{},[3716,3736],{"type":31,"tag":402,"props":3717,"children":3718},{},[3719],{"type":31,"tag":406,"props":3720,"children":3721},{},[3722,3726,3731],{"type":31,"tag":410,"props":3723,"children":3724},{},[3725],{"type":40,"value":1198},{"type":31,"tag":410,"props":3727,"children":3728},{},[3729],{"type":40,"value":3730},"Avant audit",{"type":31,"tag":410,"props":3732,"children":3733},{},[3734],{"type":40,"value":3735},"Après 6 mois",{"type":31,"tag":426,"props":3737,"children":3738},{},[3739,3757,3775,3792,3808],{"type":31,"tag":406,"props":3740,"children":3741},{},[3742,3747,3752],{"type":31,"tag":433,"props":3743,"children":3744},{},[3745],{"type":40,"value":3746},"LOC moyennes par use case",{"type":31,"tag":433,"props":3748,"children":3749},{},[3750],{"type":40,"value":3751},"280",{"type":31,"tag":433,"props":3753,"children":3754},{},[3755],{"type":40,"value":3756},"110",{"type":31,"tag":406,"props":3758,"children":3759},{},[3760,3765,3770],{"type":31,"tag":433,"props":3761,"children":3762},{},[3763],{"type":40,"value":3764},"Fonctions dupliquées dans le repo",{"type":31,"tag":433,"props":3766,"children":3767},{},[3768],{"type":40,"value":3769},"47",{"type":31,"tag":433,"props":3771,"children":3772},{},[3773],{"type":40,"value":3774},"8",{"type":31,"tag":406,"props":3776,"children":3777},{},[3778,3783,3787],{"type":31,"tag":433,"props":3779,"children":3780},{},[3781],{"type":40,"value":3782},"Temps d'onboarding d'un nouveau dev",{"type":31,"tag":433,"props":3784,"children":3785},{},[3786],{"type":40,"value":3575},{"type":31,"tag":433,"props":3788,"children":3789},{},[3790],{"type":40,"value":3791},"4 semaines",{"type":31,"tag":406,"props":3793,"children":3794},{},[3795,3800,3804],{"type":31,"tag":433,"props":3796,"children":3797},{},[3798],{"type":40,"value":3799},"Bugs de régression par release",{"type":31,"tag":433,"props":3801,"children":3802},{},[3803],{"type":40,"value":3593},{"type":31,"tag":433,"props":3805,"children":3806},{},[3807],{"type":40,"value":3598},{"type":31,"tag":406,"props":3809,"children":3810},{},[3811,3816,3821],{"type":31,"tag":433,"props":3812,"children":3813},{},[3814],{"type":40,"value":3815},"Vélocité (story points/sprint)",{"type":31,"tag":433,"props":3817,"children":3818},{},[3819],{"type":40,"value":3820},"stable",{"type":31,"tag":433,"props":3822,"children":3823},{},[3824],{"type":40,"value":3825},"+28%",{"type":31,"tag":32,"props":3827,"children":3828},{},[3829,3831,3835,3837,3842,3844,3848],{"type":40,"value":3830},"Le gain n'est pas qu'esthétique. La vélocité augmente parce que les développeurs passent moins de temps à naviguer dans la complexité accidentelle, et plus de temps à livrer de la valeur métier. C'est ce que la DORA mesure quand elle parle de ",{"type":31,"tag":97,"props":3832,"children":3833},{},[3834],{"type":40,"value":898},{"type":40,"value":3836}," et de ",{"type":31,"tag":97,"props":3838,"children":3839},{},[3840],{"type":40,"value":3841},"stability",{"type":40,"value":3843}," combinés, et c'est précisément le levier qu'une ",{"type":31,"tag":69,"props":3845,"children":3846},{"href":148},[3847],{"type":40,"value":151},{"type":40,"value":3849}," permet d'enclencher.",{"type":31,"tag":48,"props":3851,"children":3852},{},[],{"type":31,"tag":52,"props":3854,"children":3855},{"id":637},[3856],{"type":40,"value":640},{"type":31,"tag":32,"props":3858,"children":3859},{},[3860],{"type":40,"value":3861},"Ce que je veux que vous reteniez de cet article, c'est que le code Claude \"qui marche\" n'est pas une garantie de qualité, c'est une garantie de fonctionnement à T0. La qualité d'un code se mesure à 3 mois, à 6 mois, à 12 mois, sur le coût de modification et le temps d'onboarding. Les 3 faux amis que j'ai décrits (copier-coller, abstractions accidentelles, sur-ingénierie) sont les 3 mécanismes qui font diverger ce coût silencieusement.",{"type":31,"tag":32,"props":3863,"children":3864},{},[3865],{"type":40,"value":3866},"La règle YAGNI + AI, ce n'est pas du conservatisme. C'est une discipline économique. Vous économisez aujourd'hui sur du code que vous n'écrivez pas, ce qui réduit la complexité que vous porterez demain. Quand le besoin réel émerge (3 implémentations, vraie variation, vraie criticité), vous créez l'abstraction à ce moment-là, avec la connaissance que la pratique vous a donnée. Pas avant.",{"type":31,"tag":32,"props":3868,"children":3869},{},[3870],{"type":40,"value":3871},"Si en lisant ces lignes vous reconnaissez votre situation, vous avez deux choix. Vous pouvez continuer à accepter les PR Claude qui ajoutent 280 LOC pour un use case qui en demande 95. Ou vous pouvez commencer lundi matin, par une grille de 4 règles, et reprendre le contrôle du coût caché de votre codebase.",{"type":31,"tag":32,"props":3873,"children":3874},{},[3875,3877,3882],{"type":40,"value":3876},"Pour la suite des patterns craft que je documente chaque semaine sur crmcoaching, retrouvez-moi sur ",{"type":31,"tag":69,"props":3878,"children":3880},{"href":663,"rel":3879},[665],[3881],{"type":40,"value":668},{"type":40,"value":76},{"type":31,"tag":229,"props":3884,"children":3886},{"cta":673,"href":674,"title":3885,"type":676},"La règle des 3 et le réflexe anti-doublons ne sont que 2 pratiques sur 100",[3887],{"type":31,"tag":32,"props":3888,"children":3889},{},[3890],{"type":40,"value":3891},"Cet article détaille une poignée de pratiques craft qui neutralisent la sur-ingénierie IA-générée. Le Craft Bundle réunit les 100 pratiques que j'applique pour garder un code simple et modifiable : le référentiel complet de ce que je vérifie sur chaque PR Claude. Ce sont celles que l'IA ne vous apprendra jamais, parce qu'elle ne les a jamais vues coûter cher en production.",{"type":31,"tag":48,"props":3893,"children":3894},{},[],{"type":31,"tag":52,"props":3896,"children":3898},{"id":3897},"faq-sur-les-faux-amis-claude-et-le-coût-caché",[3899],{"type":40,"value":3900},"FAQ sur les faux amis Claude et le coût caché",{"type":31,"tag":693,"props":3902,"children":3903},{},[3904,3909],{"type":31,"tag":697,"props":3905,"children":3906},{},[3907],{"type":40,"value":3908},"1. Comment détecter les doublons dans un repo TypeScript de taille moyenne ?",{"type":31,"tag":32,"props":3910,"children":3911},{},[3912],{"type":40,"value":3913},"Trois outils combinés font le travail. D'abord jscpd (Copy-Paste Detector, compatible TS/JS) : sortie rapide des blocs dupliqués sur tout repo, configurable par seuil de tokens. Ensuite SonarQube en mode \"duplications\" : vue agrégée sur le repo entier. Enfin, des passes Grep ciblées sur les noms de domaine (\"calculate\", \"compute\", \"process\") pour repérer les paires sémantiquement proches mais nommées différemment. L'arsenal complet est détaillé dans les outils d'analyse statique en 2026.",{"type":31,"tag":693,"props":3915,"children":3916},{},[3917,3922],{"type":31,"tag":697,"props":3918,"children":3919},{},[3920],{"type":40,"value":3921},"2. La règle des 3 implémentations n'empêche-t-elle pas l'architecture hexagonale ?",{"type":31,"tag":32,"props":3923,"children":3924},{},[3925,3927,3933],{"type":40,"value":3926},"Non, parce que ",{"type":31,"tag":69,"props":3928,"children":3930},{"href":3929},"/fr/architecture-craft/architecture-hexagonale-java-exemples-bonnes-pratiques",[3931],{"type":40,"value":3932},"l'architecture hexagonale",{"type":40,"value":3934}," est justifiée par la testabilité, pas par la variation d'implémentation. Vous créez un port pour pouvoir tester avec un fake en mémoire. C'est 1 implémentation réelle + 1 fake de test : ça compte pour 2. Si en plus vous avez une vraie variation (Postgres + Redis, ou SMTP + Brevo), vous êtes à 3. La règle s'applique aux abstractions purement spéculatives, pas à celles qui ont une justification claire et nommée.",{"type":31,"tag":693,"props":3936,"children":3937},{},[3938,3943],{"type":31,"tag":697,"props":3939,"children":3940},{},[3941],{"type":40,"value":3942},"3. Comment convaincre une équipe attachée aux patterns enterprise ?",{"type":31,"tag":32,"props":3944,"children":3945},{},[3946],{"type":40,"value":3947},"Avec des chiffres sur leur propre repo. Comptez les interfaces qui n'ont qu'une implémentation, comptez les factories appelées une seule fois, comptez les LOC par use case. Présentez ça en revue d'architecture. Personne ne défend une factory inutilisée quand elle apparaît dans un tableau à côté de \"temps d'onboarding +4 semaines\". Le débat passe du dogme à l'économique.",{"type":31,"tag":693,"props":3949,"children":3950},{},[3951,3956],{"type":31,"tag":697,"props":3952,"children":3953},{},[3954],{"type":40,"value":3955},"4. Quel rapport entre ces faux amis et la code review IA ?",{"type":31,"tag":32,"props":3957,"children":3958},{},[3959],{"type":40,"value":3960},"Direct. Une revue de code IA-générée doit poser systématiquement 3 questions : \"Y a-t-il un doublon ailleurs dans le repo ?\", \"Cette abstraction est-elle justifiée par 3 cas réels ?\", \"La complexité de cette solution est-elle proportionnelle au besoin métier ?\". Ces 3 questions, en 2 minutes par PR, attrapent 80% des 3 faux amis avant le merge.",{"type":31,"tag":693,"props":3962,"children":3963},{},[3964,3969],{"type":31,"tag":697,"props":3965,"children":3966},{},[3967],{"type":40,"value":3968},"5. Le code Claude qui suit cette discipline est-il toujours du code \"généré par IA\" ?",{"type":31,"tag":32,"props":3970,"children":3971},{},[3972],{"type":40,"value":3973},"C'est une bonne question, et la réponse est : oui, mais pas par n'importe quel prompt. Le code Claude bien promté (avec contraintes YAGNI + recherche de doublons + proportionnalité) reste majoritairement du code IA-généré. Le développeur ajoute le contexte et la discipline. Claude exécute. C'est exactement la collaboration qu'on cherche : l'IA fait le travail mécanique, l'humain garde le jugement architectural.",{"type":31,"tag":693,"props":3975,"children":3976},{},[3977,3982],{"type":31,"tag":697,"props":3978,"children":3979},{},[3980],{"type":40,"value":3981},"6. Quelle est la métrique unique à suivre pour mesurer ces 3 faux amis ?",{"type":31,"tag":32,"props":3983,"children":3984},{},[3985,3987,3992],{"type":40,"value":3986},"Le ratio LOC par story point livré, mesuré sur 3 sprints glissants. Si la métrique monte, vous accumulez de la complexité accidentelle. Si elle baisse à valeur métier équivalente, vous gagnez en simplicité. C'est la métrique méta qui agrège les 3 faux amis sans avoir à les détecter individuellement, et c'est aussi un sujet que je détaille dans ",{"type":31,"tag":69,"props":3988,"children":3989},{"href":289},[3990],{"type":40,"value":3991},"l'illusion de productivité IA",{"type":40,"value":76},{"type":31,"tag":48,"props":3994,"children":3995},{},[],{"type":31,"tag":229,"props":3997,"children":3998},{"cta":806,"href":807,"title":808,"type":809},[3999],{"type":31,"tag":32,"props":4000,"children":4001},{},[4002],{"type":40,"value":4003},"L'EMA est l'outil que je propose au début de chaque mission. Il mesure la maturité de votre équipe sur plusieurs axes engineering : qualité du code, gouvernance IA, dette technique, vélocité réelle vs vélocité perçue. Quelques minutes pour identifier lequel des 3 faux amis s'installe le plus vite dans votre repo, et où concentrer vos efforts en priorité.",{"type":31,"tag":4005,"props":4006,"children":4007},"style",{},[4008],{"type":40,"value":4009},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":8,"searchDepth":817,"depth":817,"links":4011},[4012,4013,4014,4015,4016,4017,4018,4019,4020],{"id":1782,"depth":817,"text":1785},{"id":1863,"depth":817,"text":1866},{"id":2431,"depth":817,"text":2434},{"id":2929,"depth":817,"text":2932},{"id":3492,"depth":817,"text":3495},{"id":3640,"depth":817,"text":3643},{"id":1463,"depth":817,"text":1466},{"id":637,"depth":817,"text":640},{"id":3897,"depth":817,"text":3900},"content:fr:intelligence-artificielle:faux-ami-code-claude-coute-cher.md","fr/intelligence-artificielle/faux-ami-code-claude-coute-cher.md","fr/intelligence-artificielle/faux-ami-code-claude-coute-cher",{"_path":211,"_dir":6,"_draft":7,"_partial":7,"_locale":8,"title":4025,"description":4026,"id":4027,"date":4028,"listed":13,"nocomments":7,"hidden":13,"categories":4029,"tags":4030,"cover":4034,"readingTime":4035,"body":4039,"_type":830,"_id":9190,"_source":832,"_file":9191,"_stem":9192,"_extension":835},"Tous les tests sont verts, et 3 jours plus tard ça plante en prod","Pourquoi les tests Claude couvrent le happy path mais ratent les pannes réelles. Les 4 tests manquants et le wrapper anti-fragile à exiger.",64,"2026-05-10",[6],[4031,4032,16,4033,19],"tests","resilience","ci-cd","covers/articles/code-claude-tests-passent-plante-prod.jpg",{"text":1758,"minutes":4036,"time":4037,"words":4038},13.74,824400,2748,{"type":28,"children":4040,"toc":9175},[4041,4049,4054,4057,4063,4082,4095,4123,4141,4144,4150,4155,4684,4712,4740,4745,4757,4760,4769,4772,4778,4783,4790,4810,5539,5556,5562,5567,6163,6168,6174,6179,6719,6724,6730,6735,7224,7229,7232,7238,7250,7273,7278,8754,8773,8776,8782,8794,8811,8829,8839,8851,8854,8858,8863,8961,8973,8976,8980,8985,8990,8995,9007,9016,9019,9025,9038,9051,9102,9115,9133,9160,9163,9171],{"type":31,"tag":32,"props":4042,"children":4043},{},[4044],{"type":31,"tag":36,"props":4045,"children":4046},{},[4047],{"type":40,"value":4048},"Un mardi matin de janvier 2026, je reçois une alerte sur crmcoaching, mon SaaS pour coachs professionnels que je développe seul avec Claude. La notification de confirmation de séance avait planté toute la nuit. La CI était verte. Les tests passaient. Je ne comprenais pas. Trois heures plus tard, j'identifie le problème : plusieurs confirmations envoyées en parallèle au même moment, Brevo (mon provider d'emails transactionnels) avait appliqué son rate limit avec un 429, et le code que Claude avait généré n'avait jamais été testé sous cette condition.",{"type":31,"tag":32,"props":4050,"children":4051},{},[4052],{"type":40,"value":4053},"Ce n'était pas un bug Claude. C'était un bug de mes tests. Mes tests vérifiaient que la fonction marchait. Pas qu'elle survivait. Voici la différence, et les 4 tests que Claude n'écrit jamais spontanément, que vous devez exiger explicitement.",{"type":31,"tag":48,"props":4055,"children":4056},{},[],{"type":31,"tag":52,"props":4058,"children":4060},{"id":4059},"pourquoi-les-tests-claude-ne-couvrent-que-le-happy-path",[4061],{"type":40,"value":4062},"Pourquoi les tests Claude ne couvrent que le happy path",{"type":31,"tag":32,"props":4064,"children":4065},{},[4066,4068,4073,4075,4080],{"type":40,"value":4067},"Le constat est simple, et il est documenté. Selon le ",{"type":31,"tag":69,"props":4069,"children":4071},{"href":1793,"rel":4070},[665],[4072],{"type":40,"value":1797},{"type":40,"value":4074},", les équipes IA-heavy livrent en moyenne 35% plus de code. Mais le ratio de tests behavior-level reste stable, voire baisse. Le code grossit, le filet de tests ne suit pas. Ce déséquilibre est précisément ce que je détaille dans ",{"type":31,"tag":69,"props":4076,"children":4077},{"href":219},[4078],{"type":40,"value":4079},"la checklist pour tester du code généré par IA",{"type":40,"value":4081}," publiée en 2025.",{"type":31,"tag":32,"props":4083,"children":4084},{},[4085,4087,4093],{"type":40,"value":4086},"Pourquoi ? Parce que Claude génère des tests qui imitent le pattern moyen de son training data. Et ce pattern, c'est : un test par fonction, un mock par dépendance, une assertion sur le happy path. Si vous lui demandez \"écris des tests pour ",{"type":31,"tag":169,"props":4088,"children":4090},{"className":4089},[],[4091],{"type":40,"value":4092},"sendConfirmationEmail",{"type":40,"value":4094},"\", il vous livre un test qui vérifie que la méthode envoie un email quand tout va bien. Il ne vous livre pas le test où Brevo renvoie un 429. Il ne vous livre pas le test où la méthode est appelée 50 fois en parallèle. Il ne vous livre pas le test où le réseau timeout après 30 secondes.",{"type":31,"tag":78,"props":4096,"children":4097},{},[4098],{"type":31,"tag":32,"props":4099,"children":4100},{},[4101,4105,4107,4113,4115,4121],{"type":31,"tag":36,"props":4102,"children":4103},{},[4104],{"type":40,"value":930},{"type":40,"value":4106}," : j'ai compté les tests présents dans mon module ",{"type":31,"tag":169,"props":4108,"children":4110},{"className":4109},[],[4111],{"type":40,"value":4112},"notification",{"type":40,"value":4114},". Des dizaines de tests, une couverture de lignes correcte. Aucun ne simulait une réponse 429 de Brevo. Aucun ne simulait un timeout. Aucun ne lançait plus de 5 appels en parallèle via ",{"type":31,"tag":169,"props":4116,"children":4118},{"className":4117},[],[4119],{"type":40,"value":4120},"Promise.all",{"type":40,"value":4122},". Le filet de tests avait l'air dense, mais il était plein de trous sur les conditions réelles de production.",{"type":31,"tag":32,"props":4124,"children":4125},{},[4126,4128,4132,4134,4139],{"type":40,"value":4127},"Michael Nygard a écrit dans ",{"type":31,"tag":97,"props":4129,"children":4130},{},[4131],{"type":40,"value":790},{"type":40,"value":4133}," (2007, deuxième édition 2018) : ",{"type":31,"tag":97,"props":4135,"children":4136},{},[4137],{"type":40,"value":4138},"\"Every feature in production must be hardened by tests of failure modes, not just success modes.\"",{"type":40,"value":4140}," En 2026, Claude accélère la production de features, mais il n'accélère pas la production de tests de modes d'échec. Le ratio se déséquilibre, et la prod paie. C'est aussi la racine de la dérive que je décris dans le diagnostic du legacy à risque que personne n'avait vu venir.",{"type":31,"tag":48,"props":4142,"children":4143},{},[],{"type":31,"tag":52,"props":4145,"children":4147},{"id":4146},"le-scénario-du-crash-brevo-rate-limit-sur-crmcoaching",[4148],{"type":40,"value":4149},"Le scénario du crash Brevo rate-limit sur crmcoaching",{"type":31,"tag":32,"props":4151,"children":4152},{},[4153],{"type":40,"value":4154},"Reprenons le code que Claude avait généré pour l'envoi des confirmations de séance. Voici la version simplifiée, en TypeScript NestJS :",{"type":31,"tag":1894,"props":4156,"children":4158},{"className":1896,"code":4157,"language":1898,"meta":8,"style":8},"// apps/api/src/infrastructure/notification/brevo-notification.service.ts\n\n@Injectable()\nexport class BrevoNotificationService {\n  constructor(\n    private readonly sessionRepository: SessionRepository,\n    private readonly brevoClient: BrevoClient,\n  ) {}\n\n  async sendSessionConfirmation(sessionId: string): Promise\u003Cvoid> {\n    const session = await this.sessionRepository.findById(sessionId);\n    if (!session) throw new Error(`Session not found: ${sessionId}`);\n\n    await this.brevoClient.sendTransactionalEmail({\n      to: [{ email: session.coacheeEmail }],\n      templateId: BREVO_TEMPLATE_IDS.SESSION_CONFIRMATION,\n      params: { sessionDate: session.scheduledAt },\n    });\n  }\n}\n",[4159],{"type":31,"tag":169,"props":4160,"children":4161},{"__ignoreMap":8},[4162,4170,4177,4192,4212,4223,4252,4281,4292,4299,4357,4407,4478,4485,4522,4579,4609,4653,4669,4676],{"type":31,"tag":1904,"props":4163,"children":4164},{"class":1906,"line":1907},[4165],{"type":31,"tag":1904,"props":4166,"children":4167},{"style":1911},[4168],{"type":40,"value":4169},"// apps/api/src/infrastructure/notification/brevo-notification.service.ts\n",{"type":31,"tag":1904,"props":4171,"children":4172},{"class":1906,"line":817},[4173],{"type":31,"tag":1904,"props":4174,"children":4175},{"emptyLinePlaceholder":13},[4176],{"type":40,"value":2165},{"type":31,"tag":1904,"props":4178,"children":4179},{"class":1906,"line":1938},[4180,4184,4188],{"type":31,"tag":1904,"props":4181,"children":4182},{"style":2548},[4183],{"type":40,"value":2551},{"type":31,"tag":1904,"props":4185,"children":4186},{"style":1926},[4187],{"type":40,"value":2556},{"type":31,"tag":1904,"props":4189,"children":4190},{"style":2559},[4191],{"type":40,"value":2562},{"type":31,"tag":1904,"props":4193,"children":4194},{"class":1906,"line":1965},[4195,4199,4203,4208],{"type":31,"tag":1904,"props":4196,"children":4197},{"style":1920},[4198],{"type":40,"value":2462},{"type":31,"tag":1904,"props":4200,"children":4201},{"style":1920},[4202],{"type":40,"value":2574},{"type":31,"tag":1904,"props":4204,"children":4205},{"style":2470},[4206],{"type":40,"value":4207}," BrevoNotificationService",{"type":31,"tag":1904,"props":4209,"children":4210},{"style":1932},[4211],{"type":40,"value":2005},{"type":31,"tag":1904,"props":4213,"children":4214},{"class":1906,"line":1986},[4215,4219],{"type":31,"tag":1904,"props":4216,"children":4217},{"style":1920},[4218],{"type":40,"value":2995},{"type":31,"tag":1904,"props":4220,"children":4221},{"style":1932},[4222],{"type":40,"value":1935},{"type":31,"tag":1904,"props":4224,"children":4225},{"class":1906,"line":2008},[4226,4230,4234,4239,4243,4248],{"type":31,"tag":1904,"props":4227,"children":4228},{"style":1920},[4229],{"type":40,"value":3007},{"type":31,"tag":1904,"props":4231,"children":4232},{"style":1920},[4233],{"type":40,"value":3012},{"type":31,"tag":1904,"props":4235,"children":4236},{"style":1942},[4237],{"type":40,"value":4238}," sessionRepository",{"type":31,"tag":1904,"props":4240,"children":4241},{"style":1948},[4242],{"type":40,"value":1951},{"type":31,"tag":1904,"props":4244,"children":4245},{"style":2470},[4246],{"type":40,"value":4247}," SessionRepository",{"type":31,"tag":1904,"props":4249,"children":4250},{"style":1932},[4251],{"type":40,"value":1962},{"type":31,"tag":1904,"props":4253,"children":4254},{"class":1906,"line":2050},[4255,4259,4263,4268,4272,4277],{"type":31,"tag":1904,"props":4256,"children":4257},{"style":1920},[4258],{"type":40,"value":3007},{"type":31,"tag":1904,"props":4260,"children":4261},{"style":1920},[4262],{"type":40,"value":3012},{"type":31,"tag":1904,"props":4264,"children":4265},{"style":1942},[4266],{"type":40,"value":4267}," brevoClient",{"type":31,"tag":1904,"props":4269,"children":4270},{"style":1948},[4271],{"type":40,"value":1951},{"type":31,"tag":1904,"props":4273,"children":4274},{"style":2470},[4275],{"type":40,"value":4276}," BrevoClient",{"type":31,"tag":1904,"props":4278,"children":4279},{"style":1932},[4280],{"type":40,"value":1962},{"type":31,"tag":1904,"props":4282,"children":4283},{"class":1906,"line":2094},[4284,4288],{"type":31,"tag":1904,"props":4285,"children":4286},{"style":1932},[4287],{"type":40,"value":3096},{"type":31,"tag":1904,"props":4289,"children":4290},{"style":1932},[4291],{"type":40,"value":3101},{"type":31,"tag":1904,"props":4293,"children":4294},{"class":1906,"line":2150},[4295],{"type":31,"tag":1904,"props":4296,"children":4297},{"emptyLinePlaceholder":13},[4298],{"type":40,"value":2165},{"type":31,"tag":1904,"props":4300,"children":4301},{"class":1906,"line":2159},[4302,4306,4311,4315,4320,4324,4328,4332,4336,4340,4344,4349,4353],{"type":31,"tag":1904,"props":4303,"children":4304},{"style":1920},[4305],{"type":40,"value":3116},{"type":31,"tag":1904,"props":4307,"children":4308},{"style":1926},[4309],{"type":40,"value":4310}," sendSessionConfirmation",{"type":31,"tag":1904,"props":4312,"children":4313},{"style":1932},[4314],{"type":40,"value":2490},{"type":31,"tag":1904,"props":4316,"children":4317},{"style":1942},[4318],{"type":40,"value":4319},"sessionId",{"type":31,"tag":1904,"props":4321,"children":4322},{"style":1948},[4323],{"type":40,"value":1951},{"type":31,"tag":1904,"props":4325,"children":4326},{"style":1954},[4327],{"type":40,"value":2790},{"type":31,"tag":1904,"props":4329,"children":4330},{"style":1932},[4331],{"type":40,"value":1992},{"type":31,"tag":1904,"props":4333,"children":4334},{"style":1948},[4335],{"type":40,"value":1951},{"type":31,"tag":1904,"props":4337,"children":4338},{"style":2470},[4339],{"type":40,"value":3152},{"type":31,"tag":1904,"props":4341,"children":4342},{"style":3155},[4343],{"type":40,"value":3158},{"type":31,"tag":1904,"props":4345,"children":4346},{"style":1954},[4347],{"type":40,"value":4348},"void",{"type":31,"tag":1904,"props":4350,"children":4351},{"style":3155},[4352],{"type":40,"value":3168},{"type":31,"tag":1904,"props":4354,"children":4355},{"style":1932},[4356],{"type":40,"value":2005},{"type":31,"tag":1904,"props":4358,"children":4359},{"class":1906,"line":2168},[4360,4364,4369,4373,4377,4381,4385,4390,4394,4398,4403],{"type":31,"tag":1904,"props":4361,"children":4362},{"style":1920},[4363],{"type":40,"value":3180},{"type":31,"tag":1904,"props":4365,"children":4366},{"style":2017},[4367],{"type":40,"value":4368}," session",{"type":31,"tag":1904,"props":4370,"children":4371},{"style":1948},[4372],{"type":40,"value":2025},{"type":31,"tag":1904,"props":4374,"children":4375},{"style":1920},[4376],{"type":40,"value":3194},{"type":31,"tag":1904,"props":4378,"children":4379},{"style":3197},[4380],{"type":40,"value":3200},{"type":31,"tag":1904,"props":4382,"children":4383},{"style":2108},[4384],{"type":40,"value":76},{"type":31,"tag":1904,"props":4386,"children":4387},{"style":2028},[4388],{"type":40,"value":4389},"sessionRepository",{"type":31,"tag":1904,"props":4391,"children":4392},{"style":2108},[4393],{"type":40,"value":76},{"type":31,"tag":1904,"props":4395,"children":4396},{"style":1926},[4397],{"type":40,"value":3218},{"type":31,"tag":1904,"props":4399,"children":4400},{"style":2028},[4401],{"type":40,"value":4402},"(sessionId)",{"type":31,"tag":1904,"props":4404,"children":4405},{"style":1932},[4406],{"type":40,"value":2047},{"type":31,"tag":1904,"props":4408,"children":4409},{"class":1906,"line":2177},[4410,4414,4418,4422,4427,4432,4436,4441,4445,4450,4456,4460,4465,4470,4474],{"type":31,"tag":1904,"props":4411,"children":4412},{"style":1920},[4413],{"type":40,"value":3244},{"type":31,"tag":1904,"props":4415,"children":4416},{"style":2028},[4417],{"type":40,"value":3249},{"type":31,"tag":1904,"props":4419,"children":4420},{"style":1948},[4421],{"type":40,"value":3254},{"type":31,"tag":1904,"props":4423,"children":4424},{"style":2028},[4425],{"type":40,"value":4426},"session) ",{"type":31,"tag":1904,"props":4428,"children":4429},{"style":1920},[4430],{"type":40,"value":4431},"throw",{"type":31,"tag":1904,"props":4433,"children":4434},{"style":2816},[4435],{"type":40,"value":2819},{"type":31,"tag":1904,"props":4437,"children":4438},{"style":1926},[4439],{"type":40,"value":4440}," Error",{"type":31,"tag":1904,"props":4442,"children":4443},{"style":2028},[4444],{"type":40,"value":2490},{"type":31,"tag":1904,"props":4446,"children":4447},{"style":3399},[4448],{"type":40,"value":4449},"`Session not found: ",{"type":31,"tag":1904,"props":4451,"children":4453},{"style":4452},"--shiki-default:#949CBB;--shiki-dark:#9ECBFF",[4454],{"type":40,"value":4455},"${",{"type":31,"tag":1904,"props":4457,"children":4458},{"style":2028},[4459],{"type":40,"value":4319},{"type":31,"tag":1904,"props":4461,"children":4462},{"style":4452},[4463],{"type":40,"value":4464},"}",{"type":31,"tag":1904,"props":4466,"children":4467},{"style":3399},[4468],{"type":40,"value":4469},"`",{"type":31,"tag":1904,"props":4471,"children":4472},{"style":2028},[4473],{"type":40,"value":1992},{"type":31,"tag":1904,"props":4475,"children":4476},{"style":1932},[4477],{"type":40,"value":2047},{"type":31,"tag":1904,"props":4479,"children":4480},{"class":1906,"line":2194},[4481],{"type":31,"tag":1904,"props":4482,"children":4483},{"emptyLinePlaceholder":13},[4484],{"type":40,"value":2165},{"type":31,"tag":1904,"props":4486,"children":4487},{"class":1906,"line":2215},[4488,4492,4496,4500,4505,4509,4514,4518],{"type":31,"tag":1904,"props":4489,"children":4490},{"style":1920},[4491],{"type":40,"value":3313},{"type":31,"tag":1904,"props":4493,"children":4494},{"style":3197},[4495],{"type":40,"value":3200},{"type":31,"tag":1904,"props":4497,"children":4498},{"style":2108},[4499],{"type":40,"value":76},{"type":31,"tag":1904,"props":4501,"children":4502},{"style":2028},[4503],{"type":40,"value":4504},"brevoClient",{"type":31,"tag":1904,"props":4506,"children":4507},{"style":2108},[4508],{"type":40,"value":76},{"type":31,"tag":1904,"props":4510,"children":4511},{"style":1926},[4512],{"type":40,"value":4513},"sendTransactionalEmail",{"type":31,"tag":1904,"props":4515,"children":4516},{"style":2028},[4517],{"type":40,"value":2490},{"type":31,"tag":1904,"props":4519,"children":4520},{"style":1932},[4521],{"type":40,"value":3264},{"type":31,"tag":1904,"props":4523,"children":4524},{"class":1906,"line":2236},[4525,4530,4534,4539,4544,4549,4553,4557,4561,4566,4570,4575],{"type":31,"tag":1904,"props":4526,"children":4527},{"style":2028},[4528],{"type":40,"value":4529},"      to",{"type":31,"tag":1904,"props":4531,"children":4532},{"style":2108},[4533],{"type":40,"value":1951},{"type":31,"tag":1904,"props":4535,"children":4536},{"style":2028},[4537],{"type":40,"value":4538}," [",{"type":31,"tag":1904,"props":4540,"children":4541},{"style":1932},[4542],{"type":40,"value":4543},"{",{"type":31,"tag":1904,"props":4545,"children":4546},{"style":2028},[4547],{"type":40,"value":4548}," email",{"type":31,"tag":1904,"props":4550,"children":4551},{"style":2108},[4552],{"type":40,"value":1951},{"type":31,"tag":1904,"props":4554,"children":4555},{"style":2028},[4556],{"type":40,"value":4368},{"type":31,"tag":1904,"props":4558,"children":4559},{"style":2108},[4560],{"type":40,"value":76},{"type":31,"tag":1904,"props":4562,"children":4563},{"style":2028},[4564],{"type":40,"value":4565},"coacheeEmail ",{"type":31,"tag":1904,"props":4567,"children":4568},{"style":1932},[4569],{"type":40,"value":4464},{"type":31,"tag":1904,"props":4571,"children":4572},{"style":2028},[4573],{"type":40,"value":4574},"]",{"type":31,"tag":1904,"props":4576,"children":4577},{"style":1932},[4578],{"type":40,"value":1962},{"type":31,"tag":1904,"props":4580,"children":4581},{"class":1906,"line":2256},[4582,4587,4591,4596,4600,4605],{"type":31,"tag":1904,"props":4583,"children":4584},{"style":2028},[4585],{"type":40,"value":4586},"      templateId",{"type":31,"tag":1904,"props":4588,"children":4589},{"style":2108},[4590],{"type":40,"value":1951},{"type":31,"tag":1904,"props":4592,"children":4593},{"style":2039},[4594],{"type":40,"value":4595}," BREVO_TEMPLATE_IDS",{"type":31,"tag":1904,"props":4597,"children":4598},{"style":2108},[4599],{"type":40,"value":76},{"type":31,"tag":1904,"props":4601,"children":4602},{"style":2039},[4603],{"type":40,"value":4604},"SESSION_CONFIRMATION",{"type":31,"tag":1904,"props":4606,"children":4607},{"style":1932},[4608],{"type":40,"value":1962},{"type":31,"tag":1904,"props":4610,"children":4611},{"class":1906,"line":2290},[4612,4617,4621,4626,4631,4635,4639,4643,4648],{"type":31,"tag":1904,"props":4613,"children":4614},{"style":2028},[4615],{"type":40,"value":4616},"      params",{"type":31,"tag":1904,"props":4618,"children":4619},{"style":2108},[4620],{"type":40,"value":1951},{"type":31,"tag":1904,"props":4622,"children":4623},{"style":1932},[4624],{"type":40,"value":4625}," {",{"type":31,"tag":1904,"props":4627,"children":4628},{"style":2028},[4629],{"type":40,"value":4630}," sessionDate",{"type":31,"tag":1904,"props":4632,"children":4633},{"style":2108},[4634],{"type":40,"value":1951},{"type":31,"tag":1904,"props":4636,"children":4637},{"style":2028},[4638],{"type":40,"value":4368},{"type":31,"tag":1904,"props":4640,"children":4641},{"style":2108},[4642],{"type":40,"value":76},{"type":31,"tag":1904,"props":4644,"children":4645},{"style":2028},[4646],{"type":40,"value":4647},"scheduledAt ",{"type":31,"tag":1904,"props":4649,"children":4650},{"style":1932},[4651],{"type":40,"value":4652},"},\n",{"type":31,"tag":1904,"props":4654,"children":4655},{"class":1906,"line":2333},[4656,4661,4665],{"type":31,"tag":1904,"props":4657,"children":4658},{"style":1932},[4659],{"type":40,"value":4660},"    }",{"type":31,"tag":1904,"props":4662,"children":4663},{"style":2028},[4664],{"type":40,"value":1992},{"type":31,"tag":1904,"props":4666,"children":4667},{"style":1932},[4668],{"type":40,"value":2047},{"type":31,"tag":1904,"props":4670,"children":4671},{"class":1906,"line":2382},[4672],{"type":31,"tag":1904,"props":4673,"children":4674},{"style":1932},[4675],{"type":40,"value":2717},{"type":31,"tag":1904,"props":4677,"children":4679},{"class":1906,"line":4678},20,[4680],{"type":31,"tag":1904,"props":4681,"children":4682},{"style":1932},[4683],{"type":40,"value":2156},{"type":31,"tag":32,"props":4685,"children":4686},{},[4687,4689,4695,4696,4702,4704,4710],{"type":40,"value":4688},"Le code est propre, lisible, testable. Les tests unitaires Vitest mockaient ",{"type":31,"tag":169,"props":4690,"children":4692},{"className":4691},[],[4693],{"type":40,"value":4694},"sessionRepository.findById",{"type":40,"value":1884},{"type":31,"tag":169,"props":4697,"children":4699},{"className":4698},[],[4700],{"type":40,"value":4701},"brevoClient.sendTransactionalEmail",{"type":40,"value":4703}," avec ",{"type":31,"tag":169,"props":4705,"children":4707},{"className":4706},[],[4708],{"type":40,"value":4709},"vi.fn()",{"type":40,"value":4711},". Tous verts. Tous tautologiques.",{"type":31,"tag":32,"props":4713,"children":4714},{},[4715,4717,4723,4725,4730,4732,4738],{"type":40,"value":4716},"Voici ce qui s'est passé en prod. Un mardi à 2h47, mon job de rappel de séances a lancé plusieurs ",{"type":31,"tag":169,"props":4718,"children":4720},{"className":4719},[],[4721],{"type":40,"value":4722},"sendSessionConfirmation",{"type":40,"value":4724}," en parallèle via ",{"type":31,"tag":169,"props":4726,"children":4728},{"className":4727},[],[4729],{"type":40,"value":4120},{"type":40,"value":4731}," pour un groupe de coachees dont les séances étaient le lendemain matin. Brevo, comme tous les providers d'emails transactionnels, a un rate limit. À partir d'un certain nombre d'appels par seconde, il renvoie ",{"type":31,"tag":169,"props":4733,"children":4735},{"className":4734},[],[4736],{"type":40,"value":4737},"429 Too Many Requests",{"type":40,"value":4739},". Mon code ne gérait pas ce 429. L'exception remontait. Le job scheduler marquait les envois en échec. Aucun retry, parce que la stratégie de retry n'avait pas été codée pour ce service.",{"type":31,"tag":32,"props":4741,"children":4742},{},[4743],{"type":40,"value":4744},"Résultat : plusieurs coachees n'avaient pas reçu leur confirmation de séance. Certains ne s'étaient pas présentés le lendemain matin, pensant que la séance avait été annulée. La confiance envers le SaaS en avait pris un coup, et moi j'avais passé la matinée à déboguer au lieu de développer.",{"type":31,"tag":32,"props":4746,"children":4747},{},[4748,4750,4755],{"type":40,"value":4749},"Et tout ça parce qu'aucun test n'avait simulé ces 4 conditions de production. Le pire, c'est que les ",{"type":31,"tag":69,"props":4751,"children":4752},{"href":113},[4753],{"type":40,"value":4754},"principes de clean code et software craftsmanship",{"type":40,"value":4756}," auraient suffi à rendre cette fonction testable sous concurrence, mais je ne les avais pas formalisés dans mes prompts à Claude.",{"type":31,"tag":48,"props":4758,"children":4759},{},[],{"type":31,"tag":229,"props":4761,"children":4763},{"cta":231,"href":232,"title":4762,"type":234},"Vous voulez écrire vous-même les tests que Claude ne génère jamais ?",[4764],{"type":31,"tag":32,"props":4765,"children":4766},{},[4767],{"type":40,"value":4768},"Repérer un mode d'échec absent du filet de tests, ça ne s'apprend pas en lisant un article : ça se travaille. En mentoring 1:1, on prend votre vrai code généré par IA et on écrit ensemble les tests de concurrence, de rate limit et de timeout sur vos fonctions critiques. Vous repartez avec le réflexe d'exiger ces tests avant chaque merge, sans dépendre de personne.",{"type":31,"tag":48,"props":4770,"children":4771},{},[],{"type":31,"tag":52,"props":4773,"children":4775},{"id":4774},"les-4-tests-que-claude-nécrit-jamais",[4776],{"type":40,"value":4777},"Les 4 tests que Claude n'écrit jamais",{"type":31,"tag":32,"props":4779,"children":4780},{},[4781],{"type":40,"value":4782},"Voici les 4 tests que j'exige maintenant sur tout code Claude qui touche à une dépendance externe (réseau, DB, queue, file system). Les exemples sont en Vitest/TypeScript, dans le contexte crmcoaching.",{"type":31,"tag":4784,"props":4785,"children":4787},"h3",{"id":4786},"test-1-le-test-de-concurrence",[4788],{"type":40,"value":4789},"Test 1 : le test de concurrence",{"type":31,"tag":32,"props":4791,"children":4792},{},[4793,4795,4800,4802,4808],{"type":40,"value":4794},"Soumettez la fonction en parallèle via ",{"type":31,"tag":169,"props":4796,"children":4798},{"className":4797},[],[4799],{"type":40,"value":4120},{"type":40,"value":4801}," ou ",{"type":31,"tag":169,"props":4803,"children":4805},{"className":4804},[],[4806],{"type":40,"value":4807},"Promise.allSettled",{"type":40,"value":4809}," sur la même ressource ou avec des paramètres qui peuvent se télescoper. Vérifiez que l'état final est cohérent.",{"type":31,"tag":1894,"props":4811,"children":4813},{"className":1896,"code":4812,"language":1898,"meta":8,"style":8},"// apps/api/src/infrastructure/notification/brevo-notification.service.spec.ts\n\nit('handles 50 concurrent session confirmations without losing any', async () => {\n  const sessionIds = Array.from({ length: 50 }, (_, i) => `session-${i}`);\n\n  // mock : toutes les sessions existent, Brevo répond OK\n  vi.mocked(sessionRepository.findById).mockImplementation(async (id) => ({\n    id,\n    coacheeEmail: `coach-${id}@example.com`,\n    scheduledAt: new Date('2026-06-10T09:00:00Z'),\n  }));\n  vi.mocked(brevoClient.sendTransactionalEmail).mockResolvedValue(undefined);\n\n  const results = await Promise.allSettled(\n    sessionIds.map((id) => service.sendSessionConfirmation(id)),\n  );\n\n  const failed = results.filter((r) => r.status === 'rejected');\n  expect(failed).toHaveLength(0);\n  expect(brevoClient.sendTransactionalEmail).toHaveBeenCalledTimes(50);\n});\n",[4814],{"type":31,"tag":169,"props":4815,"children":4816},{"__ignoreMap":8},[4817,4825,4832,4873,4986,4993,5001,5075,5087,5125,5163,5180,5235,5242,5280,5339,5350,5357,5439,5478,5523],{"type":31,"tag":1904,"props":4818,"children":4819},{"class":1906,"line":1907},[4820],{"type":31,"tag":1904,"props":4821,"children":4822},{"style":1911},[4823],{"type":40,"value":4824},"// apps/api/src/infrastructure/notification/brevo-notification.service.spec.ts\n",{"type":31,"tag":1904,"props":4826,"children":4827},{"class":1906,"line":817},[4828],{"type":31,"tag":1904,"props":4829,"children":4830},{"emptyLinePlaceholder":13},[4831],{"type":40,"value":2165},{"type":31,"tag":1904,"props":4833,"children":4834},{"class":1906,"line":1938},[4835,4840,4844,4849,4854,4859,4864,4869],{"type":31,"tag":1904,"props":4836,"children":4837},{"style":1926},[4838],{"type":40,"value":4839},"it",{"type":31,"tag":1904,"props":4841,"children":4842},{"style":2028},[4843],{"type":40,"value":2490},{"type":31,"tag":1904,"props":4845,"children":4846},{"style":3399},[4847],{"type":40,"value":4848},"'handles 50 concurrent session confirmations without losing any'",{"type":31,"tag":1904,"props":4850,"children":4851},{"style":1932},[4852],{"type":40,"value":4853},",",{"type":31,"tag":1904,"props":4855,"children":4856},{"style":1920},[4857],{"type":40,"value":4858}," async",{"type":31,"tag":1904,"props":4860,"children":4861},{"style":1932},[4862],{"type":40,"value":4863}," ()",{"type":31,"tag":1904,"props":4865,"children":4866},{"style":1948},[4867],{"type":40,"value":4868}," =>",{"type":31,"tag":1904,"props":4870,"children":4871},{"style":1932},[4872],{"type":40,"value":2005},{"type":31,"tag":1904,"props":4874,"children":4875},{"class":1906,"line":1965},[4876,4880,4885,4889,4894,4898,4903,4907,4911,4916,4920,4925,4930,4934,4939,4943,4948,4952,4956,4961,4965,4970,4974,4978,4982],{"type":31,"tag":1904,"props":4877,"children":4878},{"style":1920},[4879],{"type":40,"value":2014},{"type":31,"tag":1904,"props":4881,"children":4882},{"style":2017},[4883],{"type":40,"value":4884}," sessionIds",{"type":31,"tag":1904,"props":4886,"children":4887},{"style":1948},[4888],{"type":40,"value":2025},{"type":31,"tag":1904,"props":4890,"children":4891},{"style":2028},[4892],{"type":40,"value":4893}," Array",{"type":31,"tag":1904,"props":4895,"children":4896},{"style":2108},[4897],{"type":40,"value":76},{"type":31,"tag":1904,"props":4899,"children":4900},{"style":1926},[4901],{"type":40,"value":4902},"from",{"type":31,"tag":1904,"props":4904,"children":4905},{"style":2028},[4906],{"type":40,"value":2490},{"type":31,"tag":1904,"props":4908,"children":4909},{"style":1932},[4910],{"type":40,"value":4543},{"type":31,"tag":1904,"props":4912,"children":4913},{"style":2028},[4914],{"type":40,"value":4915}," length",{"type":31,"tag":1904,"props":4917,"children":4918},{"style":2108},[4919],{"type":40,"value":1951},{"type":31,"tag":1904,"props":4921,"children":4922},{"style":2039},[4923],{"type":40,"value":4924}," 50",{"type":31,"tag":1904,"props":4926,"children":4927},{"style":1932},[4928],{"type":40,"value":4929}," },",{"type":31,"tag":1904,"props":4931,"children":4932},{"style":1932},[4933],{"type":40,"value":3249},{"type":31,"tag":1904,"props":4935,"children":4936},{"style":1942},[4937],{"type":40,"value":4938},"_",{"type":31,"tag":1904,"props":4940,"children":4941},{"style":1932},[4942],{"type":40,"value":4853},{"type":31,"tag":1904,"props":4944,"children":4945},{"style":1942},[4946],{"type":40,"value":4947}," i",{"type":31,"tag":1904,"props":4949,"children":4950},{"style":1932},[4951],{"type":40,"value":1992},{"type":31,"tag":1904,"props":4953,"children":4954},{"style":1948},[4955],{"type":40,"value":4868},{"type":31,"tag":1904,"props":4957,"children":4958},{"style":3399},[4959],{"type":40,"value":4960}," `session-",{"type":31,"tag":1904,"props":4962,"children":4963},{"style":4452},[4964],{"type":40,"value":4455},{"type":31,"tag":1904,"props":4966,"children":4967},{"style":2028},[4968],{"type":40,"value":4969},"i",{"type":31,"tag":1904,"props":4971,"children":4972},{"style":4452},[4973],{"type":40,"value":4464},{"type":31,"tag":1904,"props":4975,"children":4976},{"style":3399},[4977],{"type":40,"value":4469},{"type":31,"tag":1904,"props":4979,"children":4980},{"style":2028},[4981],{"type":40,"value":1992},{"type":31,"tag":1904,"props":4983,"children":4984},{"style":1932},[4985],{"type":40,"value":2047},{"type":31,"tag":1904,"props":4987,"children":4988},{"class":1906,"line":1986},[4989],{"type":31,"tag":1904,"props":4990,"children":4991},{"emptyLinePlaceholder":13},[4992],{"type":40,"value":2165},{"type":31,"tag":1904,"props":4994,"children":4995},{"class":1906,"line":2008},[4996],{"type":31,"tag":1904,"props":4997,"children":4998},{"style":1911},[4999],{"type":40,"value":5000},"  // mock : toutes les sessions existent, Brevo répond OK\n",{"type":31,"tag":1904,"props":5002,"children":5003},{"class":1906,"line":2050},[5004,5009,5013,5018,5023,5027,5032,5036,5041,5045,5050,5054,5059,5063,5067,5071],{"type":31,"tag":1904,"props":5005,"children":5006},{"style":2028},[5007],{"type":40,"value":5008},"  vi",{"type":31,"tag":1904,"props":5010,"children":5011},{"style":2108},[5012],{"type":40,"value":76},{"type":31,"tag":1904,"props":5014,"children":5015},{"style":1926},[5016],{"type":40,"value":5017},"mocked",{"type":31,"tag":1904,"props":5019,"children":5020},{"style":2028},[5021],{"type":40,"value":5022},"(sessionRepository",{"type":31,"tag":1904,"props":5024,"children":5025},{"style":2108},[5026],{"type":40,"value":76},{"type":31,"tag":1904,"props":5028,"children":5029},{"style":2028},[5030],{"type":40,"value":5031},"findById)",{"type":31,"tag":1904,"props":5033,"children":5034},{"style":2108},[5035],{"type":40,"value":76},{"type":31,"tag":1904,"props":5037,"children":5038},{"style":1926},[5039],{"type":40,"value":5040},"mockImplementation",{"type":31,"tag":1904,"props":5042,"children":5043},{"style":2028},[5044],{"type":40,"value":2490},{"type":31,"tag":1904,"props":5046,"children":5047},{"style":1920},[5048],{"type":40,"value":5049},"async",{"type":31,"tag":1904,"props":5051,"children":5052},{"style":1932},[5053],{"type":40,"value":3249},{"type":31,"tag":1904,"props":5055,"children":5056},{"style":1942},[5057],{"type":40,"value":5058},"id",{"type":31,"tag":1904,"props":5060,"children":5061},{"style":1932},[5062],{"type":40,"value":1992},{"type":31,"tag":1904,"props":5064,"children":5065},{"style":1948},[5066],{"type":40,"value":4868},{"type":31,"tag":1904,"props":5068,"children":5069},{"style":2028},[5070],{"type":40,"value":3249},{"type":31,"tag":1904,"props":5072,"children":5073},{"style":1932},[5074],{"type":40,"value":3264},{"type":31,"tag":1904,"props":5076,"children":5077},{"class":1906,"line":2094},[5078,5083],{"type":31,"tag":1904,"props":5079,"children":5080},{"style":2028},[5081],{"type":40,"value":5082},"    id",{"type":31,"tag":1904,"props":5084,"children":5085},{"style":1932},[5086],{"type":40,"value":1962},{"type":31,"tag":1904,"props":5088,"children":5089},{"class":1906,"line":2150},[5090,5095,5099,5104,5108,5112,5116,5121],{"type":31,"tag":1904,"props":5091,"children":5092},{"style":2028},[5093],{"type":40,"value":5094},"    coacheeEmail",{"type":31,"tag":1904,"props":5096,"children":5097},{"style":2108},[5098],{"type":40,"value":1951},{"type":31,"tag":1904,"props":5100,"children":5101},{"style":3399},[5102],{"type":40,"value":5103}," `coach-",{"type":31,"tag":1904,"props":5105,"children":5106},{"style":4452},[5107],{"type":40,"value":4455},{"type":31,"tag":1904,"props":5109,"children":5110},{"style":2028},[5111],{"type":40,"value":5058},{"type":31,"tag":1904,"props":5113,"children":5114},{"style":4452},[5115],{"type":40,"value":4464},{"type":31,"tag":1904,"props":5117,"children":5118},{"style":3399},[5119],{"type":40,"value":5120},"@example.com`",{"type":31,"tag":1904,"props":5122,"children":5123},{"style":1932},[5124],{"type":40,"value":1962},{"type":31,"tag":1904,"props":5126,"children":5127},{"class":1906,"line":2159},[5128,5133,5137,5141,5146,5150,5155,5159],{"type":31,"tag":1904,"props":5129,"children":5130},{"style":2028},[5131],{"type":40,"value":5132},"    scheduledAt",{"type":31,"tag":1904,"props":5134,"children":5135},{"style":2108},[5136],{"type":40,"value":1951},{"type":31,"tag":1904,"props":5138,"children":5139},{"style":2816},[5140],{"type":40,"value":2819},{"type":31,"tag":1904,"props":5142,"children":5143},{"style":1926},[5144],{"type":40,"value":5145}," Date",{"type":31,"tag":1904,"props":5147,"children":5148},{"style":2028},[5149],{"type":40,"value":2490},{"type":31,"tag":1904,"props":5151,"children":5152},{"style":3399},[5153],{"type":40,"value":5154},"'2026-06-10T09:00:00Z'",{"type":31,"tag":1904,"props":5156,"children":5157},{"style":2028},[5158],{"type":40,"value":1992},{"type":31,"tag":1904,"props":5160,"children":5161},{"style":1932},[5162],{"type":40,"value":1962},{"type":31,"tag":1904,"props":5164,"children":5165},{"class":1906,"line":2168},[5166,5171,5176],{"type":31,"tag":1904,"props":5167,"children":5168},{"style":1932},[5169],{"type":40,"value":5170},"  }",{"type":31,"tag":1904,"props":5172,"children":5173},{"style":2028},[5174],{"type":40,"value":5175},"))",{"type":31,"tag":1904,"props":5177,"children":5178},{"style":1932},[5179],{"type":40,"value":2047},{"type":31,"tag":1904,"props":5181,"children":5182},{"class":1906,"line":2177},[5183,5187,5191,5195,5200,5204,5209,5213,5218,5222,5227,5231],{"type":31,"tag":1904,"props":5184,"children":5185},{"style":2028},[5186],{"type":40,"value":5008},{"type":31,"tag":1904,"props":5188,"children":5189},{"style":2108},[5190],{"type":40,"value":76},{"type":31,"tag":1904,"props":5192,"children":5193},{"style":1926},[5194],{"type":40,"value":5017},{"type":31,"tag":1904,"props":5196,"children":5197},{"style":2028},[5198],{"type":40,"value":5199},"(brevoClient",{"type":31,"tag":1904,"props":5201,"children":5202},{"style":2108},[5203],{"type":40,"value":76},{"type":31,"tag":1904,"props":5205,"children":5206},{"style":2028},[5207],{"type":40,"value":5208},"sendTransactionalEmail)",{"type":31,"tag":1904,"props":5210,"children":5211},{"style":2108},[5212],{"type":40,"value":76},{"type":31,"tag":1904,"props":5214,"children":5215},{"style":1926},[5216],{"type":40,"value":5217},"mockResolvedValue",{"type":31,"tag":1904,"props":5219,"children":5220},{"style":2028},[5221],{"type":40,"value":2490},{"type":31,"tag":1904,"props":5223,"children":5224},{"style":1954},[5225],{"type":40,"value":5226},"undefined",{"type":31,"tag":1904,"props":5228,"children":5229},{"style":2028},[5230],{"type":40,"value":1992},{"type":31,"tag":1904,"props":5232,"children":5233},{"style":1932},[5234],{"type":40,"value":2047},{"type":31,"tag":1904,"props":5236,"children":5237},{"class":1906,"line":2194},[5238],{"type":31,"tag":1904,"props":5239,"children":5240},{"emptyLinePlaceholder":13},[5241],{"type":40,"value":2165},{"type":31,"tag":1904,"props":5243,"children":5244},{"class":1906,"line":2215},[5245,5249,5254,5258,5262,5267,5271,5276],{"type":31,"tag":1904,"props":5246,"children":5247},{"style":1920},[5248],{"type":40,"value":2014},{"type":31,"tag":1904,"props":5250,"children":5251},{"style":2017},[5252],{"type":40,"value":5253}," results",{"type":31,"tag":1904,"props":5255,"children":5256},{"style":1948},[5257],{"type":40,"value":2025},{"type":31,"tag":1904,"props":5259,"children":5260},{"style":1920},[5261],{"type":40,"value":3194},{"type":31,"tag":1904,"props":5263,"children":5265},{"style":5264},"--shiki-default:#E5C890;--shiki-default-font-style:italic;--shiki-dark:#79B8FF;--shiki-dark-font-style:inherit",[5266],{"type":40,"value":3152},{"type":31,"tag":1904,"props":5268,"children":5269},{"style":2108},[5270],{"type":40,"value":76},{"type":31,"tag":1904,"props":5272,"children":5273},{"style":1926},[5274],{"type":40,"value":5275},"allSettled",{"type":31,"tag":1904,"props":5277,"children":5278},{"style":2028},[5279],{"type":40,"value":1935},{"type":31,"tag":1904,"props":5281,"children":5282},{"class":1906,"line":2236},[5283,5288,5292,5297,5301,5305,5309,5313,5317,5322,5326,5330,5335],{"type":31,"tag":1904,"props":5284,"children":5285},{"style":2028},[5286],{"type":40,"value":5287},"    sessionIds",{"type":31,"tag":1904,"props":5289,"children":5290},{"style":2108},[5291],{"type":40,"value":76},{"type":31,"tag":1904,"props":5293,"children":5294},{"style":1926},[5295],{"type":40,"value":5296},"map",{"type":31,"tag":1904,"props":5298,"children":5299},{"style":2028},[5300],{"type":40,"value":2490},{"type":31,"tag":1904,"props":5302,"children":5303},{"style":1932},[5304],{"type":40,"value":2490},{"type":31,"tag":1904,"props":5306,"children":5307},{"style":1942},[5308],{"type":40,"value":5058},{"type":31,"tag":1904,"props":5310,"children":5311},{"style":1932},[5312],{"type":40,"value":1992},{"type":31,"tag":1904,"props":5314,"children":5315},{"style":1948},[5316],{"type":40,"value":4868},{"type":31,"tag":1904,"props":5318,"children":5319},{"style":2028},[5320],{"type":40,"value":5321}," service",{"type":31,"tag":1904,"props":5323,"children":5324},{"style":2108},[5325],{"type":40,"value":76},{"type":31,"tag":1904,"props":5327,"children":5328},{"style":1926},[5329],{"type":40,"value":4722},{"type":31,"tag":1904,"props":5331,"children":5332},{"style":2028},[5333],{"type":40,"value":5334},"(id))",{"type":31,"tag":1904,"props":5336,"children":5337},{"style":1932},[5338],{"type":40,"value":1962},{"type":31,"tag":1904,"props":5340,"children":5341},{"class":1906,"line":2256},[5342,5346],{"type":31,"tag":1904,"props":5343,"children":5344},{"style":2028},[5345],{"type":40,"value":3096},{"type":31,"tag":1904,"props":5347,"children":5348},{"style":1932},[5349],{"type":40,"value":2047},{"type":31,"tag":1904,"props":5351,"children":5352},{"class":1906,"line":2290},[5353],{"type":31,"tag":1904,"props":5354,"children":5355},{"emptyLinePlaceholder":13},[5356],{"type":40,"value":2165},{"type":31,"tag":1904,"props":5358,"children":5359},{"class":1906,"line":2333},[5360,5364,5369,5373,5377,5381,5386,5390,5394,5399,5403,5407,5412,5416,5421,5426,5431,5435],{"type":31,"tag":1904,"props":5361,"children":5362},{"style":1920},[5363],{"type":40,"value":2014},{"type":31,"tag":1904,"props":5365,"children":5366},{"style":2017},[5367],{"type":40,"value":5368}," failed",{"type":31,"tag":1904,"props":5370,"children":5371},{"style":1948},[5372],{"type":40,"value":2025},{"type":31,"tag":1904,"props":5374,"children":5375},{"style":2028},[5376],{"type":40,"value":5253},{"type":31,"tag":1904,"props":5378,"children":5379},{"style":2108},[5380],{"type":40,"value":76},{"type":31,"tag":1904,"props":5382,"children":5383},{"style":1926},[5384],{"type":40,"value":5385},"filter",{"type":31,"tag":1904,"props":5387,"children":5388},{"style":2028},[5389],{"type":40,"value":2490},{"type":31,"tag":1904,"props":5391,"children":5392},{"style":1932},[5393],{"type":40,"value":2490},{"type":31,"tag":1904,"props":5395,"children":5396},{"style":1942},[5397],{"type":40,"value":5398},"r",{"type":31,"tag":1904,"props":5400,"children":5401},{"style":1932},[5402],{"type":40,"value":1992},{"type":31,"tag":1904,"props":5404,"children":5405},{"style":1948},[5406],{"type":40,"value":4868},{"type":31,"tag":1904,"props":5408,"children":5409},{"style":2028},[5410],{"type":40,"value":5411}," r",{"type":31,"tag":1904,"props":5413,"children":5414},{"style":2108},[5415],{"type":40,"value":76},{"type":31,"tag":1904,"props":5417,"children":5418},{"style":2028},[5419],{"type":40,"value":5420},"status ",{"type":31,"tag":1904,"props":5422,"children":5423},{"style":1948},[5424],{"type":40,"value":5425},"===",{"type":31,"tag":1904,"props":5427,"children":5428},{"style":3399},[5429],{"type":40,"value":5430}," 'rejected'",{"type":31,"tag":1904,"props":5432,"children":5433},{"style":2028},[5434],{"type":40,"value":1992},{"type":31,"tag":1904,"props":5436,"children":5437},{"style":1932},[5438],{"type":40,"value":2047},{"type":31,"tag":1904,"props":5440,"children":5441},{"class":1906,"line":2382},[5442,5447,5452,5456,5461,5465,5470,5474],{"type":31,"tag":1904,"props":5443,"children":5444},{"style":1926},[5445],{"type":40,"value":5446},"  expect",{"type":31,"tag":1904,"props":5448,"children":5449},{"style":2028},[5450],{"type":40,"value":5451},"(failed)",{"type":31,"tag":1904,"props":5453,"children":5454},{"style":2108},[5455],{"type":40,"value":76},{"type":31,"tag":1904,"props":5457,"children":5458},{"style":1926},[5459],{"type":40,"value":5460},"toHaveLength",{"type":31,"tag":1904,"props":5462,"children":5463},{"style":2028},[5464],{"type":40,"value":2490},{"type":31,"tag":1904,"props":5466,"children":5467},{"style":2039},[5468],{"type":40,"value":5469},"0",{"type":31,"tag":1904,"props":5471,"children":5472},{"style":2028},[5473],{"type":40,"value":1992},{"type":31,"tag":1904,"props":5475,"children":5476},{"style":1932},[5477],{"type":40,"value":2047},{"type":31,"tag":1904,"props":5479,"children":5480},{"class":1906,"line":4678},[5481,5485,5489,5493,5497,5501,5506,5510,5515,5519],{"type":31,"tag":1904,"props":5482,"children":5483},{"style":1926},[5484],{"type":40,"value":5446},{"type":31,"tag":1904,"props":5486,"children":5487},{"style":2028},[5488],{"type":40,"value":5199},{"type":31,"tag":1904,"props":5490,"children":5491},{"style":2108},[5492],{"type":40,"value":76},{"type":31,"tag":1904,"props":5494,"children":5495},{"style":2028},[5496],{"type":40,"value":5208},{"type":31,"tag":1904,"props":5498,"children":5499},{"style":2108},[5500],{"type":40,"value":76},{"type":31,"tag":1904,"props":5502,"children":5503},{"style":1926},[5504],{"type":40,"value":5505},"toHaveBeenCalledTimes",{"type":31,"tag":1904,"props":5507,"children":5508},{"style":2028},[5509],{"type":40,"value":2490},{"type":31,"tag":1904,"props":5511,"children":5512},{"style":2039},[5513],{"type":40,"value":5514},"50",{"type":31,"tag":1904,"props":5516,"children":5517},{"style":2028},[5518],{"type":40,"value":1992},{"type":31,"tag":1904,"props":5520,"children":5521},{"style":1932},[5522],{"type":40,"value":2047},{"type":31,"tag":1904,"props":5524,"children":5526},{"class":1906,"line":5525},21,[5527,5531,5535],{"type":31,"tag":1904,"props":5528,"children":5529},{"style":1932},[5530],{"type":40,"value":4464},{"type":31,"tag":1904,"props":5532,"children":5533},{"style":2028},[5534],{"type":40,"value":1992},{"type":31,"tag":1904,"props":5536,"children":5537},{"style":1932},[5538],{"type":40,"value":2047},{"type":31,"tag":32,"props":5540,"children":5541},{},[5542,5544],{"type":40,"value":5543},"Ce test, Claude ne l'écrit pas spontanément. Il faut le prompter explicitement : ",{"type":31,"tag":97,"props":5545,"children":5546},{},[5547,5549,5554],{"type":40,"value":5548},"\"Écris un test Vitest qui exécute cette méthode 50 fois en parallèle via ",{"type":31,"tag":169,"props":5550,"children":5552},{"className":5551},[],[5553],{"type":40,"value":4807},{"type":40,"value":5555}," et vérifie qu'aucune ne rejette.\"",{"type":31,"tag":4784,"props":5557,"children":5559},{"id":5558},"test-2-le-test-de-rate-limit-429",[5560],{"type":40,"value":5561},"Test 2 : le test de rate limit (429)",{"type":31,"tag":32,"props":5563,"children":5564},{},[5565],{"type":40,"value":5566},"Mockez la réponse de Brevo pour qu'elle lève une erreur 429 au premier appel. Vérifiez que la méthode retry avec backoff au lieu d'échouer.",{"type":31,"tag":1894,"props":5568,"children":5570},{"className":1896,"code":5569,"language":1898,"meta":8,"style":8},"it('retries with backoff on 429 from Brevo', async () => {\n  vi.mocked(sessionRepository.findById).mockResolvedValue({\n    id: 'session-abc',\n    coacheeEmail: 'coachee@example.com',\n    scheduledAt: new Date(),\n  });\n\n  let callCount = 0;\n  vi.mocked(brevoClient.sendTransactionalEmail).mockImplementation(async () => {\n    callCount += 1;\n    if (callCount === 1) {\n      const err = new Error('Too Many Requests') as Error & { statusCode: number };\n      err.statusCode = 429;\n      throw err;\n    }\n  });\n\n  await service.sendSessionConfirmation('session-abc');\n\n  expect(callCount).toBe(2);\n  expect(brevoClient.sendTransactionalEmail).toHaveBeenCalledTimes(2);\n});\n",[5571],{"type":31,"tag":169,"props":5572,"children":5573},{"__ignoreMap":8},[5574,5610,5653,5673,5693,5720,5735,5742,5768,5823,5845,5873,5948,5978,5993,6000,6015,6022,6059,6066,6104,6147],{"type":31,"tag":1904,"props":5575,"children":5576},{"class":1906,"line":1907},[5577,5581,5585,5590,5594,5598,5602,5606],{"type":31,"tag":1904,"props":5578,"children":5579},{"style":1926},[5580],{"type":40,"value":4839},{"type":31,"tag":1904,"props":5582,"children":5583},{"style":2028},[5584],{"type":40,"value":2490},{"type":31,"tag":1904,"props":5586,"children":5587},{"style":3399},[5588],{"type":40,"value":5589},"'retries with backoff on 429 from Brevo'",{"type":31,"tag":1904,"props":5591,"children":5592},{"style":1932},[5593],{"type":40,"value":4853},{"type":31,"tag":1904,"props":5595,"children":5596},{"style":1920},[5597],{"type":40,"value":4858},{"type":31,"tag":1904,"props":5599,"children":5600},{"style":1932},[5601],{"type":40,"value":4863},{"type":31,"tag":1904,"props":5603,"children":5604},{"style":1948},[5605],{"type":40,"value":4868},{"type":31,"tag":1904,"props":5607,"children":5608},{"style":1932},[5609],{"type":40,"value":2005},{"type":31,"tag":1904,"props":5611,"children":5612},{"class":1906,"line":817},[5613,5617,5621,5625,5629,5633,5637,5641,5645,5649],{"type":31,"tag":1904,"props":5614,"children":5615},{"style":2028},[5616],{"type":40,"value":5008},{"type":31,"tag":1904,"props":5618,"children":5619},{"style":2108},[5620],{"type":40,"value":76},{"type":31,"tag":1904,"props":5622,"children":5623},{"style":1926},[5624],{"type":40,"value":5017},{"type":31,"tag":1904,"props":5626,"children":5627},{"style":2028},[5628],{"type":40,"value":5022},{"type":31,"tag":1904,"props":5630,"children":5631},{"style":2108},[5632],{"type":40,"value":76},{"type":31,"tag":1904,"props":5634,"children":5635},{"style":2028},[5636],{"type":40,"value":5031},{"type":31,"tag":1904,"props":5638,"children":5639},{"style":2108},[5640],{"type":40,"value":76},{"type":31,"tag":1904,"props":5642,"children":5643},{"style":1926},[5644],{"type":40,"value":5217},{"type":31,"tag":1904,"props":5646,"children":5647},{"style":2028},[5648],{"type":40,"value":2490},{"type":31,"tag":1904,"props":5650,"children":5651},{"style":1932},[5652],{"type":40,"value":3264},{"type":31,"tag":1904,"props":5654,"children":5655},{"class":1906,"line":1938},[5656,5660,5664,5669],{"type":31,"tag":1904,"props":5657,"children":5658},{"style":2028},[5659],{"type":40,"value":5082},{"type":31,"tag":1904,"props":5661,"children":5662},{"style":2108},[5663],{"type":40,"value":1951},{"type":31,"tag":1904,"props":5665,"children":5666},{"style":3399},[5667],{"type":40,"value":5668}," 'session-abc'",{"type":31,"tag":1904,"props":5670,"children":5671},{"style":1932},[5672],{"type":40,"value":1962},{"type":31,"tag":1904,"props":5674,"children":5675},{"class":1906,"line":1965},[5676,5680,5684,5689],{"type":31,"tag":1904,"props":5677,"children":5678},{"style":2028},[5679],{"type":40,"value":5094},{"type":31,"tag":1904,"props":5681,"children":5682},{"style":2108},[5683],{"type":40,"value":1951},{"type":31,"tag":1904,"props":5685,"children":5686},{"style":3399},[5687],{"type":40,"value":5688}," 'coachee@example.com'",{"type":31,"tag":1904,"props":5690,"children":5691},{"style":1932},[5692],{"type":40,"value":1962},{"type":31,"tag":1904,"props":5694,"children":5695},{"class":1906,"line":1986},[5696,5700,5704,5708,5712,5716],{"type":31,"tag":1904,"props":5697,"children":5698},{"style":2028},[5699],{"type":40,"value":5132},{"type":31,"tag":1904,"props":5701,"children":5702},{"style":2108},[5703],{"type":40,"value":1951},{"type":31,"tag":1904,"props":5705,"children":5706},{"style":2816},[5707],{"type":40,"value":2819},{"type":31,"tag":1904,"props":5709,"children":5710},{"style":1926},[5711],{"type":40,"value":5145},{"type":31,"tag":1904,"props":5713,"children":5714},{"style":2028},[5715],{"type":40,"value":2828},{"type":31,"tag":1904,"props":5717,"children":5718},{"style":1932},[5719],{"type":40,"value":1962},{"type":31,"tag":1904,"props":5721,"children":5722},{"class":1906,"line":2008},[5723,5727,5731],{"type":31,"tag":1904,"props":5724,"children":5725},{"style":1932},[5726],{"type":40,"value":5170},{"type":31,"tag":1904,"props":5728,"children":5729},{"style":2028},[5730],{"type":40,"value":1992},{"type":31,"tag":1904,"props":5732,"children":5733},{"style":1932},[5734],{"type":40,"value":2047},{"type":31,"tag":1904,"props":5736,"children":5737},{"class":1906,"line":2050},[5738],{"type":31,"tag":1904,"props":5739,"children":5740},{"emptyLinePlaceholder":13},[5741],{"type":40,"value":2165},{"type":31,"tag":1904,"props":5743,"children":5744},{"class":1906,"line":2094},[5745,5750,5755,5760,5764],{"type":31,"tag":1904,"props":5746,"children":5747},{"style":1920},[5748],{"type":40,"value":5749},"  let",{"type":31,"tag":1904,"props":5751,"children":5752},{"style":2028},[5753],{"type":40,"value":5754}," callCount ",{"type":31,"tag":1904,"props":5756,"children":5757},{"style":1948},[5758],{"type":40,"value":5759},"=",{"type":31,"tag":1904,"props":5761,"children":5762},{"style":2039},[5763],{"type":40,"value":2701},{"type":31,"tag":1904,"props":5765,"children":5766},{"style":1932},[5767],{"type":40,"value":2047},{"type":31,"tag":1904,"props":5769,"children":5770},{"class":1906,"line":2150},[5771,5775,5779,5783,5787,5791,5795,5799,5803,5807,5811,5815,5819],{"type":31,"tag":1904,"props":5772,"children":5773},{"style":2028},[5774],{"type":40,"value":5008},{"type":31,"tag":1904,"props":5776,"children":5777},{"style":2108},[5778],{"type":40,"value":76},{"type":31,"tag":1904,"props":5780,"children":5781},{"style":1926},[5782],{"type":40,"value":5017},{"type":31,"tag":1904,"props":5784,"children":5785},{"style":2028},[5786],{"type":40,"value":5199},{"type":31,"tag":1904,"props":5788,"children":5789},{"style":2108},[5790],{"type":40,"value":76},{"type":31,"tag":1904,"props":5792,"children":5793},{"style":2028},[5794],{"type":40,"value":5208},{"type":31,"tag":1904,"props":5796,"children":5797},{"style":2108},[5798],{"type":40,"value":76},{"type":31,"tag":1904,"props":5800,"children":5801},{"style":1926},[5802],{"type":40,"value":5040},{"type":31,"tag":1904,"props":5804,"children":5805},{"style":2028},[5806],{"type":40,"value":2490},{"type":31,"tag":1904,"props":5808,"children":5809},{"style":1920},[5810],{"type":40,"value":5049},{"type":31,"tag":1904,"props":5812,"children":5813},{"style":1932},[5814],{"type":40,"value":4863},{"type":31,"tag":1904,"props":5816,"children":5817},{"style":1948},[5818],{"type":40,"value":4868},{"type":31,"tag":1904,"props":5820,"children":5821},{"style":1932},[5822],{"type":40,"value":2005},{"type":31,"tag":1904,"props":5824,"children":5825},{"class":1906,"line":2159},[5826,5831,5836,5841],{"type":31,"tag":1904,"props":5827,"children":5828},{"style":2028},[5829],{"type":40,"value":5830},"    callCount ",{"type":31,"tag":1904,"props":5832,"children":5833},{"style":1948},[5834],{"type":40,"value":5835},"+=",{"type":31,"tag":1904,"props":5837,"children":5838},{"style":2039},[5839],{"type":40,"value":5840}," 1",{"type":31,"tag":1904,"props":5842,"children":5843},{"style":1932},[5844],{"type":40,"value":2047},{"type":31,"tag":1904,"props":5846,"children":5847},{"class":1906,"line":2168},[5848,5852,5857,5861,5865,5869],{"type":31,"tag":1904,"props":5849,"children":5850},{"style":1920},[5851],{"type":40,"value":3244},{"type":31,"tag":1904,"props":5853,"children":5854},{"style":2028},[5855],{"type":40,"value":5856}," (callCount ",{"type":31,"tag":1904,"props":5858,"children":5859},{"style":1948},[5860],{"type":40,"value":5425},{"type":31,"tag":1904,"props":5862,"children":5863},{"style":2039},[5864],{"type":40,"value":5840},{"type":31,"tag":1904,"props":5866,"children":5867},{"style":2028},[5868],{"type":40,"value":2135},{"type":31,"tag":1904,"props":5870,"children":5871},{"style":1932},[5872],{"type":40,"value":3264},{"type":31,"tag":1904,"props":5874,"children":5875},{"class":1906,"line":2177},[5876,5881,5886,5890,5894,5898,5902,5907,5911,5916,5920,5925,5929,5935,5939,5943],{"type":31,"tag":1904,"props":5877,"children":5878},{"style":1920},[5879],{"type":40,"value":5880},"      const",{"type":31,"tag":1904,"props":5882,"children":5883},{"style":2017},[5884],{"type":40,"value":5885}," err",{"type":31,"tag":1904,"props":5887,"children":5888},{"style":1948},[5889],{"type":40,"value":2025},{"type":31,"tag":1904,"props":5891,"children":5892},{"style":2816},[5893],{"type":40,"value":2819},{"type":31,"tag":1904,"props":5895,"children":5896},{"style":1926},[5897],{"type":40,"value":4440},{"type":31,"tag":1904,"props":5899,"children":5900},{"style":2028},[5901],{"type":40,"value":2490},{"type":31,"tag":1904,"props":5903,"children":5904},{"style":3399},[5905],{"type":40,"value":5906},"'Too Many Requests'",{"type":31,"tag":1904,"props":5908,"children":5909},{"style":2028},[5910],{"type":40,"value":2135},{"type":31,"tag":1904,"props":5912,"children":5913},{"style":1920},[5914],{"type":40,"value":5915},"as",{"type":31,"tag":1904,"props":5917,"children":5918},{"style":2470},[5919],{"type":40,"value":4440},{"type":31,"tag":1904,"props":5921,"children":5922},{"style":1948},[5923],{"type":40,"value":5924}," &",{"type":31,"tag":1904,"props":5926,"children":5927},{"style":1932},[5928],{"type":40,"value":4625},{"type":31,"tag":1904,"props":5930,"children":5932},{"style":5931},"--shiki-default:#C6D0F5;--shiki-dark:#FFAB70",[5933],{"type":40,"value":5934}," statusCode",{"type":31,"tag":1904,"props":5936,"children":5937},{"style":1948},[5938],{"type":40,"value":1951},{"type":31,"tag":1904,"props":5940,"children":5941},{"style":1954},[5942],{"type":40,"value":1957},{"type":31,"tag":1904,"props":5944,"children":5945},{"style":1932},[5946],{"type":40,"value":5947}," };\n",{"type":31,"tag":1904,"props":5949,"children":5950},{"class":1906,"line":2194},[5951,5956,5960,5965,5969,5974],{"type":31,"tag":1904,"props":5952,"children":5953},{"style":2028},[5954],{"type":40,"value":5955},"      err",{"type":31,"tag":1904,"props":5957,"children":5958},{"style":2108},[5959],{"type":40,"value":76},{"type":31,"tag":1904,"props":5961,"children":5962},{"style":2028},[5963],{"type":40,"value":5964},"statusCode ",{"type":31,"tag":1904,"props":5966,"children":5967},{"style":1948},[5968],{"type":40,"value":5759},{"type":31,"tag":1904,"props":5970,"children":5971},{"style":2039},[5972],{"type":40,"value":5973}," 429",{"type":31,"tag":1904,"props":5975,"children":5976},{"style":1932},[5977],{"type":40,"value":2047},{"type":31,"tag":1904,"props":5979,"children":5980},{"class":1906,"line":2215},[5981,5985,5989],{"type":31,"tag":1904,"props":5982,"children":5983},{"style":1920},[5984],{"type":40,"value":3272},{"type":31,"tag":1904,"props":5986,"children":5987},{"style":2028},[5988],{"type":40,"value":5885},{"type":31,"tag":1904,"props":5990,"children":5991},{"style":1932},[5992],{"type":40,"value":2047},{"type":31,"tag":1904,"props":5994,"children":5995},{"class":1906,"line":2236},[5996],{"type":31,"tag":1904,"props":5997,"children":5998},{"style":1932},[5999],{"type":40,"value":3305},{"type":31,"tag":1904,"props":6001,"children":6002},{"class":1906,"line":2256},[6003,6007,6011],{"type":31,"tag":1904,"props":6004,"children":6005},{"style":1932},[6006],{"type":40,"value":5170},{"type":31,"tag":1904,"props":6008,"children":6009},{"style":2028},[6010],{"type":40,"value":1992},{"type":31,"tag":1904,"props":6012,"children":6013},{"style":1932},[6014],{"type":40,"value":2047},{"type":31,"tag":1904,"props":6016,"children":6017},{"class":1906,"line":2290},[6018],{"type":31,"tag":1904,"props":6019,"children":6020},{"emptyLinePlaceholder":13},[6021],{"type":40,"value":2165},{"type":31,"tag":1904,"props":6023,"children":6024},{"class":1906,"line":2333},[6025,6030,6034,6038,6042,6046,6051,6055],{"type":31,"tag":1904,"props":6026,"children":6027},{"style":1920},[6028],{"type":40,"value":6029},"  await",{"type":31,"tag":1904,"props":6031,"children":6032},{"style":2028},[6033],{"type":40,"value":5321},{"type":31,"tag":1904,"props":6035,"children":6036},{"style":2108},[6037],{"type":40,"value":76},{"type":31,"tag":1904,"props":6039,"children":6040},{"style":1926},[6041],{"type":40,"value":4722},{"type":31,"tag":1904,"props":6043,"children":6044},{"style":2028},[6045],{"type":40,"value":2490},{"type":31,"tag":1904,"props":6047,"children":6048},{"style":3399},[6049],{"type":40,"value":6050},"'session-abc'",{"type":31,"tag":1904,"props":6052,"children":6053},{"style":2028},[6054],{"type":40,"value":1992},{"type":31,"tag":1904,"props":6056,"children":6057},{"style":1932},[6058],{"type":40,"value":2047},{"type":31,"tag":1904,"props":6060,"children":6061},{"class":1906,"line":2382},[6062],{"type":31,"tag":1904,"props":6063,"children":6064},{"emptyLinePlaceholder":13},[6065],{"type":40,"value":2165},{"type":31,"tag":1904,"props":6067,"children":6068},{"class":1906,"line":4678},[6069,6073,6078,6082,6087,6091,6096,6100],{"type":31,"tag":1904,"props":6070,"children":6071},{"style":1926},[6072],{"type":40,"value":5446},{"type":31,"tag":1904,"props":6074,"children":6075},{"style":2028},[6076],{"type":40,"value":6077},"(callCount)",{"type":31,"tag":1904,"props":6079,"children":6080},{"style":2108},[6081],{"type":40,"value":76},{"type":31,"tag":1904,"props":6083,"children":6084},{"style":1926},[6085],{"type":40,"value":6086},"toBe",{"type":31,"tag":1904,"props":6088,"children":6089},{"style":2028},[6090],{"type":40,"value":2490},{"type":31,"tag":1904,"props":6092,"children":6093},{"style":2039},[6094],{"type":40,"value":6095},"2",{"type":31,"tag":1904,"props":6097,"children":6098},{"style":2028},[6099],{"type":40,"value":1992},{"type":31,"tag":1904,"props":6101,"children":6102},{"style":1932},[6103],{"type":40,"value":2047},{"type":31,"tag":1904,"props":6105,"children":6106},{"class":1906,"line":5525},[6107,6111,6115,6119,6123,6127,6131,6135,6139,6143],{"type":31,"tag":1904,"props":6108,"children":6109},{"style":1926},[6110],{"type":40,"value":5446},{"type":31,"tag":1904,"props":6112,"children":6113},{"style":2028},[6114],{"type":40,"value":5199},{"type":31,"tag":1904,"props":6116,"children":6117},{"style":2108},[6118],{"type":40,"value":76},{"type":31,"tag":1904,"props":6120,"children":6121},{"style":2028},[6122],{"type":40,"value":5208},{"type":31,"tag":1904,"props":6124,"children":6125},{"style":2108},[6126],{"type":40,"value":76},{"type":31,"tag":1904,"props":6128,"children":6129},{"style":1926},[6130],{"type":40,"value":5505},{"type":31,"tag":1904,"props":6132,"children":6133},{"style":2028},[6134],{"type":40,"value":2490},{"type":31,"tag":1904,"props":6136,"children":6137},{"style":2039},[6138],{"type":40,"value":6095},{"type":31,"tag":1904,"props":6140,"children":6141},{"style":2028},[6142],{"type":40,"value":1992},{"type":31,"tag":1904,"props":6144,"children":6145},{"style":1932},[6146],{"type":40,"value":2047},{"type":31,"tag":1904,"props":6148,"children":6150},{"class":1906,"line":6149},22,[6151,6155,6159],{"type":31,"tag":1904,"props":6152,"children":6153},{"style":1932},[6154],{"type":40,"value":4464},{"type":31,"tag":1904,"props":6156,"children":6157},{"style":2028},[6158],{"type":40,"value":1992},{"type":31,"tag":1904,"props":6160,"children":6161},{"style":1932},[6162],{"type":40,"value":2047},{"type":31,"tag":32,"props":6164,"children":6165},{},[6166],{"type":40,"value":6167},"C'est le test qui aurait évité le crash. 20 lignes. Une heure à écrire la première fois. Une protection durable contre ce mode d'échec.",{"type":31,"tag":4784,"props":6169,"children":6171},{"id":6170},"test-3-le-test-de-timeout",[6172],{"type":40,"value":6173},"Test 3 : le test de timeout",{"type":31,"tag":32,"props":6175,"children":6176},{},[6177],{"type":40,"value":6178},"Simulez une réponse Brevo qui ne vient jamais (le mock attend indefiniment). Vérifiez que la méthode abandonne au bout de N secondes au lieu de bloquer l'event loop.",{"type":31,"tag":1894,"props":6180,"children":6182},{"className":1896,"code":6181,"language":1898,"meta":8,"style":8},"it('aborts and throws after 5 seconds if Brevo does not respond', async () => {\n  vi.useFakeTimers();\n\n  vi.mocked(sessionRepository.findById).mockResolvedValue({\n    id: 'session-timeout',\n    coacheeEmail: 'coachee@example.com',\n    scheduledAt: new Date(),\n  });\n\n  // Brevo ne répond jamais\n  vi.mocked(brevoClient.sendTransactionalEmail).mockImplementation(\n    () => new Promise\u003Cvoid>(() => { /* jamais résolu */ }),\n  );\n\n  const promise = service.sendSessionConfirmation('session-timeout');\n\n  // avancer le temps de 5 secondes\n  await vi.advanceTimersByTimeAsync(5_000);\n\n  await expect(promise).rejects.toThrow('Brevo timeout');\n\n  vi.useRealTimers();\n});\n",[6183],{"type":31,"tag":169,"props":6184,"children":6185},{"__ignoreMap":8},[6186,6222,6246,6253,6296,6316,6335,6362,6377,6384,6392,6431,6497,6508,6515,6560,6567,6575,6613,6620,6672,6679,6703],{"type":31,"tag":1904,"props":6187,"children":6188},{"class":1906,"line":1907},[6189,6193,6197,6202,6206,6210,6214,6218],{"type":31,"tag":1904,"props":6190,"children":6191},{"style":1926},[6192],{"type":40,"value":4839},{"type":31,"tag":1904,"props":6194,"children":6195},{"style":2028},[6196],{"type":40,"value":2490},{"type":31,"tag":1904,"props":6198,"children":6199},{"style":3399},[6200],{"type":40,"value":6201},"'aborts and throws after 5 seconds if Brevo does not respond'",{"type":31,"tag":1904,"props":6203,"children":6204},{"style":1932},[6205],{"type":40,"value":4853},{"type":31,"tag":1904,"props":6207,"children":6208},{"style":1920},[6209],{"type":40,"value":4858},{"type":31,"tag":1904,"props":6211,"children":6212},{"style":1932},[6213],{"type":40,"value":4863},{"type":31,"tag":1904,"props":6215,"children":6216},{"style":1948},[6217],{"type":40,"value":4868},{"type":31,"tag":1904,"props":6219,"children":6220},{"style":1932},[6221],{"type":40,"value":2005},{"type":31,"tag":1904,"props":6223,"children":6224},{"class":1906,"line":817},[6225,6229,6233,6238,6242],{"type":31,"tag":1904,"props":6226,"children":6227},{"style":2028},[6228],{"type":40,"value":5008},{"type":31,"tag":1904,"props":6230,"children":6231},{"style":2108},[6232],{"type":40,"value":76},{"type":31,"tag":1904,"props":6234,"children":6235},{"style":1926},[6236],{"type":40,"value":6237},"useFakeTimers",{"type":31,"tag":1904,"props":6239,"children":6240},{"style":2028},[6241],{"type":40,"value":2828},{"type":31,"tag":1904,"props":6243,"children":6244},{"style":1932},[6245],{"type":40,"value":2047},{"type":31,"tag":1904,"props":6247,"children":6248},{"class":1906,"line":1938},[6249],{"type":31,"tag":1904,"props":6250,"children":6251},{"emptyLinePlaceholder":13},[6252],{"type":40,"value":2165},{"type":31,"tag":1904,"props":6254,"children":6255},{"class":1906,"line":1965},[6256,6260,6264,6268,6272,6276,6280,6284,6288,6292],{"type":31,"tag":1904,"props":6257,"children":6258},{"style":2028},[6259],{"type":40,"value":5008},{"type":31,"tag":1904,"props":6261,"children":6262},{"style":2108},[6263],{"type":40,"value":76},{"type":31,"tag":1904,"props":6265,"children":6266},{"style":1926},[6267],{"type":40,"value":5017},{"type":31,"tag":1904,"props":6269,"children":6270},{"style":2028},[6271],{"type":40,"value":5022},{"type":31,"tag":1904,"props":6273,"children":6274},{"style":2108},[6275],{"type":40,"value":76},{"type":31,"tag":1904,"props":6277,"children":6278},{"style":2028},[6279],{"type":40,"value":5031},{"type":31,"tag":1904,"props":6281,"children":6282},{"style":2108},[6283],{"type":40,"value":76},{"type":31,"tag":1904,"props":6285,"children":6286},{"style":1926},[6287],{"type":40,"value":5217},{"type":31,"tag":1904,"props":6289,"children":6290},{"style":2028},[6291],{"type":40,"value":2490},{"type":31,"tag":1904,"props":6293,"children":6294},{"style":1932},[6295],{"type":40,"value":3264},{"type":31,"tag":1904,"props":6297,"children":6298},{"class":1906,"line":1986},[6299,6303,6307,6312],{"type":31,"tag":1904,"props":6300,"children":6301},{"style":2028},[6302],{"type":40,"value":5082},{"type":31,"tag":1904,"props":6304,"children":6305},{"style":2108},[6306],{"type":40,"value":1951},{"type":31,"tag":1904,"props":6308,"children":6309},{"style":3399},[6310],{"type":40,"value":6311}," 'session-timeout'",{"type":31,"tag":1904,"props":6313,"children":6314},{"style":1932},[6315],{"type":40,"value":1962},{"type":31,"tag":1904,"props":6317,"children":6318},{"class":1906,"line":2008},[6319,6323,6327,6331],{"type":31,"tag":1904,"props":6320,"children":6321},{"style":2028},[6322],{"type":40,"value":5094},{"type":31,"tag":1904,"props":6324,"children":6325},{"style":2108},[6326],{"type":40,"value":1951},{"type":31,"tag":1904,"props":6328,"children":6329},{"style":3399},[6330],{"type":40,"value":5688},{"type":31,"tag":1904,"props":6332,"children":6333},{"style":1932},[6334],{"type":40,"value":1962},{"type":31,"tag":1904,"props":6336,"children":6337},{"class":1906,"line":2050},[6338,6342,6346,6350,6354,6358],{"type":31,"tag":1904,"props":6339,"children":6340},{"style":2028},[6341],{"type":40,"value":5132},{"type":31,"tag":1904,"props":6343,"children":6344},{"style":2108},[6345],{"type":40,"value":1951},{"type":31,"tag":1904,"props":6347,"children":6348},{"style":2816},[6349],{"type":40,"value":2819},{"type":31,"tag":1904,"props":6351,"children":6352},{"style":1926},[6353],{"type":40,"value":5145},{"type":31,"tag":1904,"props":6355,"children":6356},{"style":2028},[6357],{"type":40,"value":2828},{"type":31,"tag":1904,"props":6359,"children":6360},{"style":1932},[6361],{"type":40,"value":1962},{"type":31,"tag":1904,"props":6363,"children":6364},{"class":1906,"line":2094},[6365,6369,6373],{"type":31,"tag":1904,"props":6366,"children":6367},{"style":1932},[6368],{"type":40,"value":5170},{"type":31,"tag":1904,"props":6370,"children":6371},{"style":2028},[6372],{"type":40,"value":1992},{"type":31,"tag":1904,"props":6374,"children":6375},{"style":1932},[6376],{"type":40,"value":2047},{"type":31,"tag":1904,"props":6378,"children":6379},{"class":1906,"line":2150},[6380],{"type":31,"tag":1904,"props":6381,"children":6382},{"emptyLinePlaceholder":13},[6383],{"type":40,"value":2165},{"type":31,"tag":1904,"props":6385,"children":6386},{"class":1906,"line":2159},[6387],{"type":31,"tag":1904,"props":6388,"children":6389},{"style":1911},[6390],{"type":40,"value":6391},"  // Brevo ne répond jamais\n",{"type":31,"tag":1904,"props":6393,"children":6394},{"class":1906,"line":2168},[6395,6399,6403,6407,6411,6415,6419,6423,6427],{"type":31,"tag":1904,"props":6396,"children":6397},{"style":2028},[6398],{"type":40,"value":5008},{"type":31,"tag":1904,"props":6400,"children":6401},{"style":2108},[6402],{"type":40,"value":76},{"type":31,"tag":1904,"props":6404,"children":6405},{"style":1926},[6406],{"type":40,"value":5017},{"type":31,"tag":1904,"props":6408,"children":6409},{"style":2028},[6410],{"type":40,"value":5199},{"type":31,"tag":1904,"props":6412,"children":6413},{"style":2108},[6414],{"type":40,"value":76},{"type":31,"tag":1904,"props":6416,"children":6417},{"style":2028},[6418],{"type":40,"value":5208},{"type":31,"tag":1904,"props":6420,"children":6421},{"style":2108},[6422],{"type":40,"value":76},{"type":31,"tag":1904,"props":6424,"children":6425},{"style":1926},[6426],{"type":40,"value":5040},{"type":31,"tag":1904,"props":6428,"children":6429},{"style":2028},[6430],{"type":40,"value":1935},{"type":31,"tag":1904,"props":6432,"children":6433},{"class":1906,"line":2177},[6434,6439,6443,6447,6451,6455,6459,6463,6467,6471,6475,6479,6484,6489,6493],{"type":31,"tag":1904,"props":6435,"children":6436},{"style":1932},[6437],{"type":40,"value":6438},"    ()",{"type":31,"tag":1904,"props":6440,"children":6441},{"style":1948},[6442],{"type":40,"value":4868},{"type":31,"tag":1904,"props":6444,"children":6445},{"style":2816},[6446],{"type":40,"value":2819},{"type":31,"tag":1904,"props":6448,"children":6449},{"style":5264},[6450],{"type":40,"value":3152},{"type":31,"tag":1904,"props":6452,"children":6453},{"style":3155},[6454],{"type":40,"value":3158},{"type":31,"tag":1904,"props":6456,"children":6457},{"style":1954},[6458],{"type":40,"value":4348},{"type":31,"tag":1904,"props":6460,"children":6461},{"style":3155},[6462],{"type":40,"value":3168},{"type":31,"tag":1904,"props":6464,"children":6465},{"style":2028},[6466],{"type":40,"value":2490},{"type":31,"tag":1904,"props":6468,"children":6469},{"style":1932},[6470],{"type":40,"value":2828},{"type":31,"tag":1904,"props":6472,"children":6473},{"style":1948},[6474],{"type":40,"value":4868},{"type":31,"tag":1904,"props":6476,"children":6477},{"style":1932},[6478],{"type":40,"value":4625},{"type":31,"tag":1904,"props":6480,"children":6481},{"style":1911},[6482],{"type":40,"value":6483}," /* jamais résolu */",{"type":31,"tag":1904,"props":6485,"children":6486},{"style":1932},[6487],{"type":40,"value":6488}," }",{"type":31,"tag":1904,"props":6490,"children":6491},{"style":2028},[6492],{"type":40,"value":1992},{"type":31,"tag":1904,"props":6494,"children":6495},{"style":1932},[6496],{"type":40,"value":1962},{"type":31,"tag":1904,"props":6498,"children":6499},{"class":1906,"line":2194},[6500,6504],{"type":31,"tag":1904,"props":6501,"children":6502},{"style":2028},[6503],{"type":40,"value":3096},{"type":31,"tag":1904,"props":6505,"children":6506},{"style":1932},[6507],{"type":40,"value":2047},{"type":31,"tag":1904,"props":6509,"children":6510},{"class":1906,"line":2215},[6511],{"type":31,"tag":1904,"props":6512,"children":6513},{"emptyLinePlaceholder":13},[6514],{"type":40,"value":2165},{"type":31,"tag":1904,"props":6516,"children":6517},{"class":1906,"line":2236},[6518,6522,6527,6531,6535,6539,6543,6547,6552,6556],{"type":31,"tag":1904,"props":6519,"children":6520},{"style":1920},[6521],{"type":40,"value":2014},{"type":31,"tag":1904,"props":6523,"children":6524},{"style":2017},[6525],{"type":40,"value":6526}," promise",{"type":31,"tag":1904,"props":6528,"children":6529},{"style":1948},[6530],{"type":40,"value":2025},{"type":31,"tag":1904,"props":6532,"children":6533},{"style":2028},[6534],{"type":40,"value":5321},{"type":31,"tag":1904,"props":6536,"children":6537},{"style":2108},[6538],{"type":40,"value":76},{"type":31,"tag":1904,"props":6540,"children":6541},{"style":1926},[6542],{"type":40,"value":4722},{"type":31,"tag":1904,"props":6544,"children":6545},{"style":2028},[6546],{"type":40,"value":2490},{"type":31,"tag":1904,"props":6548,"children":6549},{"style":3399},[6550],{"type":40,"value":6551},"'session-timeout'",{"type":31,"tag":1904,"props":6553,"children":6554},{"style":2028},[6555],{"type":40,"value":1992},{"type":31,"tag":1904,"props":6557,"children":6558},{"style":1932},[6559],{"type":40,"value":2047},{"type":31,"tag":1904,"props":6561,"children":6562},{"class":1906,"line":2256},[6563],{"type":31,"tag":1904,"props":6564,"children":6565},{"emptyLinePlaceholder":13},[6566],{"type":40,"value":2165},{"type":31,"tag":1904,"props":6568,"children":6569},{"class":1906,"line":2290},[6570],{"type":31,"tag":1904,"props":6571,"children":6572},{"style":1911},[6573],{"type":40,"value":6574},"  // avancer le temps de 5 secondes\n",{"type":31,"tag":1904,"props":6576,"children":6577},{"class":1906,"line":2333},[6578,6582,6587,6591,6596,6600,6605,6609],{"type":31,"tag":1904,"props":6579,"children":6580},{"style":1920},[6581],{"type":40,"value":6029},{"type":31,"tag":1904,"props":6583,"children":6584},{"style":2028},[6585],{"type":40,"value":6586}," vi",{"type":31,"tag":1904,"props":6588,"children":6589},{"style":2108},[6590],{"type":40,"value":76},{"type":31,"tag":1904,"props":6592,"children":6593},{"style":1926},[6594],{"type":40,"value":6595},"advanceTimersByTimeAsync",{"type":31,"tag":1904,"props":6597,"children":6598},{"style":2028},[6599],{"type":40,"value":2490},{"type":31,"tag":1904,"props":6601,"children":6602},{"style":2039},[6603],{"type":40,"value":6604},"5_000",{"type":31,"tag":1904,"props":6606,"children":6607},{"style":2028},[6608],{"type":40,"value":1992},{"type":31,"tag":1904,"props":6610,"children":6611},{"style":1932},[6612],{"type":40,"value":2047},{"type":31,"tag":1904,"props":6614,"children":6615},{"class":1906,"line":2382},[6616],{"type":31,"tag":1904,"props":6617,"children":6618},{"emptyLinePlaceholder":13},[6619],{"type":40,"value":2165},{"type":31,"tag":1904,"props":6621,"children":6622},{"class":1906,"line":4678},[6623,6627,6632,6637,6641,6646,6650,6655,6659,6664,6668],{"type":31,"tag":1904,"props":6624,"children":6625},{"style":1920},[6626],{"type":40,"value":6029},{"type":31,"tag":1904,"props":6628,"children":6629},{"style":1926},[6630],{"type":40,"value":6631}," expect",{"type":31,"tag":1904,"props":6633,"children":6634},{"style":2028},[6635],{"type":40,"value":6636},"(promise)",{"type":31,"tag":1904,"props":6638,"children":6639},{"style":2108},[6640],{"type":40,"value":76},{"type":31,"tag":1904,"props":6642,"children":6643},{"style":2028},[6644],{"type":40,"value":6645},"rejects",{"type":31,"tag":1904,"props":6647,"children":6648},{"style":2108},[6649],{"type":40,"value":76},{"type":31,"tag":1904,"props":6651,"children":6652},{"style":1926},[6653],{"type":40,"value":6654},"toThrow",{"type":31,"tag":1904,"props":6656,"children":6657},{"style":2028},[6658],{"type":40,"value":2490},{"type":31,"tag":1904,"props":6660,"children":6661},{"style":3399},[6662],{"type":40,"value":6663},"'Brevo timeout'",{"type":31,"tag":1904,"props":6665,"children":6666},{"style":2028},[6667],{"type":40,"value":1992},{"type":31,"tag":1904,"props":6669,"children":6670},{"style":1932},[6671],{"type":40,"value":2047},{"type":31,"tag":1904,"props":6673,"children":6674},{"class":1906,"line":5525},[6675],{"type":31,"tag":1904,"props":6676,"children":6677},{"emptyLinePlaceholder":13},[6678],{"type":40,"value":2165},{"type":31,"tag":1904,"props":6680,"children":6681},{"class":1906,"line":6149},[6682,6686,6690,6695,6699],{"type":31,"tag":1904,"props":6683,"children":6684},{"style":2028},[6685],{"type":40,"value":5008},{"type":31,"tag":1904,"props":6687,"children":6688},{"style":2108},[6689],{"type":40,"value":76},{"type":31,"tag":1904,"props":6691,"children":6692},{"style":1926},[6693],{"type":40,"value":6694},"useRealTimers",{"type":31,"tag":1904,"props":6696,"children":6697},{"style":2028},[6698],{"type":40,"value":2828},{"type":31,"tag":1904,"props":6700,"children":6701},{"style":1932},[6702],{"type":40,"value":2047},{"type":31,"tag":1904,"props":6704,"children":6706},{"class":1906,"line":6705},23,[6707,6711,6715],{"type":31,"tag":1904,"props":6708,"children":6709},{"style":1932},[6710],{"type":40,"value":4464},{"type":31,"tag":1904,"props":6712,"children":6713},{"style":2028},[6714],{"type":40,"value":1992},{"type":31,"tag":1904,"props":6716,"children":6717},{"style":1932},[6718],{"type":40,"value":2047},{"type":31,"tag":32,"props":6720,"children":6721},{},[6722],{"type":40,"value":6723},"Sans ce test, vous découvrirez le problème le jour où Brevo a une latence anormale et que votre job de notifications se bouche complètement.",{"type":31,"tag":4784,"props":6725,"children":6727},{"id":6726},"test-4-le-test-de-partial-failure",[6728],{"type":40,"value":6729},"Test 4 : le test de partial failure",{"type":31,"tag":32,"props":6731,"children":6732},{},[6733],{"type":40,"value":6734},"Pour les méthodes qui enchainent deux actions (ex : persistance DB + envoi email), simulez l'échec de la deuxième et vérifiez que la première est compensée ou que la méthode est idempotente.",{"type":31,"tag":1894,"props":6736,"children":6738},{"className":1896,"code":6737,"language":1898,"meta":8,"style":8},"it('does not mark session as notified in DB when Brevo send fails', async () => {\n  const session = {\n    id: 'session-partial',\n    coacheeEmail: 'coachee@example.com',\n    scheduledAt: new Date(),\n    notificationSentAt: null as Date | null,\n  };\n\n  vi.mocked(sessionRepository.findById).mockResolvedValue(session);\n  vi.mocked(brevoClient.sendTransactionalEmail).mockRejectedValue(\n    new Error('Brevo SMTP down'),\n  );\n\n  await expect(service.sendSessionConfirmation('session-partial')).rejects.toThrow();\n\n  // la DB ne doit pas avoir été mise à jour\n  expect(sessionRepository.save).not.toHaveBeenCalled();\n  expect(session.notificationSentAt).toBeNull();\n});\n",[6739],{"type":31,"tag":169,"props":6740,"children":6741},{"__ignoreMap":8},[6742,6778,6797,6817,6836,6863,6903,6911,6918,6962,7002,7031,7042,7049,7110,7117,7125,7171,7209],{"type":31,"tag":1904,"props":6743,"children":6744},{"class":1906,"line":1907},[6745,6749,6753,6758,6762,6766,6770,6774],{"type":31,"tag":1904,"props":6746,"children":6747},{"style":1926},[6748],{"type":40,"value":4839},{"type":31,"tag":1904,"props":6750,"children":6751},{"style":2028},[6752],{"type":40,"value":2490},{"type":31,"tag":1904,"props":6754,"children":6755},{"style":3399},[6756],{"type":40,"value":6757},"'does not mark session as notified in DB when Brevo send fails'",{"type":31,"tag":1904,"props":6759,"children":6760},{"style":1932},[6761],{"type":40,"value":4853},{"type":31,"tag":1904,"props":6763,"children":6764},{"style":1920},[6765],{"type":40,"value":4858},{"type":31,"tag":1904,"props":6767,"children":6768},{"style":1932},[6769],{"type":40,"value":4863},{"type":31,"tag":1904,"props":6771,"children":6772},{"style":1948},[6773],{"type":40,"value":4868},{"type":31,"tag":1904,"props":6775,"children":6776},{"style":1932},[6777],{"type":40,"value":2005},{"type":31,"tag":1904,"props":6779,"children":6780},{"class":1906,"line":817},[6781,6785,6789,6793],{"type":31,"tag":1904,"props":6782,"children":6783},{"style":1920},[6784],{"type":40,"value":2014},{"type":31,"tag":1904,"props":6786,"children":6787},{"style":2017},[6788],{"type":40,"value":4368},{"type":31,"tag":1904,"props":6790,"children":6791},{"style":1948},[6792],{"type":40,"value":2025},{"type":31,"tag":1904,"props":6794,"children":6795},{"style":1932},[6796],{"type":40,"value":2005},{"type":31,"tag":1904,"props":6798,"children":6799},{"class":1906,"line":1938},[6800,6804,6808,6813],{"type":31,"tag":1904,"props":6801,"children":6802},{"style":2028},[6803],{"type":40,"value":5082},{"type":31,"tag":1904,"props":6805,"children":6806},{"style":2108},[6807],{"type":40,"value":1951},{"type":31,"tag":1904,"props":6809,"children":6810},{"style":3399},[6811],{"type":40,"value":6812}," 'session-partial'",{"type":31,"tag":1904,"props":6814,"children":6815},{"style":1932},[6816],{"type":40,"value":1962},{"type":31,"tag":1904,"props":6818,"children":6819},{"class":1906,"line":1965},[6820,6824,6828,6832],{"type":31,"tag":1904,"props":6821,"children":6822},{"style":2028},[6823],{"type":40,"value":5094},{"type":31,"tag":1904,"props":6825,"children":6826},{"style":2108},[6827],{"type":40,"value":1951},{"type":31,"tag":1904,"props":6829,"children":6830},{"style":3399},[6831],{"type":40,"value":5688},{"type":31,"tag":1904,"props":6833,"children":6834},{"style":1932},[6835],{"type":40,"value":1962},{"type":31,"tag":1904,"props":6837,"children":6838},{"class":1906,"line":1986},[6839,6843,6847,6851,6855,6859],{"type":31,"tag":1904,"props":6840,"children":6841},{"style":2028},[6842],{"type":40,"value":5132},{"type":31,"tag":1904,"props":6844,"children":6845},{"style":2108},[6846],{"type":40,"value":1951},{"type":31,"tag":1904,"props":6848,"children":6849},{"style":2816},[6850],{"type":40,"value":2819},{"type":31,"tag":1904,"props":6852,"children":6853},{"style":1926},[6854],{"type":40,"value":5145},{"type":31,"tag":1904,"props":6856,"children":6857},{"style":2028},[6858],{"type":40,"value":2828},{"type":31,"tag":1904,"props":6860,"children":6861},{"style":1932},[6862],{"type":40,"value":1962},{"type":31,"tag":1904,"props":6864,"children":6865},{"class":1906,"line":2008},[6866,6871,6875,6880,6885,6889,6894,6899],{"type":31,"tag":1904,"props":6867,"children":6868},{"style":2028},[6869],{"type":40,"value":6870},"    notificationSentAt",{"type":31,"tag":1904,"props":6872,"children":6873},{"style":2108},[6874],{"type":40,"value":1951},{"type":31,"tag":1904,"props":6876,"children":6877},{"style":1954},[6878],{"type":40,"value":6879}," null",{"type":31,"tag":1904,"props":6881,"children":6882},{"style":1920},[6883],{"type":40,"value":6884}," as",{"type":31,"tag":1904,"props":6886,"children":6887},{"style":2470},[6888],{"type":40,"value":5145},{"type":31,"tag":1904,"props":6890,"children":6891},{"style":1948},[6892],{"type":40,"value":6893}," |",{"type":31,"tag":1904,"props":6895,"children":6897},{"style":6896},"--shiki-default:#CA9EE6;--shiki-default-font-style:italic;--shiki-dark:#79B8FF;--shiki-dark-font-style:inherit",[6898],{"type":40,"value":6879},{"type":31,"tag":1904,"props":6900,"children":6901},{"style":1932},[6902],{"type":40,"value":1962},{"type":31,"tag":1904,"props":6904,"children":6905},{"class":1906,"line":2050},[6906],{"type":31,"tag":1904,"props":6907,"children":6908},{"style":1932},[6909],{"type":40,"value":6910},"  };\n",{"type":31,"tag":1904,"props":6912,"children":6913},{"class":1906,"line":2094},[6914],{"type":31,"tag":1904,"props":6915,"children":6916},{"emptyLinePlaceholder":13},[6917],{"type":40,"value":2165},{"type":31,"tag":1904,"props":6919,"children":6920},{"class":1906,"line":2150},[6921,6925,6929,6933,6937,6941,6945,6949,6953,6958],{"type":31,"tag":1904,"props":6922,"children":6923},{"style":2028},[6924],{"type":40,"value":5008},{"type":31,"tag":1904,"props":6926,"children":6927},{"style":2108},[6928],{"type":40,"value":76},{"type":31,"tag":1904,"props":6930,"children":6931},{"style":1926},[6932],{"type":40,"value":5017},{"type":31,"tag":1904,"props":6934,"children":6935},{"style":2028},[6936],{"type":40,"value":5022},{"type":31,"tag":1904,"props":6938,"children":6939},{"style":2108},[6940],{"type":40,"value":76},{"type":31,"tag":1904,"props":6942,"children":6943},{"style":2028},[6944],{"type":40,"value":5031},{"type":31,"tag":1904,"props":6946,"children":6947},{"style":2108},[6948],{"type":40,"value":76},{"type":31,"tag":1904,"props":6950,"children":6951},{"style":1926},[6952],{"type":40,"value":5217},{"type":31,"tag":1904,"props":6954,"children":6955},{"style":2028},[6956],{"type":40,"value":6957},"(session)",{"type":31,"tag":1904,"props":6959,"children":6960},{"style":1932},[6961],{"type":40,"value":2047},{"type":31,"tag":1904,"props":6963,"children":6964},{"class":1906,"line":2159},[6965,6969,6973,6977,6981,6985,6989,6993,6998],{"type":31,"tag":1904,"props":6966,"children":6967},{"style":2028},[6968],{"type":40,"value":5008},{"type":31,"tag":1904,"props":6970,"children":6971},{"style":2108},[6972],{"type":40,"value":76},{"type":31,"tag":1904,"props":6974,"children":6975},{"style":1926},[6976],{"type":40,"value":5017},{"type":31,"tag":1904,"props":6978,"children":6979},{"style":2028},[6980],{"type":40,"value":5199},{"type":31,"tag":1904,"props":6982,"children":6983},{"style":2108},[6984],{"type":40,"value":76},{"type":31,"tag":1904,"props":6986,"children":6987},{"style":2028},[6988],{"type":40,"value":5208},{"type":31,"tag":1904,"props":6990,"children":6991},{"style":2108},[6992],{"type":40,"value":76},{"type":31,"tag":1904,"props":6994,"children":6995},{"style":1926},[6996],{"type":40,"value":6997},"mockRejectedValue",{"type":31,"tag":1904,"props":6999,"children":7000},{"style":2028},[7001],{"type":40,"value":1935},{"type":31,"tag":1904,"props":7003,"children":7004},{"class":1906,"line":2168},[7005,7010,7014,7018,7023,7027],{"type":31,"tag":1904,"props":7006,"children":7007},{"style":2816},[7008],{"type":40,"value":7009},"    new",{"type":31,"tag":1904,"props":7011,"children":7012},{"style":1926},[7013],{"type":40,"value":4440},{"type":31,"tag":1904,"props":7015,"children":7016},{"style":2028},[7017],{"type":40,"value":2490},{"type":31,"tag":1904,"props":7019,"children":7020},{"style":3399},[7021],{"type":40,"value":7022},"'Brevo SMTP down'",{"type":31,"tag":1904,"props":7024,"children":7025},{"style":2028},[7026],{"type":40,"value":1992},{"type":31,"tag":1904,"props":7028,"children":7029},{"style":1932},[7030],{"type":40,"value":1962},{"type":31,"tag":1904,"props":7032,"children":7033},{"class":1906,"line":2177},[7034,7038],{"type":31,"tag":1904,"props":7035,"children":7036},{"style":2028},[7037],{"type":40,"value":3096},{"type":31,"tag":1904,"props":7039,"children":7040},{"style":1932},[7041],{"type":40,"value":2047},{"type":31,"tag":1904,"props":7043,"children":7044},{"class":1906,"line":2194},[7045],{"type":31,"tag":1904,"props":7046,"children":7047},{"emptyLinePlaceholder":13},[7048],{"type":40,"value":2165},{"type":31,"tag":1904,"props":7050,"children":7051},{"class":1906,"line":2215},[7052,7056,7060,7065,7069,7073,7077,7082,7086,7090,7094,7098,7102,7106],{"type":31,"tag":1904,"props":7053,"children":7054},{"style":1920},[7055],{"type":40,"value":6029},{"type":31,"tag":1904,"props":7057,"children":7058},{"style":1926},[7059],{"type":40,"value":6631},{"type":31,"tag":1904,"props":7061,"children":7062},{"style":2028},[7063],{"type":40,"value":7064},"(service",{"type":31,"tag":1904,"props":7066,"children":7067},{"style":2108},[7068],{"type":40,"value":76},{"type":31,"tag":1904,"props":7070,"children":7071},{"style":1926},[7072],{"type":40,"value":4722},{"type":31,"tag":1904,"props":7074,"children":7075},{"style":2028},[7076],{"type":40,"value":2490},{"type":31,"tag":1904,"props":7078,"children":7079},{"style":3399},[7080],{"type":40,"value":7081},"'session-partial'",{"type":31,"tag":1904,"props":7083,"children":7084},{"style":2028},[7085],{"type":40,"value":5175},{"type":31,"tag":1904,"props":7087,"children":7088},{"style":2108},[7089],{"type":40,"value":76},{"type":31,"tag":1904,"props":7091,"children":7092},{"style":2028},[7093],{"type":40,"value":6645},{"type":31,"tag":1904,"props":7095,"children":7096},{"style":2108},[7097],{"type":40,"value":76},{"type":31,"tag":1904,"props":7099,"children":7100},{"style":1926},[7101],{"type":40,"value":6654},{"type":31,"tag":1904,"props":7103,"children":7104},{"style":2028},[7105],{"type":40,"value":2828},{"type":31,"tag":1904,"props":7107,"children":7108},{"style":1932},[7109],{"type":40,"value":2047},{"type":31,"tag":1904,"props":7111,"children":7112},{"class":1906,"line":2236},[7113],{"type":31,"tag":1904,"props":7114,"children":7115},{"emptyLinePlaceholder":13},[7116],{"type":40,"value":2165},{"type":31,"tag":1904,"props":7118,"children":7119},{"class":1906,"line":2256},[7120],{"type":31,"tag":1904,"props":7121,"children":7122},{"style":1911},[7123],{"type":40,"value":7124},"  // la DB ne doit pas avoir été mise à jour\n",{"type":31,"tag":1904,"props":7126,"children":7127},{"class":1906,"line":2290},[7128,7132,7136,7140,7145,7149,7154,7158,7163,7167],{"type":31,"tag":1904,"props":7129,"children":7130},{"style":1926},[7131],{"type":40,"value":5446},{"type":31,"tag":1904,"props":7133,"children":7134},{"style":2028},[7135],{"type":40,"value":5022},{"type":31,"tag":1904,"props":7137,"children":7138},{"style":2108},[7139],{"type":40,"value":76},{"type":31,"tag":1904,"props":7141,"children":7142},{"style":2028},[7143],{"type":40,"value":7144},"save)",{"type":31,"tag":1904,"props":7146,"children":7147},{"style":2108},[7148],{"type":40,"value":76},{"type":31,"tag":1904,"props":7150,"children":7151},{"style":2028},[7152],{"type":40,"value":7153},"not",{"type":31,"tag":1904,"props":7155,"children":7156},{"style":2108},[7157],{"type":40,"value":76},{"type":31,"tag":1904,"props":7159,"children":7160},{"style":1926},[7161],{"type":40,"value":7162},"toHaveBeenCalled",{"type":31,"tag":1904,"props":7164,"children":7165},{"style":2028},[7166],{"type":40,"value":2828},{"type":31,"tag":1904,"props":7168,"children":7169},{"style":1932},[7170],{"type":40,"value":2047},{"type":31,"tag":1904,"props":7172,"children":7173},{"class":1906,"line":2333},[7174,7178,7183,7187,7192,7196,7201,7205],{"type":31,"tag":1904,"props":7175,"children":7176},{"style":1926},[7177],{"type":40,"value":5446},{"type":31,"tag":1904,"props":7179,"children":7180},{"style":2028},[7181],{"type":40,"value":7182},"(session",{"type":31,"tag":1904,"props":7184,"children":7185},{"style":2108},[7186],{"type":40,"value":76},{"type":31,"tag":1904,"props":7188,"children":7189},{"style":2028},[7190],{"type":40,"value":7191},"notificationSentAt)",{"type":31,"tag":1904,"props":7193,"children":7194},{"style":2108},[7195],{"type":40,"value":76},{"type":31,"tag":1904,"props":7197,"children":7198},{"style":1926},[7199],{"type":40,"value":7200},"toBeNull",{"type":31,"tag":1904,"props":7202,"children":7203},{"style":2028},[7204],{"type":40,"value":2828},{"type":31,"tag":1904,"props":7206,"children":7207},{"style":1932},[7208],{"type":40,"value":2047},{"type":31,"tag":1904,"props":7210,"children":7211},{"class":1906,"line":2382},[7212,7216,7220],{"type":31,"tag":1904,"props":7213,"children":7214},{"style":1932},[7215],{"type":40,"value":4464},{"type":31,"tag":1904,"props":7217,"children":7218},{"style":2028},[7219],{"type":40,"value":1992},{"type":31,"tag":1904,"props":7221,"children":7222},{"style":1932},[7223],{"type":40,"value":2047},{"type":31,"tag":32,"props":7225,"children":7226},{},[7227],{"type":40,"value":7228},"Ce test révèle souvent un bug d'idempotence : la méthode marque la session \"notifiée\" en DB avant d'envoyer l'email via Brevo, donc si l'envoi échoue et qu'on retry, on n'envoie pas le deuxième email. Le coachee ne reçoit jamais sa confirmation, mais la DB indique que tout va bien.",{"type":31,"tag":48,"props":7230,"children":7231},{},[],{"type":31,"tag":52,"props":7233,"children":7235},{"id":7234},"le-wrapper-anti-fragile-à-demander-à-claude",[7236],{"type":40,"value":7237},"Le wrapper anti-fragile à demander à Claude",{"type":31,"tag":32,"props":7239,"children":7240},{},[7241,7243,7248],{"type":40,"value":7242},"Une fois ces 4 tests écrits, je prompte Claude différemment. Au lieu de \"implémente ",{"type":31,"tag":169,"props":7244,"children":7246},{"className":7245},[],[7247],{"type":40,"value":4722},{"type":40,"value":7249},"\", je dis :",{"type":31,"tag":32,"props":7251,"children":7252},{},[7253],{"type":31,"tag":97,"props":7254,"children":7255},{},[7256,7258,7263,7265,7271],{"type":40,"value":7257},"\"Implémente ",{"type":31,"tag":169,"props":7259,"children":7261},{"className":7260},[],[7262],{"type":40,"value":4722},{"type":40,"value":7264}," dans NestJS en gérant les 429 de Brevo avec un retry exponentiel (p-retry ou helper maison), un timeout sur l'appel réseau (AbortSignal ou p-timeout), et une stratégie d'idempotence basée sur un champ ",{"type":31,"tag":169,"props":7266,"children":7268},{"className":7267},[],[7269],{"type":40,"value":7270},"notificationSentAt",{"type":40,"value":7272}," en DB. Les tests Vitest fournis doivent tous passer.\"",{"type":31,"tag":32,"props":7274,"children":7275},{},[7276],{"type":40,"value":7277},"Voici ce que Claude livre alors :",{"type":31,"tag":1894,"props":7279,"children":7281},{"className":1896,"code":7280,"language":1898,"meta":8,"style":8},"// apps/api/src/infrastructure/notification/brevo-notification.service.ts\n\nimport pRetry, { AbortError } from 'p-retry';\n\nconst BREVO_TIMEOUT_MS = 5_000;\nconst BREVO_RETRY_MAX = 5;\n\n@Injectable()\nexport class BrevoNotificationService {\n  constructor(\n    private readonly sessionRepository: SessionRepository,\n    private readonly brevoClient: BrevoClient,\n  ) {}\n\n  async sendSessionConfirmation(sessionId: string): Promise\u003Cvoid> {\n    const session = await this.sessionRepository.findById(sessionId);\n    if (session == null) throw new Error(`Session not found: ${sessionId}`);\n\n    // idempotence : ne pas renvoyer si déjà envoyé\n    if (session.notificationSentAt != null) return;\n\n    await pRetry(\n      async () => {\n        const controller = new AbortController();\n        const timer = setTimeout(() => controller.abort(), BREVO_TIMEOUT_MS);\n\n        try {\n          await this.brevoClient.sendTransactionalEmail(\n            {\n              to: [{ email: session.coacheeEmail }],\n              templateId: BREVO_TEMPLATE_IDS.SESSION_CONFIRMATION,\n              params: { sessionDate: session.scheduledAt },\n            },\n            { signal: controller.signal },\n          );\n        } catch (err: unknown) {\n          clearTimeout(timer);\n          if (controller.signal.aborted) {\n            throw new AbortError('Brevo timeout');\n          }\n          const statusCode = (err as { statusCode?: number }).statusCode;\n          if (statusCode === 429 || statusCode === 503) throw err; // retry\n          throw new AbortError((err as Error).message); // pas de retry sur les 4xx\n        }\n        clearTimeout(timer);\n      },\n      {\n        retries: BREVO_RETRY_MAX,\n        factor: 2,\n        minTimeout: 100,\n        onFailedAttempt: (error) => {\n          if (error.retriesLeft === 0) throw error;\n        },\n      },\n    );\n\n    await this.sessionRepository.markNotified(sessionId, new Date());\n  }\n}\n",[7282],{"type":31,"tag":169,"props":7283,"children":7284},{"__ignoreMap":8},[7285,7292,7299,7343,7350,7376,7401,7408,7423,7442,7453,7480,7507,7518,7525,7580,7627,7696,7703,7711,7754,7761,7776,7796,7831,7898,7906,7919,7952,7961,8014,8043,8084,8093,8128,8141,8181,8199,8235,8269,8278,8342,8404,8456,8465,8482,8491,8500,8521,8543,8564,8598,8645,8654,8662,8675,8683,8738,8746],{"type":31,"tag":1904,"props":7286,"children":7287},{"class":1906,"line":1907},[7288],{"type":31,"tag":1904,"props":7289,"children":7290},{"style":1911},[7291],{"type":40,"value":4169},{"type":31,"tag":1904,"props":7293,"children":7294},{"class":1906,"line":817},[7295],{"type":31,"tag":1904,"props":7296,"children":7297},{"emptyLinePlaceholder":13},[7298],{"type":40,"value":2165},{"type":31,"tag":1904,"props":7300,"children":7301},{"class":1906,"line":1938},[7302,7307,7312,7316,7320,7325,7329,7334,7339],{"type":31,"tag":1904,"props":7303,"children":7304},{"style":1920},[7305],{"type":40,"value":7306},"import",{"type":31,"tag":1904,"props":7308,"children":7309},{"style":2028},[7310],{"type":40,"value":7311}," pRetry",{"type":31,"tag":1904,"props":7313,"children":7314},{"style":1932},[7315],{"type":40,"value":4853},{"type":31,"tag":1904,"props":7317,"children":7318},{"style":1932},[7319],{"type":40,"value":4625},{"type":31,"tag":1904,"props":7321,"children":7322},{"style":2028},[7323],{"type":40,"value":7324}," AbortError ",{"type":31,"tag":1904,"props":7326,"children":7327},{"style":1932},[7328],{"type":40,"value":4464},{"type":31,"tag":1904,"props":7330,"children":7331},{"style":1920},[7332],{"type":40,"value":7333}," from",{"type":31,"tag":1904,"props":7335,"children":7336},{"style":3399},[7337],{"type":40,"value":7338}," 'p-retry'",{"type":31,"tag":1904,"props":7340,"children":7341},{"style":1932},[7342],{"type":40,"value":2047},{"type":31,"tag":1904,"props":7344,"children":7345},{"class":1906,"line":1965},[7346],{"type":31,"tag":1904,"props":7347,"children":7348},{"emptyLinePlaceholder":13},[7349],{"type":40,"value":2165},{"type":31,"tag":1904,"props":7351,"children":7352},{"class":1906,"line":1986},[7353,7358,7363,7367,7372],{"type":31,"tag":1904,"props":7354,"children":7355},{"style":1920},[7356],{"type":40,"value":7357},"const",{"type":31,"tag":1904,"props":7359,"children":7360},{"style":2017},[7361],{"type":40,"value":7362}," BREVO_TIMEOUT_MS",{"type":31,"tag":1904,"props":7364,"children":7365},{"style":1948},[7366],{"type":40,"value":2025},{"type":31,"tag":1904,"props":7368,"children":7369},{"style":2039},[7370],{"type":40,"value":7371}," 5_000",{"type":31,"tag":1904,"props":7373,"children":7374},{"style":1932},[7375],{"type":40,"value":2047},{"type":31,"tag":1904,"props":7377,"children":7378},{"class":1906,"line":2008},[7379,7383,7388,7392,7397],{"type":31,"tag":1904,"props":7380,"children":7381},{"style":1920},[7382],{"type":40,"value":7357},{"type":31,"tag":1904,"props":7384,"children":7385},{"style":2017},[7386],{"type":40,"value":7387}," BREVO_RETRY_MAX",{"type":31,"tag":1904,"props":7389,"children":7390},{"style":1948},[7391],{"type":40,"value":2025},{"type":31,"tag":1904,"props":7393,"children":7394},{"style":2039},[7395],{"type":40,"value":7396}," 5",{"type":31,"tag":1904,"props":7398,"children":7399},{"style":1932},[7400],{"type":40,"value":2047},{"type":31,"tag":1904,"props":7402,"children":7403},{"class":1906,"line":2050},[7404],{"type":31,"tag":1904,"props":7405,"children":7406},{"emptyLinePlaceholder":13},[7407],{"type":40,"value":2165},{"type":31,"tag":1904,"props":7409,"children":7410},{"class":1906,"line":2094},[7411,7415,7419],{"type":31,"tag":1904,"props":7412,"children":7413},{"style":2548},[7414],{"type":40,"value":2551},{"type":31,"tag":1904,"props":7416,"children":7417},{"style":1926},[7418],{"type":40,"value":2556},{"type":31,"tag":1904,"props":7420,"children":7421},{"style":2559},[7422],{"type":40,"value":2562},{"type":31,"tag":1904,"props":7424,"children":7425},{"class":1906,"line":2150},[7426,7430,7434,7438],{"type":31,"tag":1904,"props":7427,"children":7428},{"style":1920},[7429],{"type":40,"value":2462},{"type":31,"tag":1904,"props":7431,"children":7432},{"style":1920},[7433],{"type":40,"value":2574},{"type":31,"tag":1904,"props":7435,"children":7436},{"style":2470},[7437],{"type":40,"value":4207},{"type":31,"tag":1904,"props":7439,"children":7440},{"style":1932},[7441],{"type":40,"value":2005},{"type":31,"tag":1904,"props":7443,"children":7444},{"class":1906,"line":2159},[7445,7449],{"type":31,"tag":1904,"props":7446,"children":7447},{"style":1920},[7448],{"type":40,"value":2995},{"type":31,"tag":1904,"props":7450,"children":7451},{"style":1932},[7452],{"type":40,"value":1935},{"type":31,"tag":1904,"props":7454,"children":7455},{"class":1906,"line":2168},[7456,7460,7464,7468,7472,7476],{"type":31,"tag":1904,"props":7457,"children":7458},{"style":1920},[7459],{"type":40,"value":3007},{"type":31,"tag":1904,"props":7461,"children":7462},{"style":1920},[7463],{"type":40,"value":3012},{"type":31,"tag":1904,"props":7465,"children":7466},{"style":1942},[7467],{"type":40,"value":4238},{"type":31,"tag":1904,"props":7469,"children":7470},{"style":1948},[7471],{"type":40,"value":1951},{"type":31,"tag":1904,"props":7473,"children":7474},{"style":2470},[7475],{"type":40,"value":4247},{"type":31,"tag":1904,"props":7477,"children":7478},{"style":1932},[7479],{"type":40,"value":1962},{"type":31,"tag":1904,"props":7481,"children":7482},{"class":1906,"line":2177},[7483,7487,7491,7495,7499,7503],{"type":31,"tag":1904,"props":7484,"children":7485},{"style":1920},[7486],{"type":40,"value":3007},{"type":31,"tag":1904,"props":7488,"children":7489},{"style":1920},[7490],{"type":40,"value":3012},{"type":31,"tag":1904,"props":7492,"children":7493},{"style":1942},[7494],{"type":40,"value":4267},{"type":31,"tag":1904,"props":7496,"children":7497},{"style":1948},[7498],{"type":40,"value":1951},{"type":31,"tag":1904,"props":7500,"children":7501},{"style":2470},[7502],{"type":40,"value":4276},{"type":31,"tag":1904,"props":7504,"children":7505},{"style":1932},[7506],{"type":40,"value":1962},{"type":31,"tag":1904,"props":7508,"children":7509},{"class":1906,"line":2194},[7510,7514],{"type":31,"tag":1904,"props":7511,"children":7512},{"style":1932},[7513],{"type":40,"value":3096},{"type":31,"tag":1904,"props":7515,"children":7516},{"style":1932},[7517],{"type":40,"value":3101},{"type":31,"tag":1904,"props":7519,"children":7520},{"class":1906,"line":2215},[7521],{"type":31,"tag":1904,"props":7522,"children":7523},{"emptyLinePlaceholder":13},[7524],{"type":40,"value":2165},{"type":31,"tag":1904,"props":7526,"children":7527},{"class":1906,"line":2236},[7528,7532,7536,7540,7544,7548,7552,7556,7560,7564,7568,7572,7576],{"type":31,"tag":1904,"props":7529,"children":7530},{"style":1920},[7531],{"type":40,"value":3116},{"type":31,"tag":1904,"props":7533,"children":7534},{"style":1926},[7535],{"type":40,"value":4310},{"type":31,"tag":1904,"props":7537,"children":7538},{"style":1932},[7539],{"type":40,"value":2490},{"type":31,"tag":1904,"props":7541,"children":7542},{"style":1942},[7543],{"type":40,"value":4319},{"type":31,"tag":1904,"props":7545,"children":7546},{"style":1948},[7547],{"type":40,"value":1951},{"type":31,"tag":1904,"props":7549,"children":7550},{"style":1954},[7551],{"type":40,"value":2790},{"type":31,"tag":1904,"props":7553,"children":7554},{"style":1932},[7555],{"type":40,"value":1992},{"type":31,"tag":1904,"props":7557,"children":7558},{"style":1948},[7559],{"type":40,"value":1951},{"type":31,"tag":1904,"props":7561,"children":7562},{"style":2470},[7563],{"type":40,"value":3152},{"type":31,"tag":1904,"props":7565,"children":7566},{"style":3155},[7567],{"type":40,"value":3158},{"type":31,"tag":1904,"props":7569,"children":7570},{"style":1954},[7571],{"type":40,"value":4348},{"type":31,"tag":1904,"props":7573,"children":7574},{"style":3155},[7575],{"type":40,"value":3168},{"type":31,"tag":1904,"props":7577,"children":7578},{"style":1932},[7579],{"type":40,"value":2005},{"type":31,"tag":1904,"props":7581,"children":7582},{"class":1906,"line":2256},[7583,7587,7591,7595,7599,7603,7607,7611,7615,7619,7623],{"type":31,"tag":1904,"props":7584,"children":7585},{"style":1920},[7586],{"type":40,"value":3180},{"type":31,"tag":1904,"props":7588,"children":7589},{"style":2017},[7590],{"type":40,"value":4368},{"type":31,"tag":1904,"props":7592,"children":7593},{"style":1948},[7594],{"type":40,"value":2025},{"type":31,"tag":1904,"props":7596,"children":7597},{"style":1920},[7598],{"type":40,"value":3194},{"type":31,"tag":1904,"props":7600,"children":7601},{"style":3197},[7602],{"type":40,"value":3200},{"type":31,"tag":1904,"props":7604,"children":7605},{"style":2108},[7606],{"type":40,"value":76},{"type":31,"tag":1904,"props":7608,"children":7609},{"style":2028},[7610],{"type":40,"value":4389},{"type":31,"tag":1904,"props":7612,"children":7613},{"style":2108},[7614],{"type":40,"value":76},{"type":31,"tag":1904,"props":7616,"children":7617},{"style":1926},[7618],{"type":40,"value":3218},{"type":31,"tag":1904,"props":7620,"children":7621},{"style":2028},[7622],{"type":40,"value":4402},{"type":31,"tag":1904,"props":7624,"children":7625},{"style":1932},[7626],{"type":40,"value":2047},{"type":31,"tag":1904,"props":7628,"children":7629},{"class":1906,"line":2290},[7630,7634,7639,7644,7648,7652,7656,7660,7664,7668,7672,7676,7680,7684,7688,7692],{"type":31,"tag":1904,"props":7631,"children":7632},{"style":1920},[7633],{"type":40,"value":3244},{"type":31,"tag":1904,"props":7635,"children":7636},{"style":2028},[7637],{"type":40,"value":7638}," (session ",{"type":31,"tag":1904,"props":7640,"children":7641},{"style":1948},[7642],{"type":40,"value":7643},"==",{"type":31,"tag":1904,"props":7645,"children":7646},{"style":1954},[7647],{"type":40,"value":6879},{"type":31,"tag":1904,"props":7649,"children":7650},{"style":2028},[7651],{"type":40,"value":2135},{"type":31,"tag":1904,"props":7653,"children":7654},{"style":1920},[7655],{"type":40,"value":4431},{"type":31,"tag":1904,"props":7657,"children":7658},{"style":2816},[7659],{"type":40,"value":2819},{"type":31,"tag":1904,"props":7661,"children":7662},{"style":1926},[7663],{"type":40,"value":4440},{"type":31,"tag":1904,"props":7665,"children":7666},{"style":2028},[7667],{"type":40,"value":2490},{"type":31,"tag":1904,"props":7669,"children":7670},{"style":3399},[7671],{"type":40,"value":4449},{"type":31,"tag":1904,"props":7673,"children":7674},{"style":4452},[7675],{"type":40,"value":4455},{"type":31,"tag":1904,"props":7677,"children":7678},{"style":2028},[7679],{"type":40,"value":4319},{"type":31,"tag":1904,"props":7681,"children":7682},{"style":4452},[7683],{"type":40,"value":4464},{"type":31,"tag":1904,"props":7685,"children":7686},{"style":3399},[7687],{"type":40,"value":4469},{"type":31,"tag":1904,"props":7689,"children":7690},{"style":2028},[7691],{"type":40,"value":1992},{"type":31,"tag":1904,"props":7693,"children":7694},{"style":1932},[7695],{"type":40,"value":2047},{"type":31,"tag":1904,"props":7697,"children":7698},{"class":1906,"line":2333},[7699],{"type":31,"tag":1904,"props":7700,"children":7701},{"emptyLinePlaceholder":13},[7702],{"type":40,"value":2165},{"type":31,"tag":1904,"props":7704,"children":7705},{"class":1906,"line":2382},[7706],{"type":31,"tag":1904,"props":7707,"children":7708},{"style":1911},[7709],{"type":40,"value":7710},"    // idempotence : ne pas renvoyer si déjà envoyé\n",{"type":31,"tag":1904,"props":7712,"children":7713},{"class":1906,"line":4678},[7714,7718,7723,7727,7732,7737,7741,7745,7750],{"type":31,"tag":1904,"props":7715,"children":7716},{"style":1920},[7717],{"type":40,"value":3244},{"type":31,"tag":1904,"props":7719,"children":7720},{"style":2028},[7721],{"type":40,"value":7722}," (session",{"type":31,"tag":1904,"props":7724,"children":7725},{"style":2108},[7726],{"type":40,"value":76},{"type":31,"tag":1904,"props":7728,"children":7729},{"style":2028},[7730],{"type":40,"value":7731},"notificationSentAt ",{"type":31,"tag":1904,"props":7733,"children":7734},{"style":1948},[7735],{"type":40,"value":7736},"!=",{"type":31,"tag":1904,"props":7738,"children":7739},{"style":1954},[7740],{"type":40,"value":6879},{"type":31,"tag":1904,"props":7742,"children":7743},{"style":2028},[7744],{"type":40,"value":2135},{"type":31,"tag":1904,"props":7746,"children":7747},{"style":1920},[7748],{"type":40,"value":7749},"return",{"type":31,"tag":1904,"props":7751,"children":7752},{"style":1932},[7753],{"type":40,"value":2047},{"type":31,"tag":1904,"props":7755,"children":7756},{"class":1906,"line":5525},[7757],{"type":31,"tag":1904,"props":7758,"children":7759},{"emptyLinePlaceholder":13},[7760],{"type":40,"value":2165},{"type":31,"tag":1904,"props":7762,"children":7763},{"class":1906,"line":6149},[7764,7768,7772],{"type":31,"tag":1904,"props":7765,"children":7766},{"style":1920},[7767],{"type":40,"value":3313},{"type":31,"tag":1904,"props":7769,"children":7770},{"style":1926},[7771],{"type":40,"value":7311},{"type":31,"tag":1904,"props":7773,"children":7774},{"style":2028},[7775],{"type":40,"value":1935},{"type":31,"tag":1904,"props":7777,"children":7778},{"class":1906,"line":6705},[7779,7784,7788,7792],{"type":31,"tag":1904,"props":7780,"children":7781},{"style":1920},[7782],{"type":40,"value":7783},"      async",{"type":31,"tag":1904,"props":7785,"children":7786},{"style":1932},[7787],{"type":40,"value":4863},{"type":31,"tag":1904,"props":7789,"children":7790},{"style":1948},[7791],{"type":40,"value":4868},{"type":31,"tag":1904,"props":7793,"children":7794},{"style":1932},[7795],{"type":40,"value":2005},{"type":31,"tag":1904,"props":7797,"children":7799},{"class":1906,"line":7798},24,[7800,7805,7810,7814,7818,7823,7827],{"type":31,"tag":1904,"props":7801,"children":7802},{"style":1920},[7803],{"type":40,"value":7804},"        const",{"type":31,"tag":1904,"props":7806,"children":7807},{"style":2017},[7808],{"type":40,"value":7809}," controller",{"type":31,"tag":1904,"props":7811,"children":7812},{"style":1948},[7813],{"type":40,"value":2025},{"type":31,"tag":1904,"props":7815,"children":7816},{"style":2816},[7817],{"type":40,"value":2819},{"type":31,"tag":1904,"props":7819,"children":7820},{"style":1926},[7821],{"type":40,"value":7822}," AbortController",{"type":31,"tag":1904,"props":7824,"children":7825},{"style":2028},[7826],{"type":40,"value":2828},{"type":31,"tag":1904,"props":7828,"children":7829},{"style":1932},[7830],{"type":40,"value":2047},{"type":31,"tag":1904,"props":7832,"children":7834},{"class":1906,"line":7833},25,[7835,7839,7844,7848,7853,7857,7861,7865,7869,7873,7878,7882,7886,7890,7894],{"type":31,"tag":1904,"props":7836,"children":7837},{"style":1920},[7838],{"type":40,"value":7804},{"type":31,"tag":1904,"props":7840,"children":7841},{"style":2017},[7842],{"type":40,"value":7843}," timer",{"type":31,"tag":1904,"props":7845,"children":7846},{"style":1948},[7847],{"type":40,"value":2025},{"type":31,"tag":1904,"props":7849,"children":7850},{"style":1926},[7851],{"type":40,"value":7852}," setTimeout",{"type":31,"tag":1904,"props":7854,"children":7855},{"style":2028},[7856],{"type":40,"value":2490},{"type":31,"tag":1904,"props":7858,"children":7859},{"style":1932},[7860],{"type":40,"value":2828},{"type":31,"tag":1904,"props":7862,"children":7863},{"style":1948},[7864],{"type":40,"value":4868},{"type":31,"tag":1904,"props":7866,"children":7867},{"style":2028},[7868],{"type":40,"value":7809},{"type":31,"tag":1904,"props":7870,"children":7871},{"style":2108},[7872],{"type":40,"value":76},{"type":31,"tag":1904,"props":7874,"children":7875},{"style":1926},[7876],{"type":40,"value":7877},"abort",{"type":31,"tag":1904,"props":7879,"children":7880},{"style":2028},[7881],{"type":40,"value":2828},{"type":31,"tag":1904,"props":7883,"children":7884},{"style":1932},[7885],{"type":40,"value":4853},{"type":31,"tag":1904,"props":7887,"children":7888},{"style":2017},[7889],{"type":40,"value":7362},{"type":31,"tag":1904,"props":7891,"children":7892},{"style":2028},[7893],{"type":40,"value":1992},{"type":31,"tag":1904,"props":7895,"children":7896},{"style":1932},[7897],{"type":40,"value":2047},{"type":31,"tag":1904,"props":7899,"children":7901},{"class":1906,"line":7900},26,[7902],{"type":31,"tag":1904,"props":7903,"children":7904},{"emptyLinePlaceholder":13},[7905],{"type":40,"value":2165},{"type":31,"tag":1904,"props":7907,"children":7909},{"class":1906,"line":7908},27,[7910,7915],{"type":31,"tag":1904,"props":7911,"children":7912},{"style":1920},[7913],{"type":40,"value":7914},"        try",{"type":31,"tag":1904,"props":7916,"children":7917},{"style":1932},[7918],{"type":40,"value":2005},{"type":31,"tag":1904,"props":7920,"children":7922},{"class":1906,"line":7921},28,[7923,7928,7932,7936,7940,7944,7948],{"type":31,"tag":1904,"props":7924,"children":7925},{"style":1920},[7926],{"type":40,"value":7927},"          await",{"type":31,"tag":1904,"props":7929,"children":7930},{"style":3197},[7931],{"type":40,"value":3200},{"type":31,"tag":1904,"props":7933,"children":7934},{"style":2108},[7935],{"type":40,"value":76},{"type":31,"tag":1904,"props":7937,"children":7938},{"style":2028},[7939],{"type":40,"value":4504},{"type":31,"tag":1904,"props":7941,"children":7942},{"style":2108},[7943],{"type":40,"value":76},{"type":31,"tag":1904,"props":7945,"children":7946},{"style":1926},[7947],{"type":40,"value":4513},{"type":31,"tag":1904,"props":7949,"children":7950},{"style":2028},[7951],{"type":40,"value":1935},{"type":31,"tag":1904,"props":7953,"children":7955},{"class":1906,"line":7954},29,[7956],{"type":31,"tag":1904,"props":7957,"children":7958},{"style":1932},[7959],{"type":40,"value":7960},"            {\n",{"type":31,"tag":1904,"props":7962,"children":7964},{"class":1906,"line":7963},30,[7965,7970,7974,7978,7982,7986,7990,7994,7998,8002,8006,8010],{"type":31,"tag":1904,"props":7966,"children":7967},{"style":2028},[7968],{"type":40,"value":7969},"              to",{"type":31,"tag":1904,"props":7971,"children":7972},{"style":2108},[7973],{"type":40,"value":1951},{"type":31,"tag":1904,"props":7975,"children":7976},{"style":2028},[7977],{"type":40,"value":4538},{"type":31,"tag":1904,"props":7979,"children":7980},{"style":1932},[7981],{"type":40,"value":4543},{"type":31,"tag":1904,"props":7983,"children":7984},{"style":2028},[7985],{"type":40,"value":4548},{"type":31,"tag":1904,"props":7987,"children":7988},{"style":2108},[7989],{"type":40,"value":1951},{"type":31,"tag":1904,"props":7991,"children":7992},{"style":2028},[7993],{"type":40,"value":4368},{"type":31,"tag":1904,"props":7995,"children":7996},{"style":2108},[7997],{"type":40,"value":76},{"type":31,"tag":1904,"props":7999,"children":8000},{"style":2028},[8001],{"type":40,"value":4565},{"type":31,"tag":1904,"props":8003,"children":8004},{"style":1932},[8005],{"type":40,"value":4464},{"type":31,"tag":1904,"props":8007,"children":8008},{"style":2028},[8009],{"type":40,"value":4574},{"type":31,"tag":1904,"props":8011,"children":8012},{"style":1932},[8013],{"type":40,"value":1962},{"type":31,"tag":1904,"props":8015,"children":8017},{"class":1906,"line":8016},31,[8018,8023,8027,8031,8035,8039],{"type":31,"tag":1904,"props":8019,"children":8020},{"style":2028},[8021],{"type":40,"value":8022},"              templateId",{"type":31,"tag":1904,"props":8024,"children":8025},{"style":2108},[8026],{"type":40,"value":1951},{"type":31,"tag":1904,"props":8028,"children":8029},{"style":2039},[8030],{"type":40,"value":4595},{"type":31,"tag":1904,"props":8032,"children":8033},{"style":2108},[8034],{"type":40,"value":76},{"type":31,"tag":1904,"props":8036,"children":8037},{"style":2039},[8038],{"type":40,"value":4604},{"type":31,"tag":1904,"props":8040,"children":8041},{"style":1932},[8042],{"type":40,"value":1962},{"type":31,"tag":1904,"props":8044,"children":8046},{"class":1906,"line":8045},32,[8047,8052,8056,8060,8064,8068,8072,8076,8080],{"type":31,"tag":1904,"props":8048,"children":8049},{"style":2028},[8050],{"type":40,"value":8051},"              params",{"type":31,"tag":1904,"props":8053,"children":8054},{"style":2108},[8055],{"type":40,"value":1951},{"type":31,"tag":1904,"props":8057,"children":8058},{"style":1932},[8059],{"type":40,"value":4625},{"type":31,"tag":1904,"props":8061,"children":8062},{"style":2028},[8063],{"type":40,"value":4630},{"type":31,"tag":1904,"props":8065,"children":8066},{"style":2108},[8067],{"type":40,"value":1951},{"type":31,"tag":1904,"props":8069,"children":8070},{"style":2028},[8071],{"type":40,"value":4368},{"type":31,"tag":1904,"props":8073,"children":8074},{"style":2108},[8075],{"type":40,"value":76},{"type":31,"tag":1904,"props":8077,"children":8078},{"style":2028},[8079],{"type":40,"value":4647},{"type":31,"tag":1904,"props":8081,"children":8082},{"style":1932},[8083],{"type":40,"value":4652},{"type":31,"tag":1904,"props":8085,"children":8087},{"class":1906,"line":8086},33,[8088],{"type":31,"tag":1904,"props":8089,"children":8090},{"style":1932},[8091],{"type":40,"value":8092},"            },\n",{"type":31,"tag":1904,"props":8094,"children":8096},{"class":1906,"line":8095},34,[8097,8102,8107,8111,8115,8119,8124],{"type":31,"tag":1904,"props":8098,"children":8099},{"style":1932},[8100],{"type":40,"value":8101},"            {",{"type":31,"tag":1904,"props":8103,"children":8104},{"style":2028},[8105],{"type":40,"value":8106}," signal",{"type":31,"tag":1904,"props":8108,"children":8109},{"style":2108},[8110],{"type":40,"value":1951},{"type":31,"tag":1904,"props":8112,"children":8113},{"style":2028},[8114],{"type":40,"value":7809},{"type":31,"tag":1904,"props":8116,"children":8117},{"style":2108},[8118],{"type":40,"value":76},{"type":31,"tag":1904,"props":8120,"children":8121},{"style":2028},[8122],{"type":40,"value":8123},"signal ",{"type":31,"tag":1904,"props":8125,"children":8126},{"style":1932},[8127],{"type":40,"value":4652},{"type":31,"tag":1904,"props":8129,"children":8131},{"class":1906,"line":8130},35,[8132,8137],{"type":31,"tag":1904,"props":8133,"children":8134},{"style":2028},[8135],{"type":40,"value":8136},"          )",{"type":31,"tag":1904,"props":8138,"children":8139},{"style":1932},[8140],{"type":40,"value":2047},{"type":31,"tag":1904,"props":8142,"children":8144},{"class":1906,"line":8143},36,[8145,8150,8155,8159,8164,8168,8173,8177],{"type":31,"tag":1904,"props":8146,"children":8147},{"style":1932},[8148],{"type":40,"value":8149},"        }",{"type":31,"tag":1904,"props":8151,"children":8152},{"style":1920},[8153],{"type":40,"value":8154}," catch",{"type":31,"tag":1904,"props":8156,"children":8157},{"style":1932},[8158],{"type":40,"value":3249},{"type":31,"tag":1904,"props":8160,"children":8161},{"style":1942},[8162],{"type":40,"value":8163},"err",{"type":31,"tag":1904,"props":8165,"children":8166},{"style":1948},[8167],{"type":40,"value":1951},{"type":31,"tag":1904,"props":8169,"children":8170},{"style":1954},[8171],{"type":40,"value":8172}," unknown",{"type":31,"tag":1904,"props":8174,"children":8175},{"style":1932},[8176],{"type":40,"value":1992},{"type":31,"tag":1904,"props":8178,"children":8179},{"style":1932},[8180],{"type":40,"value":2005},{"type":31,"tag":1904,"props":8182,"children":8184},{"class":1906,"line":8183},37,[8185,8190,8195],{"type":31,"tag":1904,"props":8186,"children":8187},{"style":1926},[8188],{"type":40,"value":8189},"          clearTimeout",{"type":31,"tag":1904,"props":8191,"children":8192},{"style":2028},[8193],{"type":40,"value":8194},"(timer)",{"type":31,"tag":1904,"props":8196,"children":8197},{"style":1932},[8198],{"type":40,"value":2047},{"type":31,"tag":1904,"props":8200,"children":8202},{"class":1906,"line":8201},38,[8203,8208,8213,8217,8222,8226,8231],{"type":31,"tag":1904,"props":8204,"children":8205},{"style":1920},[8206],{"type":40,"value":8207},"          if",{"type":31,"tag":1904,"props":8209,"children":8210},{"style":2028},[8211],{"type":40,"value":8212}," (controller",{"type":31,"tag":1904,"props":8214,"children":8215},{"style":2108},[8216],{"type":40,"value":76},{"type":31,"tag":1904,"props":8218,"children":8219},{"style":2028},[8220],{"type":40,"value":8221},"signal",{"type":31,"tag":1904,"props":8223,"children":8224},{"style":2108},[8225],{"type":40,"value":76},{"type":31,"tag":1904,"props":8227,"children":8228},{"style":2028},[8229],{"type":40,"value":8230},"aborted) ",{"type":31,"tag":1904,"props":8232,"children":8233},{"style":1932},[8234],{"type":40,"value":3264},{"type":31,"tag":1904,"props":8236,"children":8238},{"class":1906,"line":8237},39,[8239,8244,8248,8253,8257,8261,8265],{"type":31,"tag":1904,"props":8240,"children":8241},{"style":1920},[8242],{"type":40,"value":8243},"            throw",{"type":31,"tag":1904,"props":8245,"children":8246},{"style":2816},[8247],{"type":40,"value":2819},{"type":31,"tag":1904,"props":8249,"children":8250},{"style":1926},[8251],{"type":40,"value":8252}," AbortError",{"type":31,"tag":1904,"props":8254,"children":8255},{"style":2028},[8256],{"type":40,"value":2490},{"type":31,"tag":1904,"props":8258,"children":8259},{"style":3399},[8260],{"type":40,"value":6663},{"type":31,"tag":1904,"props":8262,"children":8263},{"style":2028},[8264],{"type":40,"value":1992},{"type":31,"tag":1904,"props":8266,"children":8267},{"style":1932},[8268],{"type":40,"value":2047},{"type":31,"tag":1904,"props":8270,"children":8272},{"class":1906,"line":8271},40,[8273],{"type":31,"tag":1904,"props":8274,"children":8275},{"style":1932},[8276],{"type":40,"value":8277},"          }\n",{"type":31,"tag":1904,"props":8279,"children":8281},{"class":1906,"line":8280},41,[8282,8287,8291,8295,8300,8304,8308,8312,8317,8321,8325,8329,8333,8338],{"type":31,"tag":1904,"props":8283,"children":8284},{"style":1920},[8285],{"type":40,"value":8286},"          const",{"type":31,"tag":1904,"props":8288,"children":8289},{"style":2017},[8290],{"type":40,"value":5934},{"type":31,"tag":1904,"props":8292,"children":8293},{"style":1948},[8294],{"type":40,"value":2025},{"type":31,"tag":1904,"props":8296,"children":8297},{"style":2028},[8298],{"type":40,"value":8299}," (err ",{"type":31,"tag":1904,"props":8301,"children":8302},{"style":1920},[8303],{"type":40,"value":5915},{"type":31,"tag":1904,"props":8305,"children":8306},{"style":1932},[8307],{"type":40,"value":4625},{"type":31,"tag":1904,"props":8309,"children":8310},{"style":5931},[8311],{"type":40,"value":5934},{"type":31,"tag":1904,"props":8313,"children":8314},{"style":1948},[8315],{"type":40,"value":8316},"?:",{"type":31,"tag":1904,"props":8318,"children":8319},{"style":1954},[8320],{"type":40,"value":1957},{"type":31,"tag":1904,"props":8322,"children":8323},{"style":1932},[8324],{"type":40,"value":6488},{"type":31,"tag":1904,"props":8326,"children":8327},{"style":2028},[8328],{"type":40,"value":1992},{"type":31,"tag":1904,"props":8330,"children":8331},{"style":2108},[8332],{"type":40,"value":76},{"type":31,"tag":1904,"props":8334,"children":8335},{"style":2028},[8336],{"type":40,"value":8337},"statusCode",{"type":31,"tag":1904,"props":8339,"children":8340},{"style":1932},[8341],{"type":40,"value":2047},{"type":31,"tag":1904,"props":8343,"children":8345},{"class":1906,"line":8344},42,[8346,8350,8355,8359,8363,8368,8373,8377,8382,8386,8390,8394,8399],{"type":31,"tag":1904,"props":8347,"children":8348},{"style":1920},[8349],{"type":40,"value":8207},{"type":31,"tag":1904,"props":8351,"children":8352},{"style":2028},[8353],{"type":40,"value":8354}," (statusCode ",{"type":31,"tag":1904,"props":8356,"children":8357},{"style":1948},[8358],{"type":40,"value":5425},{"type":31,"tag":1904,"props":8360,"children":8361},{"style":2039},[8362],{"type":40,"value":5973},{"type":31,"tag":1904,"props":8364,"children":8365},{"style":1948},[8366],{"type":40,"value":8367}," ||",{"type":31,"tag":1904,"props":8369,"children":8370},{"style":2028},[8371],{"type":40,"value":8372}," statusCode ",{"type":31,"tag":1904,"props":8374,"children":8375},{"style":1948},[8376],{"type":40,"value":5425},{"type":31,"tag":1904,"props":8378,"children":8379},{"style":2039},[8380],{"type":40,"value":8381}," 503",{"type":31,"tag":1904,"props":8383,"children":8384},{"style":2028},[8385],{"type":40,"value":2135},{"type":31,"tag":1904,"props":8387,"children":8388},{"style":1920},[8389],{"type":40,"value":4431},{"type":31,"tag":1904,"props":8391,"children":8392},{"style":2028},[8393],{"type":40,"value":5885},{"type":31,"tag":1904,"props":8395,"children":8396},{"style":1932},[8397],{"type":40,"value":8398},";",{"type":31,"tag":1904,"props":8400,"children":8401},{"style":1911},[8402],{"type":40,"value":8403}," // retry\n",{"type":31,"tag":1904,"props":8405,"children":8407},{"class":1906,"line":8406},43,[8408,8413,8417,8421,8426,8430,8434,8438,8442,8447,8451],{"type":31,"tag":1904,"props":8409,"children":8410},{"style":1920},[8411],{"type":40,"value":8412},"          throw",{"type":31,"tag":1904,"props":8414,"children":8415},{"style":2816},[8416],{"type":40,"value":2819},{"type":31,"tag":1904,"props":8418,"children":8419},{"style":1926},[8420],{"type":40,"value":8252},{"type":31,"tag":1904,"props":8422,"children":8423},{"style":2028},[8424],{"type":40,"value":8425},"((err ",{"type":31,"tag":1904,"props":8427,"children":8428},{"style":1920},[8429],{"type":40,"value":5915},{"type":31,"tag":1904,"props":8431,"children":8432},{"style":2470},[8433],{"type":40,"value":4440},{"type":31,"tag":1904,"props":8435,"children":8436},{"style":2028},[8437],{"type":40,"value":1992},{"type":31,"tag":1904,"props":8439,"children":8440},{"style":2108},[8441],{"type":40,"value":76},{"type":31,"tag":1904,"props":8443,"children":8444},{"style":2028},[8445],{"type":40,"value":8446},"message)",{"type":31,"tag":1904,"props":8448,"children":8449},{"style":1932},[8450],{"type":40,"value":8398},{"type":31,"tag":1904,"props":8452,"children":8453},{"style":1911},[8454],{"type":40,"value":8455}," // pas de retry sur les 4xx\n",{"type":31,"tag":1904,"props":8457,"children":8459},{"class":1906,"line":8458},44,[8460],{"type":31,"tag":1904,"props":8461,"children":8462},{"style":1932},[8463],{"type":40,"value":8464},"        }\n",{"type":31,"tag":1904,"props":8466,"children":8468},{"class":1906,"line":8467},45,[8469,8474,8478],{"type":31,"tag":1904,"props":8470,"children":8471},{"style":1926},[8472],{"type":40,"value":8473},"        clearTimeout",{"type":31,"tag":1904,"props":8475,"children":8476},{"style":2028},[8477],{"type":40,"value":8194},{"type":31,"tag":1904,"props":8479,"children":8480},{"style":1932},[8481],{"type":40,"value":2047},{"type":31,"tag":1904,"props":8483,"children":8485},{"class":1906,"line":8484},46,[8486],{"type":31,"tag":1904,"props":8487,"children":8488},{"style":1932},[8489],{"type":40,"value":8490},"      },\n",{"type":31,"tag":1904,"props":8492,"children":8494},{"class":1906,"line":8493},47,[8495],{"type":31,"tag":1904,"props":8496,"children":8497},{"style":1932},[8498],{"type":40,"value":8499},"      {\n",{"type":31,"tag":1904,"props":8501,"children":8503},{"class":1906,"line":8502},48,[8504,8509,8513,8517],{"type":31,"tag":1904,"props":8505,"children":8506},{"style":2028},[8507],{"type":40,"value":8508},"        retries",{"type":31,"tag":1904,"props":8510,"children":8511},{"style":2108},[8512],{"type":40,"value":1951},{"type":31,"tag":1904,"props":8514,"children":8515},{"style":2017},[8516],{"type":40,"value":7387},{"type":31,"tag":1904,"props":8518,"children":8519},{"style":1932},[8520],{"type":40,"value":1962},{"type":31,"tag":1904,"props":8522,"children":8524},{"class":1906,"line":8523},49,[8525,8530,8534,8539],{"type":31,"tag":1904,"props":8526,"children":8527},{"style":2028},[8528],{"type":40,"value":8529},"        factor",{"type":31,"tag":1904,"props":8531,"children":8532},{"style":2108},[8533],{"type":40,"value":1951},{"type":31,"tag":1904,"props":8535,"children":8536},{"style":2039},[8537],{"type":40,"value":8538}," 2",{"type":31,"tag":1904,"props":8540,"children":8541},{"style":1932},[8542],{"type":40,"value":1962},{"type":31,"tag":1904,"props":8544,"children":8546},{"class":1906,"line":8545},50,[8547,8552,8556,8560],{"type":31,"tag":1904,"props":8548,"children":8549},{"style":2028},[8550],{"type":40,"value":8551},"        minTimeout",{"type":31,"tag":1904,"props":8553,"children":8554},{"style":2108},[8555],{"type":40,"value":1951},{"type":31,"tag":1904,"props":8557,"children":8558},{"style":2039},[8559],{"type":40,"value":2130},{"type":31,"tag":1904,"props":8561,"children":8562},{"style":1932},[8563],{"type":40,"value":1962},{"type":31,"tag":1904,"props":8565,"children":8567},{"class":1906,"line":8566},51,[8568,8573,8577,8581,8586,8590,8594],{"type":31,"tag":1904,"props":8569,"children":8570},{"style":1926},[8571],{"type":40,"value":8572},"        onFailedAttempt",{"type":31,"tag":1904,"props":8574,"children":8575},{"style":2108},[8576],{"type":40,"value":1951},{"type":31,"tag":1904,"props":8578,"children":8579},{"style":1932},[8580],{"type":40,"value":3249},{"type":31,"tag":1904,"props":8582,"children":8583},{"style":1942},[8584],{"type":40,"value":8585},"error",{"type":31,"tag":1904,"props":8587,"children":8588},{"style":1932},[8589],{"type":40,"value":1992},{"type":31,"tag":1904,"props":8591,"children":8592},{"style":1948},[8593],{"type":40,"value":4868},{"type":31,"tag":1904,"props":8595,"children":8596},{"style":1932},[8597],{"type":40,"value":2005},{"type":31,"tag":1904,"props":8599,"children":8601},{"class":1906,"line":8600},52,[8602,8606,8611,8615,8620,8624,8628,8632,8636,8641],{"type":31,"tag":1904,"props":8603,"children":8604},{"style":1920},[8605],{"type":40,"value":8207},{"type":31,"tag":1904,"props":8607,"children":8608},{"style":2028},[8609],{"type":40,"value":8610}," (error",{"type":31,"tag":1904,"props":8612,"children":8613},{"style":2108},[8614],{"type":40,"value":76},{"type":31,"tag":1904,"props":8616,"children":8617},{"style":2028},[8618],{"type":40,"value":8619},"retriesLeft ",{"type":31,"tag":1904,"props":8621,"children":8622},{"style":1948},[8623],{"type":40,"value":5425},{"type":31,"tag":1904,"props":8625,"children":8626},{"style":2039},[8627],{"type":40,"value":2701},{"type":31,"tag":1904,"props":8629,"children":8630},{"style":2028},[8631],{"type":40,"value":2135},{"type":31,"tag":1904,"props":8633,"children":8634},{"style":1920},[8635],{"type":40,"value":4431},{"type":31,"tag":1904,"props":8637,"children":8638},{"style":2028},[8639],{"type":40,"value":8640}," error",{"type":31,"tag":1904,"props":8642,"children":8643},{"style":1932},[8644],{"type":40,"value":2047},{"type":31,"tag":1904,"props":8646,"children":8648},{"class":1906,"line":8647},53,[8649],{"type":31,"tag":1904,"props":8650,"children":8651},{"style":1932},[8652],{"type":40,"value":8653},"        },\n",{"type":31,"tag":1904,"props":8655,"children":8657},{"class":1906,"line":8656},54,[8658],{"type":31,"tag":1904,"props":8659,"children":8660},{"style":1932},[8661],{"type":40,"value":8490},{"type":31,"tag":1904,"props":8663,"children":8665},{"class":1906,"line":8664},55,[8666,8671],{"type":31,"tag":1904,"props":8667,"children":8668},{"style":2028},[8669],{"type":40,"value":8670},"    )",{"type":31,"tag":1904,"props":8672,"children":8673},{"style":1932},[8674],{"type":40,"value":2047},{"type":31,"tag":1904,"props":8676,"children":8678},{"class":1906,"line":8677},56,[8679],{"type":31,"tag":1904,"props":8680,"children":8681},{"emptyLinePlaceholder":13},[8682],{"type":40,"value":2165},{"type":31,"tag":1904,"props":8684,"children":8686},{"class":1906,"line":8685},57,[8687,8691,8695,8699,8703,8707,8712,8717,8721,8725,8729,8734],{"type":31,"tag":1904,"props":8688,"children":8689},{"style":1920},[8690],{"type":40,"value":3313},{"type":31,"tag":1904,"props":8692,"children":8693},{"style":3197},[8694],{"type":40,"value":3200},{"type":31,"tag":1904,"props":8696,"children":8697},{"style":2108},[8698],{"type":40,"value":76},{"type":31,"tag":1904,"props":8700,"children":8701},{"style":2028},[8702],{"type":40,"value":4389},{"type":31,"tag":1904,"props":8704,"children":8705},{"style":2108},[8706],{"type":40,"value":76},{"type":31,"tag":1904,"props":8708,"children":8709},{"style":1926},[8710],{"type":40,"value":8711},"markNotified",{"type":31,"tag":1904,"props":8713,"children":8714},{"style":2028},[8715],{"type":40,"value":8716},"(sessionId",{"type":31,"tag":1904,"props":8718,"children":8719},{"style":1932},[8720],{"type":40,"value":4853},{"type":31,"tag":1904,"props":8722,"children":8723},{"style":2816},[8724],{"type":40,"value":2819},{"type":31,"tag":1904,"props":8726,"children":8727},{"style":1926},[8728],{"type":40,"value":5145},{"type":31,"tag":1904,"props":8730,"children":8731},{"style":2028},[8732],{"type":40,"value":8733},"())",{"type":31,"tag":1904,"props":8735,"children":8736},{"style":1932},[8737],{"type":40,"value":2047},{"type":31,"tag":1904,"props":8739,"children":8741},{"class":1906,"line":8740},58,[8742],{"type":31,"tag":1904,"props":8743,"children":8744},{"style":1932},[8745],{"type":40,"value":2717},{"type":31,"tag":1904,"props":8747,"children":8749},{"class":1906,"line":8748},59,[8750],{"type":31,"tag":1904,"props":8751,"children":8752},{"style":1932},[8753],{"type":40,"value":2156},{"type":31,"tag":32,"props":8755,"children":8756},{},[8757,8759,8764,8766,8772],{"type":40,"value":8758},"Quelques lignes de plus en surface. Les 4 modes d'échec couverts. Le wrapper anti-fragile est la combinaison qui rend Claude utilisable en prod. C'est ce que recommande Martin Fowler dans ",{"type":31,"tag":97,"props":8760,"children":8761},{},[8762],{"type":40,"value":8763},"Patterns of Enterprise Application Architecture",{"type":40,"value":8765}," (2002) sur les ",{"type":31,"tag":69,"props":8767,"children":8769},{"href":8768},"/fr/architecture-craft/patterns-resilience-circuit-breaker-retry",[8770],{"type":40,"value":8771},"patterns de résilience type Circuit Breaker et Retry",{"type":40,"value":76},{"type":31,"tag":48,"props":8774,"children":8775},{},[],{"type":31,"tag":52,"props":8777,"children":8779},{"id":8778},"comment-intégrer-ces-tests-sans-ralentir-la-ci",[8780],{"type":40,"value":8781},"Comment intégrer ces tests sans ralentir la CI",{"type":31,"tag":32,"props":8783,"children":8784},{},[8785,8787,8792],{"type":40,"value":8786},"L'objection classique : ",{"type":31,"tag":97,"props":8788,"children":8789},{},[8790],{"type":40,"value":8791},"\"On va mettre 15 minutes de CI au lieu de 4.\"",{"type":40,"value":8793}," Voici comment je structure la pyramide sur crmcoaching pour que ça ne soit pas le cas.",{"type":31,"tag":32,"props":8795,"children":8796},{},[8797,8802,8804,8809],{"type":31,"tag":36,"props":8798,"children":8799},{},[8800],{"type":40,"value":8801},"Etage 1 : tests unitaires Vitest (90% du volume).",{"type":40,"value":8803}," Tournent en moins de 2 minutes. Tous les comportements métier sont couverts ici, en utilisant des fakes en mémoire ou des mocks ",{"type":31,"tag":169,"props":8805,"children":8807},{"className":8806},[],[8808],{"type":40,"value":4709},{"type":40,"value":8810}," au lieu de vraies dépendances. C'est l'etage où les 4 tests \"concurrence, 429, timeout, partial failure\" vivent, mais sur du code instrumenté pour ne pas réellement faire d'I/O réseau vers Brevo.",{"type":31,"tag":32,"props":8812,"children":8813},{},[8814,8819,8821,8827],{"type":31,"tag":36,"props":8815,"children":8816},{},[8817],{"type":40,"value":8818},"Etage 2 : tests d'intégration NestJS (8% du volume).",{"type":40,"value":8820}," Tournent en 3-5 minutes en parallèle. Valident que les adapters (Prisma, client Brevo, jobs Bull) fonctionnent avec leurs vraies implémentations contre des conteneurs Docker (Postgres, Brevo sandbox). On ne re-teste pas la logique métier ici, on teste l'intégration. Tout ce qui touche au piège classique des ",{"type":31,"tag":69,"props":8822,"children":8824},{"href":8823},"/fr/dette-technique/tests-integration-legacy-pieges",[8825],{"type":40,"value":8826},"tests d'intégration sur du code legacy",{"type":40,"value":8828}," est traité dans un article dédié.",{"type":31,"tag":32,"props":8830,"children":8831},{},[8832,8837],{"type":31,"tag":36,"props":8833,"children":8834},{},[8835],{"type":40,"value":8836},"Etage 3 : tests end-to-end (2% du volume).",{"type":40,"value":8838}," Tournent en 5-10 minutes sur un seul scénario critique end-to-end, en pre-prod. C'est l'etage \"ça marche vraiment quand tout est branché, Brevo compris\".",{"type":31,"tag":32,"props":8840,"children":8841},{},[8842,8844,8850],{"type":40,"value":8843},"Avec cette pyramide, ajouter 4 tests de modes d'échec à l'etage 1 coûte 0,5 seconde de plus en CI par module. C'est négligeable. C'est exactement le sujet que je traite quand j'aide une équipe à se rapprocher de la ",{"type":31,"tag":69,"props":8845,"children":8847},{"href":8846},"/fr/dette-technique/definition-of-done-qualite",[8848],{"type":40,"value":8849},"Definition of Done sur la qualité",{"type":40,"value":76},{"type":31,"tag":48,"props":8852,"children":8853},{},[],{"type":31,"tag":52,"props":8855,"children":8856},{"id":1463},[8857],{"type":40,"value":1466},{"type":31,"tag":32,"props":8859,"children":8860},{},[8861],{"type":40,"value":8862},"Depuis que j'ai installé cette discipline sur crmcoaching, les chiffres sur 3 mois sont nets.",{"type":31,"tag":398,"props":8864,"children":8865},{},[8866,8886],{"type":31,"tag":402,"props":8867,"children":8868},{},[8869],{"type":31,"tag":406,"props":8870,"children":8871},{},[8872,8876,8881],{"type":31,"tag":410,"props":8873,"children":8874},{},[8875],{"type":40,"value":1198},{"type":31,"tag":410,"props":8877,"children":8878},{},[8879],{"type":40,"value":8880},"Avant",{"type":31,"tag":410,"props":8882,"children":8883},{},[8884],{"type":40,"value":8885},"Après 3 mois",{"type":31,"tag":426,"props":8887,"children":8888},{},[8889,8907,8925,8943],{"type":31,"tag":406,"props":8890,"children":8891},{},[8892,8897,8902],{"type":31,"tag":433,"props":8893,"children":8894},{},[8895],{"type":40,"value":8896},"Incidents prod liés à un mode d'échec non testé",{"type":31,"tag":433,"props":8898,"children":8899},{},[8900],{"type":40,"value":8901},"3 par trimestre",{"type":31,"tag":433,"props":8903,"children":8904},{},[8905],{"type":40,"value":8906},"0 par trimestre",{"type":31,"tag":406,"props":8908,"children":8909},{},[8910,8915,8920],{"type":31,"tag":433,"props":8911,"children":8912},{},[8913],{"type":40,"value":8914},"MTTR (temps moyen de restauration)",{"type":31,"tag":433,"props":8916,"children":8917},{},[8918],{"type":40,"value":8919},"2h30",{"type":31,"tag":433,"props":8921,"children":8922},{},[8923],{"type":40,"value":8924},"30 minutes",{"type":31,"tag":406,"props":8926,"children":8927},{},[8928,8933,8938],{"type":31,"tag":433,"props":8929,"children":8930},{},[8931],{"type":40,"value":8932},"Confiance pour déployer le vendredi",{"type":31,"tag":433,"props":8934,"children":8935},{},[8936],{"type":40,"value":8937},"\"pas avant lundi\"",{"type":31,"tag":433,"props":8939,"children":8940},{},[8941],{"type":40,"value":8942},"\"sans stress\"",{"type":31,"tag":406,"props":8944,"children":8945},{},[8946,8951,8956],{"type":31,"tag":433,"props":8947,"children":8948},{},[8949],{"type":40,"value":8950},"Heures consacrées au debug post-incident",{"type":31,"tag":433,"props":8952,"children":8953},{},[8954],{"type":40,"value":8955},"12h par trimestre",{"type":31,"tag":433,"props":8957,"children":8958},{},[8959],{"type":40,"value":8960},"2h par trimestre",{"type":31,"tag":32,"props":8962,"children":8963},{},[8964,8966,8971],{"type":40,"value":8965},"Le gain n'est pas que technique. Quand je sais que mes tests couvrent les modes d'échec, je déploie sereinement. Quand je crains mes propres déploiements, je me freine, je retarde les releases, je perds du flux. La métrique sous-jacente, c'est ce que la DORA appelle le ",{"type":31,"tag":97,"props":8967,"children":8968},{},[8969],{"type":40,"value":8970},"Mean Time to Restore",{"type":40,"value":8972},", et c'est l'un des 4 indicateurs de performance d'une équipe engineering.",{"type":31,"tag":48,"props":8974,"children":8975},{},[],{"type":31,"tag":52,"props":8977,"children":8978},{"id":637},[8979],{"type":40,"value":640},{"type":31,"tag":32,"props":8981,"children":8982},{},[8983],{"type":40,"value":8984},"Ce que je veux que vous reteniez de cet article, c'est que les tests Claude couvrent ce que Claude voit. Et Claude ne voit pas la prod. Il ne voit pas la concurrence à 2h du matin sur un weekend. Il ne voit pas le rate limit de Brevo qui change à 30 secondes près. Il ne voit pas le timeout silencieux qui bouche votre queue de jobs. Si vous lui demandez \"écris les tests\", vous obtenez le filet du happy path. Si vous lui demandez \"écris les 4 tests de modes d'échec critiques\", vous obtenez un filet utile.",{"type":31,"tag":32,"props":8986,"children":8987},{},[8988],{"type":40,"value":8989},"Votre rôle de développeur solo ou de senior en 2026 n'est pas de relire des assertions. C'est de nommer explicitement les 4 modes d'échec que Claude doit tester, et d'exiger ces tests dans votre Definition of Done. Si vous tenez cette discipline, vos déploiements du vendredi deviennent calmes. Si vous la lâchez, vous découvrez vos modes d'échec en plein milieu de la nuit, et chaque incident coûte un cran de confiance que vous ne récupérez pas facilement.",{"type":31,"tag":32,"props":8991,"children":8992},{},[8993],{"type":40,"value":8994},"Si en lisant ces lignes vous reconnaissez votre situation, vous avez deux choix. Vous pouvez attendre le prochain crash 429 nocturne. Ou vous pouvez commencer lundi matin, par 4 tests supplémentaires sur la méthode critique de votre choix, et apprendre à dormir tranquille.",{"type":31,"tag":32,"props":8996,"children":8997},{},[8998,9000,9005],{"type":40,"value":8999},"Pour la suite des patterns de tests anti-fragiles, retrouvez-moi sur ",{"type":31,"tag":69,"props":9001,"children":9003},{"href":663,"rel":9002},[665],[9004],{"type":40,"value":668},{"type":40,"value":9006},", où je publie chaque semaine les cas réels rencontrés sur crmcoaching.",{"type":31,"tag":229,"props":9008,"children":9010},{"cta":673,"href":674,"title":9009,"type":676},"Tester les modes d'échec n'est qu'une des 100 pratiques craft",[9011],{"type":31,"tag":32,"props":9012,"children":9013},{},[9014],{"type":40,"value":9015},"Exiger les 4 tests de modes d'échec sur du code généré par Claude, c'est une seule pratique parmi celles qui font la différence en prod. Le Craft Bundle réunit les 100 pratiques que j'applique pour coder propre et résilient, celles que l'IA ne vous apprendra jamais parce qu'elle ne les a jamais vues planter à 2h du matin sous un rate limit Brevo.",{"type":31,"tag":48,"props":9017,"children":9018},{},[],{"type":31,"tag":52,"props":9020,"children":9022},{"id":9021},"faq-sur-les-tests-claude-et-la-résilience-prod",[9023],{"type":40,"value":9024},"FAQ sur les tests Claude et la résilience prod",{"type":31,"tag":693,"props":9026,"children":9027},{},[9028,9033],{"type":31,"tag":697,"props":9029,"children":9030},{},[9031],{"type":40,"value":9032},"1. Faut-il écrire ces 4 tests pour chaque fonction du repo ?",{"type":31,"tag":32,"props":9034,"children":9035},{},[9036],{"type":40,"value":9037},"Non, ce serait disproportionné. La règle que j'applique : ces 4 tests sont obligatoires sur toute fonction qui touche à un service externe (réseau, DB, queue, file system). Sur les fonctions pures (calcul, transformation), un test unitaire classique suffit. Le test de criticité, c'est : \"si cette fonction échoue, est-ce qu'un utilisateur ou un système externe en souffre ?\". Si oui, les 4 tests.",{"type":31,"tag":693,"props":9039,"children":9040},{},[9041,9046],{"type":31,"tag":697,"props":9042,"children":9043},{},[9044],{"type":40,"value":9045},"2. Comment introduire cette discipline sans bloquer les PR existantes ?",{"type":31,"tag":32,"props":9047,"children":9048},{},[9049],{"type":40,"value":9050},"Je recommande deux phases. Phase 1 (3 mois) : tout nouveau code qui touche à un service externe doit avoir les 4 tests. Pas de rétroactif. Phase 2 (6 mois suivants) : on remonte le backlog, en commençant par les 10 fonctions les plus critiques (celles que vous citeriez en post-mortem). C'est la stratégie Boy Scout Rule appliquée aux tests, comme je le décris dans la Boy Scout Rule du développement clean code : améliorer ce qu'on touche, sans tout réécrire d'un coup.",{"type":31,"tag":693,"props":9052,"children":9053},{},[9054,9059],{"type":31,"tag":697,"props":9055,"children":9056},{},[9057],{"type":40,"value":9058},"3. Quelles librairies pour le retry et le timeout en TypeScript ?",{"type":31,"tag":32,"props":9060,"children":9061},{},[9062,9064,9069,9071,9077,9079,9085,9086,9092,9094,9100],{"type":40,"value":9063},"Sur crmcoaching j'utilise ",{"type":31,"tag":169,"props":9065,"children":9067},{"className":9066},[],[9068],{"type":40,"value":712},{"type":40,"value":9070}," (retry exponentiel avec hook ",{"type":31,"tag":169,"props":9072,"children":9074},{"className":9073},[],[9075],{"type":40,"value":9076},"onFailedAttempt",{"type":40,"value":9078},") et ",{"type":31,"tag":169,"props":9080,"children":9082},{"className":9081},[],[9083],{"type":40,"value":9084},"p-timeout",{"type":40,"value":4801},{"type":31,"tag":169,"props":9087,"children":9089},{"className":9088},[],[9090],{"type":40,"value":9091},"AbortSignal",{"type":40,"value":9093}," natif pour le timeout. Les deux sont légères, bien maintenues, et s'intègrent sans friction dans NestJS. Pour le circuit breaker si besoin, ",{"type":31,"tag":169,"props":9095,"children":9097},{"className":9096},[],[9098],{"type":40,"value":9099},"opossum",{"type":40,"value":9101}," est la référence Node.js. Le choix d'outil compte moins que la discipline d'instrumenter : l'important c'est que la stratégie soit explicite et testée, pas qu'elle utilise telle ou telle lib.",{"type":31,"tag":693,"props":9103,"children":9104},{},[9105,9110],{"type":31,"tag":697,"props":9106,"children":9107},{},[9108],{"type":40,"value":9109},"4. Quel rapport entre ces tests et la métrique DORA \"MTTR\" ?",{"type":31,"tag":32,"props":9111,"children":9112},{},[9113],{"type":40,"value":9114},"Direct. Le MTTR (Mean Time to Restore) mesure le temps moyen entre la détection d'un incident et sa résolution. Un incident causé par un mode d'échec testé en CI ne devrait jamais arriver en prod (c'est la prévention). Un incident sur un mode d'échec non testé prend en moyenne 6x plus de temps à diagnostiquer, parce qu'on découvre le comportement en live. Tester en amont = MTTR plus court en aval.",{"type":31,"tag":693,"props":9116,"children":9117},{},[9118,9123],{"type":31,"tag":697,"props":9119,"children":9120},{},[9121],{"type":40,"value":9122},"5. Comment convaincre un investisseur ou un client sceptique sur le ROI de ces tests ?",{"type":31,"tag":32,"props":9124,"children":9125},{},[9126,9128,9132],{"type":40,"value":9127},"Avec deux chiffres. D'abord, le coût d'un incident rate-limit Brevo comme celui que je décris : journée perdue à déboguer, coachees absents à leurs séances, perte de confiance dans le SaaS. Ensuite, le coût de prévention : 4 tests en plus, 1 heure de dev. Le rapport est sans commune mesure. C'est l'angle business que je détaille dans ",{"type":31,"tag":69,"props":9129,"children":9130},{"href":3629},[9131],{"type":40,"value":3632},{"type":40,"value":76},{"type":31,"tag":693,"props":9134,"children":9135},{},[9136,9141],{"type":31,"tag":697,"props":9137,"children":9138},{},[9139],{"type":40,"value":9140},"6. Et si Claude refuse de générer ces tests parce que le code n'est pas \"testable\" ?",{"type":31,"tag":32,"props":9142,"children":9143},{},[9144,9146,9158],{"type":40,"value":9145},"C'est un signal précieux. Si Claude n'arrive pas à écrire un test de concurrence sur votre fonction, c'est probablement que la fonction n'est pas découplée correctement de ses dépendances. C'est l'occasion de re-prompter avec une contrainte d'inversion de dépendance : ",{"type":31,"tag":97,"props":9147,"children":9148},{},[9149,9151,9156],{"type":40,"value":9150},"\"Réécris la classe pour qu'elle injecte ses dépendances via le constructeur NestJS, afin que les 4 tests de modes d'échec deviennent triviaux à écrire avec ",{"type":31,"tag":169,"props":9152,"children":9154},{"className":9153},[],[9155],{"type":40,"value":4709},{"type":40,"value":9157},".\"",{"type":40,"value":9159}," L'architecture s'améliore en sortie, exactement comme le défend la dependency inversion pratique.",{"type":31,"tag":48,"props":9161,"children":9162},{},[],{"type":31,"tag":229,"props":9164,"children":9165},{"cta":806,"href":807,"title":808,"type":809},[9166],{"type":31,"tag":32,"props":9167,"children":9168},{},[9169],{"type":40,"value":9170},"L'EMA est l'outil que je propose au début de chaque mission. Il mesure la maturité de votre équipe sur plusieurs axes engineering : qualité des tests, résilience prod, gouvernance IA, delivery. Quelques minutes pour identifier où votre filet de tests craque sous la concurrence et la latence, et où concentrer vos efforts en priorité.",{"type":31,"tag":4005,"props":9172,"children":9173},{},[9174],{"type":40,"value":4009},{"title":8,"searchDepth":817,"depth":817,"links":9176},[9177,9178,9179,9185,9186,9187,9188,9189],{"id":4059,"depth":817,"text":4062},{"id":4146,"depth":817,"text":4149},{"id":4774,"depth":817,"text":4777,"children":9180},[9181,9182,9183,9184],{"id":4786,"depth":1938,"text":4789},{"id":5558,"depth":1938,"text":5561},{"id":6170,"depth":1938,"text":6173},{"id":6726,"depth":1938,"text":6729},{"id":7234,"depth":817,"text":7237},{"id":8778,"depth":817,"text":8781},{"id":1463,"depth":817,"text":1466},{"id":637,"depth":817,"text":640},{"id":9021,"depth":817,"text":9024},"content:fr:intelligence-artificielle:code-claude-tests-passent-plante-prod.md","fr/intelligence-artificielle/code-claude-tests-passent-plante-prod.md","fr/intelligence-artificielle/code-claude-tests-passent-plante-prod",{"_path":184,"_dir":6,"_draft":7,"_partial":7,"_locale":8,"title":9194,"description":9195,"id":9196,"date":9197,"listed":13,"nocomments":7,"hidden":13,"categories":9198,"tags":9199,"cover":9202,"readingTime":9203,"body":9208,"_type":830,"_id":14957,"_source":832,"_file":14958,"_stem":14959,"_extension":835},"5 anti-patterns que Claude reproduit en silence dans vos codebases","Cinq patterns dangereux que Claude écrit depuis 2 ans dans des milliers de repos. La liste, les exemples, et les contre-patterns craft à appliquer.",63,"2026-05-07",[6],[16,9200,18,9201,19],"anti-patterns","code-review","covers/articles/5-patterns-dangereux-claude.jpg",{"text":9204,"minutes":9205,"time":9206,"words":9207},"15 min read",14.52,871200,2904,{"type":28,"children":9209,"toc":14945},[9210,9218,9223,9226,9232,9244,9249,9261,9285,9288,9294,9299,9304,11244,11293,11305,11308,11314,11327,11339,11874,11925,12419,12424,12427,12433,12453,12918,12923,12935,13532,13545,13550,13553,13559,13564,13847,13860,13881,14313,14331,14334,14340,14377,14389,14409,14422,14425,14431,14436,14595,14600,14603,14612,14615,14619,14624,14738,14748,14751,14755,14760,14765,14770,14781,14784,14793,14796,14802,14815,14835,14878,14891,14917,14930,14933,14941],{"type":31,"tag":32,"props":9211,"children":9212},{},[9213],{"type":31,"tag":36,"props":9214,"children":9215},{},[9216],{"type":40,"value":9217},"En construisant crmcoaching avec Claude (et au fil de mes accompagnements), j'ai vu Claude reproduire les mêmes 5 patterns à chaque nouvelle fonctionnalité. Copiés-collés sans relecture, ils pourrissent la maintenabilité à bas bruit. Aucun ne fait planter la prod tout de suite. Tous coûtent cher à 12 mois.",{"type":31,"tag":32,"props":9219,"children":9220},{},[9221],{"type":40,"value":9222},"Voici les 5 anti-patterns que je vois revenir, pourquoi Claude les écrit, et les contre-patterns craft que j'impose pour les neutraliser. Vous pouvez ouvrir votre repo principal et chercher ces signatures dès lundi matin.",{"type":31,"tag":48,"props":9224,"children":9225},{},[],{"type":31,"tag":52,"props":9227,"children":9229},{"id":9228},"pourquoi-claude-reproduit-certains-patterns-en-silence",[9230],{"type":40,"value":9231},"Pourquoi Claude reproduit certains patterns en silence",{"type":31,"tag":32,"props":9233,"children":9234},{},[9235,9237,9242],{"type":40,"value":9236},"Le constat de base est documenté. Le ",{"type":31,"tag":69,"props":9238,"children":9240},{"href":1793,"rel":9239},[665],[9241],{"type":40,"value":1797},{"type":40,"value":9243}," montre que sur 153 millions de lignes de code analysées, le code \"copié\" (par opposition à refactoré) a augmenté de 8 fois depuis l'arrivée massive des assistants IA dans les workflows de développement. Le code \"moved or refactored\" a baissé de 39%. Les équipes consomment de la suggestion brute et la collent dans leur repo, parfois sans modification.",{"type":31,"tag":32,"props":9245,"children":9246},{},[9247],{"type":40,"value":9248},"Ce n'est pas un problème de modèle, c'est un problème de training data. Claude apprend à partir de milliards de lignes de code public. Sur GitHub, le code public est massivement écrit par des juniors, des bibliothèques en alpha, des exemples de tutoriels, des copier-collers de Stack Overflow. Quand vous promptez Claude pour une God Function, il vous en livre une, parce que c'est la moyenne statistique de ce qu'il a vu. Et cette moyenne, comme je l'analyse dans le retour d'expérience sur la code review IA, est très en dessous du standard craft attendu en production sérieuse.",{"type":31,"tag":78,"props":9250,"children":9251},{},[9252],{"type":31,"tag":32,"props":9253,"children":9254},{},[9255,9259],{"type":31,"tag":36,"props":9256,"children":9257},{},[9258],{"type":40,"value":930},{"type":40,"value":9260}," : au fil du développement du CRM, j'ai mesuré le ratio de fonctions de plus de 60 lignes dans les commits que j'acceptais tels quels versus ceux que je repassais en review avant de les intégrer. Sans grille de review active : 22% des fonctions Claude dépassaient ce seuil. Avec re-prompt explicite et review systématique : 4%. La codebase ne s'effondre pas tout de suite, mais le coût de modification grimpe linéairement avec la longueur moyenne des fonctions. À 6 mois, c'était le sujet n°1 de mes sessions de refactoring.",{"type":31,"tag":32,"props":9262,"children":9263},{},[9264,9266,9270,9272,9277,9279,9283],{"type":40,"value":9265},"Robert C. Martin l'avait écrit dans ",{"type":31,"tag":97,"props":9267,"children":9268},{},[9269],{"type":40,"value":101},{"type":40,"value":9271}," en 2008 : ",{"type":31,"tag":97,"props":9273,"children":9274},{},[9275],{"type":40,"value":9276},"\"The first rule of functions is that they should be small. The second rule of functions is that they should be smaller than that.\"",{"type":40,"value":9278}," Cette règle, exposée en français dans ",{"type":31,"tag":69,"props":9280,"children":9281},{"href":113},[9282],{"type":40,"value":994},{"type":40,"value":9284},", Claude ne l'applique pas par défaut. C'est à vous de la lui imposer par le prompt et la review.",{"type":31,"tag":48,"props":9286,"children":9287},{},[],{"type":31,"tag":52,"props":9289,"children":9291},{"id":9290},"pattern-1-la-god-function",[9292],{"type":40,"value":9293},"Pattern #1 : la God Function",{"type":31,"tag":32,"props":9295,"children":9296},{},[9297],{"type":40,"value":9298},"C'est le pattern le plus visible. Claude livre une fonction de 60 à 120 lignes qui fait tout : validation, transformation, accès DB, logging, envoi d'événement. Tout dans le même bloc, parce que c'est ce qui ressort statistiquement le plus dans le training data.",{"type":31,"tag":32,"props":9300,"children":9301},{},[9302],{"type":40,"value":9303},"Voici un exemple réel que j'ai vu apparaître dans crmcoaching sur la conversion d'un lead en client :",{"type":31,"tag":1894,"props":9305,"children":9307},{"className":1896,"code":9306,"language":1898,"meta":8,"style":8},"// apps/api/src/application/use-cases/convert-lead-to-client.use-case.ts\n// Généré par Claude sans prompt de découpe (tel quel)\n\n@Injectable()\nexport class ConvertLeadToClientUseCase {\n  constructor(\n    private readonly prisma: PrismaClient,\n    private readonly brevoService: BrevoService,\n    private readonly auditService: AuditService,\n    private readonly eventEmitter: EventEmitter2,\n  ) {}\n\n  async execute(leadId: string, coachId: string): Promise\u003CClientDto> {\n    // 1. Validation (15 lignes)\n    if (!leadId) throw new BadRequestException('leadId requis');\n    const lead = await this.prisma.lead.findUnique({ where: { id: leadId } });\n    if (!lead) throw new NotFoundException(`Lead ${leadId} introuvable`);\n    if (lead.coachId !== coachId) throw new ForbiddenException('Lead hors scope');\n    if (lead.status === 'CONVERTED') throw new ConflictException('Lead déjà converti');\n    const existingClient = await this.prisma.client.findFirst({\n      where: { email: lead.email, coachId },\n    });\n    if (existingClient) throw new ConflictException('Client existant avec cet email');\n    // ... 8 autres lignes de validation métier\n\n    // 2. Création du client (15 lignes)\n    const client = await this.prisma.client.create({\n      data: {\n        email: lead.email,\n        firstName: lead.firstName,\n        lastName: lead.lastName,\n        phone: lead.phone,\n        coachId,\n        status: 'ACTIVE',\n        createdBy: coachId,\n        convertedFromLeadId: leadId,\n      },\n    });\n    await this.prisma.lead.update({\n      where: { id: leadId },\n      data: { status: 'CONVERTED', convertedAt: new Date(), convertedToClientId: client.id },\n    });\n\n    // 3. Notification Brevo (12 lignes)\n    await this.brevoService.sendTransactionalEmail({\n      to: [{ email: client.email, name: `${client.firstName} ${client.lastName}` }],\n      templateId: 42,\n      params: { firstName: client.firstName, coachName: lead.coachId },\n    });\n    await this.brevoService.addContactToList(client.email, 'clients-actifs');\n\n    // 4. Audit (6 lignes)\n    await this.auditService.log({\n      action: 'LEAD_CONVERTED',\n      entityType: 'client',\n      entityId: client.id,\n      userId: coachId,\n      meta: { fromLeadId: leadId },\n    });\n\n    // 5. Événement domaine (4 lignes)\n    this.eventEmitter.emit('client.created', { clientId: client.id, coachId });\n\n    return ClientDto.fromPrisma(client);\n  }\n}\n",[9308],{"type":31,"tag":169,"props":9309,"children":9310},{"__ignoreMap":8},[9311,9319,9327,9334,9349,9369,9380,9409,9438,9467,9496,9507,9514,9589,9597,9647,9747,9814,9874,9936,9994,10044,10059,10100,10108,10115,10123,10179,10195,10223,10252,10281,10310,10322,10343,10363,10384,10391,10406,10450,10481,10564,10579,10586,10594,10630,10745,10765,10830,10845,10903,10910,10918,10955,10976,10997,11025,11045,11078,11093,11101,11110,11194,11201,11230,11237],{"type":31,"tag":1904,"props":9312,"children":9313},{"class":1906,"line":1907},[9314],{"type":31,"tag":1904,"props":9315,"children":9316},{"style":1911},[9317],{"type":40,"value":9318},"// apps/api/src/application/use-cases/convert-lead-to-client.use-case.ts\n",{"type":31,"tag":1904,"props":9320,"children":9321},{"class":1906,"line":817},[9322],{"type":31,"tag":1904,"props":9323,"children":9324},{"style":1911},[9325],{"type":40,"value":9326},"// Généré par Claude sans prompt de découpe (tel quel)\n",{"type":31,"tag":1904,"props":9328,"children":9329},{"class":1906,"line":1938},[9330],{"type":31,"tag":1904,"props":9331,"children":9332},{"emptyLinePlaceholder":13},[9333],{"type":40,"value":2165},{"type":31,"tag":1904,"props":9335,"children":9336},{"class":1906,"line":1965},[9337,9341,9345],{"type":31,"tag":1904,"props":9338,"children":9339},{"style":2548},[9340],{"type":40,"value":2551},{"type":31,"tag":1904,"props":9342,"children":9343},{"style":1926},[9344],{"type":40,"value":2556},{"type":31,"tag":1904,"props":9346,"children":9347},{"style":2559},[9348],{"type":40,"value":2562},{"type":31,"tag":1904,"props":9350,"children":9351},{"class":1906,"line":1986},[9352,9356,9360,9365],{"type":31,"tag":1904,"props":9353,"children":9354},{"style":1920},[9355],{"type":40,"value":2462},{"type":31,"tag":1904,"props":9357,"children":9358},{"style":1920},[9359],{"type":40,"value":2574},{"type":31,"tag":1904,"props":9361,"children":9362},{"style":2470},[9363],{"type":40,"value":9364}," ConvertLeadToClientUseCase",{"type":31,"tag":1904,"props":9366,"children":9367},{"style":1932},[9368],{"type":40,"value":2005},{"type":31,"tag":1904,"props":9370,"children":9371},{"class":1906,"line":2008},[9372,9376],{"type":31,"tag":1904,"props":9373,"children":9374},{"style":1920},[9375],{"type":40,"value":2995},{"type":31,"tag":1904,"props":9377,"children":9378},{"style":1932},[9379],{"type":40,"value":1935},{"type":31,"tag":1904,"props":9381,"children":9382},{"class":1906,"line":2050},[9383,9387,9391,9396,9400,9405],{"type":31,"tag":1904,"props":9384,"children":9385},{"style":1920},[9386],{"type":40,"value":3007},{"type":31,"tag":1904,"props":9388,"children":9389},{"style":1920},[9390],{"type":40,"value":3012},{"type":31,"tag":1904,"props":9392,"children":9393},{"style":1942},[9394],{"type":40,"value":9395}," prisma",{"type":31,"tag":1904,"props":9397,"children":9398},{"style":1948},[9399],{"type":40,"value":1951},{"type":31,"tag":1904,"props":9401,"children":9402},{"style":2470},[9403],{"type":40,"value":9404}," PrismaClient",{"type":31,"tag":1904,"props":9406,"children":9407},{"style":1932},[9408],{"type":40,"value":1962},{"type":31,"tag":1904,"props":9410,"children":9411},{"class":1906,"line":2094},[9412,9416,9420,9425,9429,9434],{"type":31,"tag":1904,"props":9413,"children":9414},{"style":1920},[9415],{"type":40,"value":3007},{"type":31,"tag":1904,"props":9417,"children":9418},{"style":1920},[9419],{"type":40,"value":3012},{"type":31,"tag":1904,"props":9421,"children":9422},{"style":1942},[9423],{"type":40,"value":9424}," brevoService",{"type":31,"tag":1904,"props":9426,"children":9427},{"style":1948},[9428],{"type":40,"value":1951},{"type":31,"tag":1904,"props":9430,"children":9431},{"style":2470},[9432],{"type":40,"value":9433}," BrevoService",{"type":31,"tag":1904,"props":9435,"children":9436},{"style":1932},[9437],{"type":40,"value":1962},{"type":31,"tag":1904,"props":9439,"children":9440},{"class":1906,"line":2150},[9441,9445,9449,9454,9458,9463],{"type":31,"tag":1904,"props":9442,"children":9443},{"style":1920},[9444],{"type":40,"value":3007},{"type":31,"tag":1904,"props":9446,"children":9447},{"style":1920},[9448],{"type":40,"value":3012},{"type":31,"tag":1904,"props":9450,"children":9451},{"style":1942},[9452],{"type":40,"value":9453}," auditService",{"type":31,"tag":1904,"props":9455,"children":9456},{"style":1948},[9457],{"type":40,"value":1951},{"type":31,"tag":1904,"props":9459,"children":9460},{"style":2470},[9461],{"type":40,"value":9462}," AuditService",{"type":31,"tag":1904,"props":9464,"children":9465},{"style":1932},[9466],{"type":40,"value":1962},{"type":31,"tag":1904,"props":9468,"children":9469},{"class":1906,"line":2159},[9470,9474,9478,9483,9487,9492],{"type":31,"tag":1904,"props":9471,"children":9472},{"style":1920},[9473],{"type":40,"value":3007},{"type":31,"tag":1904,"props":9475,"children":9476},{"style":1920},[9477],{"type":40,"value":3012},{"type":31,"tag":1904,"props":9479,"children":9480},{"style":1942},[9481],{"type":40,"value":9482}," eventEmitter",{"type":31,"tag":1904,"props":9484,"children":9485},{"style":1948},[9486],{"type":40,"value":1951},{"type":31,"tag":1904,"props":9488,"children":9489},{"style":2470},[9490],{"type":40,"value":9491}," EventEmitter2",{"type":31,"tag":1904,"props":9493,"children":9494},{"style":1932},[9495],{"type":40,"value":1962},{"type":31,"tag":1904,"props":9497,"children":9498},{"class":1906,"line":2168},[9499,9503],{"type":31,"tag":1904,"props":9500,"children":9501},{"style":1932},[9502],{"type":40,"value":3096},{"type":31,"tag":1904,"props":9504,"children":9505},{"style":1932},[9506],{"type":40,"value":3101},{"type":31,"tag":1904,"props":9508,"children":9509},{"class":1906,"line":2177},[9510],{"type":31,"tag":1904,"props":9511,"children":9512},{"emptyLinePlaceholder":13},[9513],{"type":40,"value":2165},{"type":31,"tag":1904,"props":9515,"children":9516},{"class":1906,"line":2194},[9517,9521,9526,9530,9535,9539,9543,9547,9552,9556,9560,9564,9568,9572,9576,9581,9585],{"type":31,"tag":1904,"props":9518,"children":9519},{"style":1920},[9520],{"type":40,"value":3116},{"type":31,"tag":1904,"props":9522,"children":9523},{"style":1926},[9524],{"type":40,"value":9525}," execute",{"type":31,"tag":1904,"props":9527,"children":9528},{"style":1932},[9529],{"type":40,"value":2490},{"type":31,"tag":1904,"props":9531,"children":9532},{"style":1942},[9533],{"type":40,"value":9534},"leadId",{"type":31,"tag":1904,"props":9536,"children":9537},{"style":1948},[9538],{"type":40,"value":1951},{"type":31,"tag":1904,"props":9540,"children":9541},{"style":1954},[9542],{"type":40,"value":2790},{"type":31,"tag":1904,"props":9544,"children":9545},{"style":1932},[9546],{"type":40,"value":4853},{"type":31,"tag":1904,"props":9548,"children":9549},{"style":1942},[9550],{"type":40,"value":9551}," coachId",{"type":31,"tag":1904,"props":9553,"children":9554},{"style":1948},[9555],{"type":40,"value":1951},{"type":31,"tag":1904,"props":9557,"children":9558},{"style":1954},[9559],{"type":40,"value":2790},{"type":31,"tag":1904,"props":9561,"children":9562},{"style":1932},[9563],{"type":40,"value":1992},{"type":31,"tag":1904,"props":9565,"children":9566},{"style":1948},[9567],{"type":40,"value":1951},{"type":31,"tag":1904,"props":9569,"children":9570},{"style":2470},[9571],{"type":40,"value":3152},{"type":31,"tag":1904,"props":9573,"children":9574},{"style":3155},[9575],{"type":40,"value":3158},{"type":31,"tag":1904,"props":9577,"children":9578},{"style":2470},[9579],{"type":40,"value":9580},"ClientDto",{"type":31,"tag":1904,"props":9582,"children":9583},{"style":3155},[9584],{"type":40,"value":3168},{"type":31,"tag":1904,"props":9586,"children":9587},{"style":1932},[9588],{"type":40,"value":2005},{"type":31,"tag":1904,"props":9590,"children":9591},{"class":1906,"line":2215},[9592],{"type":31,"tag":1904,"props":9593,"children":9594},{"style":1911},[9595],{"type":40,"value":9596},"    // 1. Validation (15 lignes)\n",{"type":31,"tag":1904,"props":9598,"children":9599},{"class":1906,"line":2236},[9600,9604,9608,9612,9617,9621,9625,9630,9634,9639,9643],{"type":31,"tag":1904,"props":9601,"children":9602},{"style":1920},[9603],{"type":40,"value":3244},{"type":31,"tag":1904,"props":9605,"children":9606},{"style":2028},[9607],{"type":40,"value":3249},{"type":31,"tag":1904,"props":9609,"children":9610},{"style":1948},[9611],{"type":40,"value":3254},{"type":31,"tag":1904,"props":9613,"children":9614},{"style":2028},[9615],{"type":40,"value":9616},"leadId) ",{"type":31,"tag":1904,"props":9618,"children":9619},{"style":1920},[9620],{"type":40,"value":4431},{"type":31,"tag":1904,"props":9622,"children":9623},{"style":2816},[9624],{"type":40,"value":2819},{"type":31,"tag":1904,"props":9626,"children":9627},{"style":1926},[9628],{"type":40,"value":9629}," BadRequestException",{"type":31,"tag":1904,"props":9631,"children":9632},{"style":2028},[9633],{"type":40,"value":2490},{"type":31,"tag":1904,"props":9635,"children":9636},{"style":3399},[9637],{"type":40,"value":9638},"'leadId requis'",{"type":31,"tag":1904,"props":9640,"children":9641},{"style":2028},[9642],{"type":40,"value":1992},{"type":31,"tag":1904,"props":9644,"children":9645},{"style":1932},[9646],{"type":40,"value":2047},{"type":31,"tag":1904,"props":9648,"children":9649},{"class":1906,"line":2256},[9650,9654,9658,9662,9666,9670,9674,9679,9683,9687,9691,9696,9700,9704,9709,9713,9717,9722,9726,9731,9735,9739,9743],{"type":31,"tag":1904,"props":9651,"children":9652},{"style":1920},[9653],{"type":40,"value":3180},{"type":31,"tag":1904,"props":9655,"children":9656},{"style":2017},[9657],{"type":40,"value":2644},{"type":31,"tag":1904,"props":9659,"children":9660},{"style":1948},[9661],{"type":40,"value":2025},{"type":31,"tag":1904,"props":9663,"children":9664},{"style":1920},[9665],{"type":40,"value":3194},{"type":31,"tag":1904,"props":9667,"children":9668},{"style":3197},[9669],{"type":40,"value":3200},{"type":31,"tag":1904,"props":9671,"children":9672},{"style":2108},[9673],{"type":40,"value":76},{"type":31,"tag":1904,"props":9675,"children":9676},{"style":2028},[9677],{"type":40,"value":9678},"prisma",{"type":31,"tag":1904,"props":9680,"children":9681},{"style":2108},[9682],{"type":40,"value":76},{"type":31,"tag":1904,"props":9684,"children":9685},{"style":2028},[9686],{"type":40,"value":2495},{"type":31,"tag":1904,"props":9688,"children":9689},{"style":2108},[9690],{"type":40,"value":76},{"type":31,"tag":1904,"props":9692,"children":9693},{"style":1926},[9694],{"type":40,"value":9695},"findUnique",{"type":31,"tag":1904,"props":9697,"children":9698},{"style":2028},[9699],{"type":40,"value":2490},{"type":31,"tag":1904,"props":9701,"children":9702},{"style":1932},[9703],{"type":40,"value":4543},{"type":31,"tag":1904,"props":9705,"children":9706},{"style":2028},[9707],{"type":40,"value":9708}," where",{"type":31,"tag":1904,"props":9710,"children":9711},{"style":2108},[9712],{"type":40,"value":1951},{"type":31,"tag":1904,"props":9714,"children":9715},{"style":1932},[9716],{"type":40,"value":4625},{"type":31,"tag":1904,"props":9718,"children":9719},{"style":2028},[9720],{"type":40,"value":9721}," id",{"type":31,"tag":1904,"props":9723,"children":9724},{"style":2108},[9725],{"type":40,"value":1951},{"type":31,"tag":1904,"props":9727,"children":9728},{"style":2028},[9729],{"type":40,"value":9730}," leadId ",{"type":31,"tag":1904,"props":9732,"children":9733},{"style":1932},[9734],{"type":40,"value":4464},{"type":31,"tag":1904,"props":9736,"children":9737},{"style":1932},[9738],{"type":40,"value":6488},{"type":31,"tag":1904,"props":9740,"children":9741},{"style":2028},[9742],{"type":40,"value":1992},{"type":31,"tag":1904,"props":9744,"children":9745},{"style":1932},[9746],{"type":40,"value":2047},{"type":31,"tag":1904,"props":9748,"children":9749},{"class":1906,"line":2290},[9750,9754,9758,9762,9767,9771,9775,9780,9784,9789,9793,9797,9801,9806,9810],{"type":31,"tag":1904,"props":9751,"children":9752},{"style":1920},[9753],{"type":40,"value":3244},{"type":31,"tag":1904,"props":9755,"children":9756},{"style":2028},[9757],{"type":40,"value":3249},{"type":31,"tag":1904,"props":9759,"children":9760},{"style":1948},[9761],{"type":40,"value":3254},{"type":31,"tag":1904,"props":9763,"children":9764},{"style":2028},[9765],{"type":40,"value":9766},"lead) ",{"type":31,"tag":1904,"props":9768,"children":9769},{"style":1920},[9770],{"type":40,"value":4431},{"type":31,"tag":1904,"props":9772,"children":9773},{"style":2816},[9774],{"type":40,"value":2819},{"type":31,"tag":1904,"props":9776,"children":9777},{"style":1926},[9778],{"type":40,"value":9779}," NotFoundException",{"type":31,"tag":1904,"props":9781,"children":9782},{"style":2028},[9783],{"type":40,"value":2490},{"type":31,"tag":1904,"props":9785,"children":9786},{"style":3399},[9787],{"type":40,"value":9788},"`Lead ",{"type":31,"tag":1904,"props":9790,"children":9791},{"style":4452},[9792],{"type":40,"value":4455},{"type":31,"tag":1904,"props":9794,"children":9795},{"style":2028},[9796],{"type":40,"value":9534},{"type":31,"tag":1904,"props":9798,"children":9799},{"style":4452},[9800],{"type":40,"value":4464},{"type":31,"tag":1904,"props":9802,"children":9803},{"style":3399},[9804],{"type":40,"value":9805}," introuvable`",{"type":31,"tag":1904,"props":9807,"children":9808},{"style":2028},[9809],{"type":40,"value":1992},{"type":31,"tag":1904,"props":9811,"children":9812},{"style":1932},[9813],{"type":40,"value":2047},{"type":31,"tag":1904,"props":9815,"children":9816},{"class":1906,"line":2333},[9817,9821,9825,9829,9834,9839,9844,9848,9852,9857,9861,9866,9870],{"type":31,"tag":1904,"props":9818,"children":9819},{"style":1920},[9820],{"type":40,"value":3244},{"type":31,"tag":1904,"props":9822,"children":9823},{"style":2028},[9824],{"type":40,"value":2672},{"type":31,"tag":1904,"props":9826,"children":9827},{"style":2108},[9828],{"type":40,"value":76},{"type":31,"tag":1904,"props":9830,"children":9831},{"style":2028},[9832],{"type":40,"value":9833},"coachId ",{"type":31,"tag":1904,"props":9835,"children":9836},{"style":1948},[9837],{"type":40,"value":9838},"!==",{"type":31,"tag":1904,"props":9840,"children":9841},{"style":2028},[9842],{"type":40,"value":9843}," coachId) ",{"type":31,"tag":1904,"props":9845,"children":9846},{"style":1920},[9847],{"type":40,"value":4431},{"type":31,"tag":1904,"props":9849,"children":9850},{"style":2816},[9851],{"type":40,"value":2819},{"type":31,"tag":1904,"props":9853,"children":9854},{"style":1926},[9855],{"type":40,"value":9856}," ForbiddenException",{"type":31,"tag":1904,"props":9858,"children":9859},{"style":2028},[9860],{"type":40,"value":2490},{"type":31,"tag":1904,"props":9862,"children":9863},{"style":3399},[9864],{"type":40,"value":9865},"'Lead hors scope'",{"type":31,"tag":1904,"props":9867,"children":9868},{"style":2028},[9869],{"type":40,"value":1992},{"type":31,"tag":1904,"props":9871,"children":9872},{"style":1932},[9873],{"type":40,"value":2047},{"type":31,"tag":1904,"props":9875,"children":9876},{"class":1906,"line":2382},[9877,9881,9885,9889,9893,9897,9902,9906,9910,9914,9919,9923,9928,9932],{"type":31,"tag":1904,"props":9878,"children":9879},{"style":1920},[9880],{"type":40,"value":3244},{"type":31,"tag":1904,"props":9882,"children":9883},{"style":2028},[9884],{"type":40,"value":2672},{"type":31,"tag":1904,"props":9886,"children":9887},{"style":2108},[9888],{"type":40,"value":76},{"type":31,"tag":1904,"props":9890,"children":9891},{"style":2028},[9892],{"type":40,"value":5420},{"type":31,"tag":1904,"props":9894,"children":9895},{"style":1948},[9896],{"type":40,"value":5425},{"type":31,"tag":1904,"props":9898,"children":9899},{"style":3399},[9900],{"type":40,"value":9901}," 'CONVERTED'",{"type":31,"tag":1904,"props":9903,"children":9904},{"style":2028},[9905],{"type":40,"value":2135},{"type":31,"tag":1904,"props":9907,"children":9908},{"style":1920},[9909],{"type":40,"value":4431},{"type":31,"tag":1904,"props":9911,"children":9912},{"style":2816},[9913],{"type":40,"value":2819},{"type":31,"tag":1904,"props":9915,"children":9916},{"style":1926},[9917],{"type":40,"value":9918}," ConflictException",{"type":31,"tag":1904,"props":9920,"children":9921},{"style":2028},[9922],{"type":40,"value":2490},{"type":31,"tag":1904,"props":9924,"children":9925},{"style":3399},[9926],{"type":40,"value":9927},"'Lead déjà converti'",{"type":31,"tag":1904,"props":9929,"children":9930},{"style":2028},[9931],{"type":40,"value":1992},{"type":31,"tag":1904,"props":9933,"children":9934},{"style":1932},[9935],{"type":40,"value":2047},{"type":31,"tag":1904,"props":9937,"children":9938},{"class":1906,"line":4678},[9939,9943,9948,9952,9956,9960,9964,9968,9972,9977,9981,9986,9990],{"type":31,"tag":1904,"props":9940,"children":9941},{"style":1920},[9942],{"type":40,"value":3180},{"type":31,"tag":1904,"props":9944,"children":9945},{"style":2017},[9946],{"type":40,"value":9947}," existingClient",{"type":31,"tag":1904,"props":9949,"children":9950},{"style":1948},[9951],{"type":40,"value":2025},{"type":31,"tag":1904,"props":9953,"children":9954},{"style":1920},[9955],{"type":40,"value":3194},{"type":31,"tag":1904,"props":9957,"children":9958},{"style":3197},[9959],{"type":40,"value":3200},{"type":31,"tag":1904,"props":9961,"children":9962},{"style":2108},[9963],{"type":40,"value":76},{"type":31,"tag":1904,"props":9965,"children":9966},{"style":2028},[9967],{"type":40,"value":9678},{"type":31,"tag":1904,"props":9969,"children":9970},{"style":2108},[9971],{"type":40,"value":76},{"type":31,"tag":1904,"props":9973,"children":9974},{"style":2028},[9975],{"type":40,"value":9976},"client",{"type":31,"tag":1904,"props":9978,"children":9979},{"style":2108},[9980],{"type":40,"value":76},{"type":31,"tag":1904,"props":9982,"children":9983},{"style":1926},[9984],{"type":40,"value":9985},"findFirst",{"type":31,"tag":1904,"props":9987,"children":9988},{"style":2028},[9989],{"type":40,"value":2490},{"type":31,"tag":1904,"props":9991,"children":9992},{"style":1932},[9993],{"type":40,"value":3264},{"type":31,"tag":1904,"props":9995,"children":9996},{"class":1906,"line":5525},[9997,10002,10006,10010,10014,10018,10022,10026,10031,10035,10040],{"type":31,"tag":1904,"props":9998,"children":9999},{"style":2028},[10000],{"type":40,"value":10001},"      where",{"type":31,"tag":1904,"props":10003,"children":10004},{"style":2108},[10005],{"type":40,"value":1951},{"type":31,"tag":1904,"props":10007,"children":10008},{"style":1932},[10009],{"type":40,"value":4625},{"type":31,"tag":1904,"props":10011,"children":10012},{"style":2028},[10013],{"type":40,"value":4548},{"type":31,"tag":1904,"props":10015,"children":10016},{"style":2108},[10017],{"type":40,"value":1951},{"type":31,"tag":1904,"props":10019,"children":10020},{"style":2028},[10021],{"type":40,"value":2644},{"type":31,"tag":1904,"props":10023,"children":10024},{"style":2108},[10025],{"type":40,"value":76},{"type":31,"tag":1904,"props":10027,"children":10028},{"style":2028},[10029],{"type":40,"value":10030},"email",{"type":31,"tag":1904,"props":10032,"children":10033},{"style":1932},[10034],{"type":40,"value":4853},{"type":31,"tag":1904,"props":10036,"children":10037},{"style":2028},[10038],{"type":40,"value":10039}," coachId ",{"type":31,"tag":1904,"props":10041,"children":10042},{"style":1932},[10043],{"type":40,"value":4652},{"type":31,"tag":1904,"props":10045,"children":10046},{"class":1906,"line":6149},[10047,10051,10055],{"type":31,"tag":1904,"props":10048,"children":10049},{"style":1932},[10050],{"type":40,"value":4660},{"type":31,"tag":1904,"props":10052,"children":10053},{"style":2028},[10054],{"type":40,"value":1992},{"type":31,"tag":1904,"props":10056,"children":10057},{"style":1932},[10058],{"type":40,"value":2047},{"type":31,"tag":1904,"props":10060,"children":10061},{"class":1906,"line":6705},[10062,10066,10071,10075,10079,10083,10087,10092,10096],{"type":31,"tag":1904,"props":10063,"children":10064},{"style":1920},[10065],{"type":40,"value":3244},{"type":31,"tag":1904,"props":10067,"children":10068},{"style":2028},[10069],{"type":40,"value":10070}," (existingClient) ",{"type":31,"tag":1904,"props":10072,"children":10073},{"style":1920},[10074],{"type":40,"value":4431},{"type":31,"tag":1904,"props":10076,"children":10077},{"style":2816},[10078],{"type":40,"value":2819},{"type":31,"tag":1904,"props":10080,"children":10081},{"style":1926},[10082],{"type":40,"value":9918},{"type":31,"tag":1904,"props":10084,"children":10085},{"style":2028},[10086],{"type":40,"value":2490},{"type":31,"tag":1904,"props":10088,"children":10089},{"style":3399},[10090],{"type":40,"value":10091},"'Client existant avec cet email'",{"type":31,"tag":1904,"props":10093,"children":10094},{"style":2028},[10095],{"type":40,"value":1992},{"type":31,"tag":1904,"props":10097,"children":10098},{"style":1932},[10099],{"type":40,"value":2047},{"type":31,"tag":1904,"props":10101,"children":10102},{"class":1906,"line":7798},[10103],{"type":31,"tag":1904,"props":10104,"children":10105},{"style":1911},[10106],{"type":40,"value":10107},"    // ... 8 autres lignes de validation métier\n",{"type":31,"tag":1904,"props":10109,"children":10110},{"class":1906,"line":7833},[10111],{"type":31,"tag":1904,"props":10112,"children":10113},{"emptyLinePlaceholder":13},[10114],{"type":40,"value":2165},{"type":31,"tag":1904,"props":10116,"children":10117},{"class":1906,"line":7900},[10118],{"type":31,"tag":1904,"props":10119,"children":10120},{"style":1911},[10121],{"type":40,"value":10122},"    // 2. Création du client (15 lignes)\n",{"type":31,"tag":1904,"props":10124,"children":10125},{"class":1906,"line":7908},[10126,10130,10134,10138,10142,10146,10150,10154,10158,10162,10166,10171,10175],{"type":31,"tag":1904,"props":10127,"children":10128},{"style":1920},[10129],{"type":40,"value":3180},{"type":31,"tag":1904,"props":10131,"children":10132},{"style":2017},[10133],{"type":40,"value":3185},{"type":31,"tag":1904,"props":10135,"children":10136},{"style":1948},[10137],{"type":40,"value":2025},{"type":31,"tag":1904,"props":10139,"children":10140},{"style":1920},[10141],{"type":40,"value":3194},{"type":31,"tag":1904,"props":10143,"children":10144},{"style":3197},[10145],{"type":40,"value":3200},{"type":31,"tag":1904,"props":10147,"children":10148},{"style":2108},[10149],{"type":40,"value":76},{"type":31,"tag":1904,"props":10151,"children":10152},{"style":2028},[10153],{"type":40,"value":9678},{"type":31,"tag":1904,"props":10155,"children":10156},{"style":2108},[10157],{"type":40,"value":76},{"type":31,"tag":1904,"props":10159,"children":10160},{"style":2028},[10161],{"type":40,"value":9976},{"type":31,"tag":1904,"props":10163,"children":10164},{"style":2108},[10165],{"type":40,"value":76},{"type":31,"tag":1904,"props":10167,"children":10168},{"style":1926},[10169],{"type":40,"value":10170},"create",{"type":31,"tag":1904,"props":10172,"children":10173},{"style":2028},[10174],{"type":40,"value":2490},{"type":31,"tag":1904,"props":10176,"children":10177},{"style":1932},[10178],{"type":40,"value":3264},{"type":31,"tag":1904,"props":10180,"children":10181},{"class":1906,"line":7921},[10182,10187,10191],{"type":31,"tag":1904,"props":10183,"children":10184},{"style":2028},[10185],{"type":40,"value":10186},"      data",{"type":31,"tag":1904,"props":10188,"children":10189},{"style":2108},[10190],{"type":40,"value":1951},{"type":31,"tag":1904,"props":10192,"children":10193},{"style":1932},[10194],{"type":40,"value":2005},{"type":31,"tag":1904,"props":10196,"children":10197},{"class":1906,"line":7954},[10198,10203,10207,10211,10215,10219],{"type":31,"tag":1904,"props":10199,"children":10200},{"style":2028},[10201],{"type":40,"value":10202},"        email",{"type":31,"tag":1904,"props":10204,"children":10205},{"style":2108},[10206],{"type":40,"value":1951},{"type":31,"tag":1904,"props":10208,"children":10209},{"style":2028},[10210],{"type":40,"value":2644},{"type":31,"tag":1904,"props":10212,"children":10213},{"style":2108},[10214],{"type":40,"value":76},{"type":31,"tag":1904,"props":10216,"children":10217},{"style":2028},[10218],{"type":40,"value":10030},{"type":31,"tag":1904,"props":10220,"children":10221},{"style":1932},[10222],{"type":40,"value":1962},{"type":31,"tag":1904,"props":10224,"children":10225},{"class":1906,"line":7963},[10226,10231,10235,10239,10243,10248],{"type":31,"tag":1904,"props":10227,"children":10228},{"style":2028},[10229],{"type":40,"value":10230},"        firstName",{"type":31,"tag":1904,"props":10232,"children":10233},{"style":2108},[10234],{"type":40,"value":1951},{"type":31,"tag":1904,"props":10236,"children":10237},{"style":2028},[10238],{"type":40,"value":2644},{"type":31,"tag":1904,"props":10240,"children":10241},{"style":2108},[10242],{"type":40,"value":76},{"type":31,"tag":1904,"props":10244,"children":10245},{"style":2028},[10246],{"type":40,"value":10247},"firstName",{"type":31,"tag":1904,"props":10249,"children":10250},{"style":1932},[10251],{"type":40,"value":1962},{"type":31,"tag":1904,"props":10253,"children":10254},{"class":1906,"line":8016},[10255,10260,10264,10268,10272,10277],{"type":31,"tag":1904,"props":10256,"children":10257},{"style":2028},[10258],{"type":40,"value":10259},"        lastName",{"type":31,"tag":1904,"props":10261,"children":10262},{"style":2108},[10263],{"type":40,"value":1951},{"type":31,"tag":1904,"props":10265,"children":10266},{"style":2028},[10267],{"type":40,"value":2644},{"type":31,"tag":1904,"props":10269,"children":10270},{"style":2108},[10271],{"type":40,"value":76},{"type":31,"tag":1904,"props":10273,"children":10274},{"style":2028},[10275],{"type":40,"value":10276},"lastName",{"type":31,"tag":1904,"props":10278,"children":10279},{"style":1932},[10280],{"type":40,"value":1962},{"type":31,"tag":1904,"props":10282,"children":10283},{"class":1906,"line":8045},[10284,10289,10293,10297,10301,10306],{"type":31,"tag":1904,"props":10285,"children":10286},{"style":2028},[10287],{"type":40,"value":10288},"        phone",{"type":31,"tag":1904,"props":10290,"children":10291},{"style":2108},[10292],{"type":40,"value":1951},{"type":31,"tag":1904,"props":10294,"children":10295},{"style":2028},[10296],{"type":40,"value":2644},{"type":31,"tag":1904,"props":10298,"children":10299},{"style":2108},[10300],{"type":40,"value":76},{"type":31,"tag":1904,"props":10302,"children":10303},{"style":2028},[10304],{"type":40,"value":10305},"phone",{"type":31,"tag":1904,"props":10307,"children":10308},{"style":1932},[10309],{"type":40,"value":1962},{"type":31,"tag":1904,"props":10311,"children":10312},{"class":1906,"line":8086},[10313,10318],{"type":31,"tag":1904,"props":10314,"children":10315},{"style":2028},[10316],{"type":40,"value":10317},"        coachId",{"type":31,"tag":1904,"props":10319,"children":10320},{"style":1932},[10321],{"type":40,"value":1962},{"type":31,"tag":1904,"props":10323,"children":10324},{"class":1906,"line":8095},[10325,10330,10334,10339],{"type":31,"tag":1904,"props":10326,"children":10327},{"style":2028},[10328],{"type":40,"value":10329},"        status",{"type":31,"tag":1904,"props":10331,"children":10332},{"style":2108},[10333],{"type":40,"value":1951},{"type":31,"tag":1904,"props":10335,"children":10336},{"style":3399},[10337],{"type":40,"value":10338}," 'ACTIVE'",{"type":31,"tag":1904,"props":10340,"children":10341},{"style":1932},[10342],{"type":40,"value":1962},{"type":31,"tag":1904,"props":10344,"children":10345},{"class":1906,"line":8130},[10346,10351,10355,10359],{"type":31,"tag":1904,"props":10347,"children":10348},{"style":2028},[10349],{"type":40,"value":10350},"        createdBy",{"type":31,"tag":1904,"props":10352,"children":10353},{"style":2108},[10354],{"type":40,"value":1951},{"type":31,"tag":1904,"props":10356,"children":10357},{"style":2028},[10358],{"type":40,"value":9551},{"type":31,"tag":1904,"props":10360,"children":10361},{"style":1932},[10362],{"type":40,"value":1962},{"type":31,"tag":1904,"props":10364,"children":10365},{"class":1906,"line":8143},[10366,10371,10375,10380],{"type":31,"tag":1904,"props":10367,"children":10368},{"style":2028},[10369],{"type":40,"value":10370},"        convertedFromLeadId",{"type":31,"tag":1904,"props":10372,"children":10373},{"style":2108},[10374],{"type":40,"value":1951},{"type":31,"tag":1904,"props":10376,"children":10377},{"style":2028},[10378],{"type":40,"value":10379}," leadId",{"type":31,"tag":1904,"props":10381,"children":10382},{"style":1932},[10383],{"type":40,"value":1962},{"type":31,"tag":1904,"props":10385,"children":10386},{"class":1906,"line":8183},[10387],{"type":31,"tag":1904,"props":10388,"children":10389},{"style":1932},[10390],{"type":40,"value":8490},{"type":31,"tag":1904,"props":10392,"children":10393},{"class":1906,"line":8201},[10394,10398,10402],{"type":31,"tag":1904,"props":10395,"children":10396},{"style":1932},[10397],{"type":40,"value":4660},{"type":31,"tag":1904,"props":10399,"children":10400},{"style":2028},[10401],{"type":40,"value":1992},{"type":31,"tag":1904,"props":10403,"children":10404},{"style":1932},[10405],{"type":40,"value":2047},{"type":31,"tag":1904,"props":10407,"children":10408},{"class":1906,"line":8237},[10409,10413,10417,10421,10425,10429,10433,10437,10442,10446],{"type":31,"tag":1904,"props":10410,"children":10411},{"style":1920},[10412],{"type":40,"value":3313},{"type":31,"tag":1904,"props":10414,"children":10415},{"style":3197},[10416],{"type":40,"value":3200},{"type":31,"tag":1904,"props":10418,"children":10419},{"style":2108},[10420],{"type":40,"value":76},{"type":31,"tag":1904,"props":10422,"children":10423},{"style":2028},[10424],{"type":40,"value":9678},{"type":31,"tag":1904,"props":10426,"children":10427},{"style":2108},[10428],{"type":40,"value":76},{"type":31,"tag":1904,"props":10430,"children":10431},{"style":2028},[10432],{"type":40,"value":2495},{"type":31,"tag":1904,"props":10434,"children":10435},{"style":2108},[10436],{"type":40,"value":76},{"type":31,"tag":1904,"props":10438,"children":10439},{"style":1926},[10440],{"type":40,"value":10441},"update",{"type":31,"tag":1904,"props":10443,"children":10444},{"style":2028},[10445],{"type":40,"value":2490},{"type":31,"tag":1904,"props":10447,"children":10448},{"style":1932},[10449],{"type":40,"value":3264},{"type":31,"tag":1904,"props":10451,"children":10452},{"class":1906,"line":8271},[10453,10457,10461,10465,10469,10473,10477],{"type":31,"tag":1904,"props":10454,"children":10455},{"style":2028},[10456],{"type":40,"value":10001},{"type":31,"tag":1904,"props":10458,"children":10459},{"style":2108},[10460],{"type":40,"value":1951},{"type":31,"tag":1904,"props":10462,"children":10463},{"style":1932},[10464],{"type":40,"value":4625},{"type":31,"tag":1904,"props":10466,"children":10467},{"style":2028},[10468],{"type":40,"value":9721},{"type":31,"tag":1904,"props":10470,"children":10471},{"style":2108},[10472],{"type":40,"value":1951},{"type":31,"tag":1904,"props":10474,"children":10475},{"style":2028},[10476],{"type":40,"value":9730},{"type":31,"tag":1904,"props":10478,"children":10479},{"style":1932},[10480],{"type":40,"value":4652},{"type":31,"tag":1904,"props":10482,"children":10483},{"class":1906,"line":8280},[10484,10488,10492,10496,10501,10505,10509,10513,10518,10522,10526,10530,10534,10538,10543,10547,10551,10555,10560],{"type":31,"tag":1904,"props":10485,"children":10486},{"style":2028},[10487],{"type":40,"value":10186},{"type":31,"tag":1904,"props":10489,"children":10490},{"style":2108},[10491],{"type":40,"value":1951},{"type":31,"tag":1904,"props":10493,"children":10494},{"style":1932},[10495],{"type":40,"value":4625},{"type":31,"tag":1904,"props":10497,"children":10498},{"style":2028},[10499],{"type":40,"value":10500}," status",{"type":31,"tag":1904,"props":10502,"children":10503},{"style":2108},[10504],{"type":40,"value":1951},{"type":31,"tag":1904,"props":10506,"children":10507},{"style":3399},[10508],{"type":40,"value":9901},{"type":31,"tag":1904,"props":10510,"children":10511},{"style":1932},[10512],{"type":40,"value":4853},{"type":31,"tag":1904,"props":10514,"children":10515},{"style":2028},[10516],{"type":40,"value":10517}," convertedAt",{"type":31,"tag":1904,"props":10519,"children":10520},{"style":2108},[10521],{"type":40,"value":1951},{"type":31,"tag":1904,"props":10523,"children":10524},{"style":2816},[10525],{"type":40,"value":2819},{"type":31,"tag":1904,"props":10527,"children":10528},{"style":1926},[10529],{"type":40,"value":5145},{"type":31,"tag":1904,"props":10531,"children":10532},{"style":2028},[10533],{"type":40,"value":2828},{"type":31,"tag":1904,"props":10535,"children":10536},{"style":1932},[10537],{"type":40,"value":4853},{"type":31,"tag":1904,"props":10539,"children":10540},{"style":2028},[10541],{"type":40,"value":10542}," convertedToClientId",{"type":31,"tag":1904,"props":10544,"children":10545},{"style":2108},[10546],{"type":40,"value":1951},{"type":31,"tag":1904,"props":10548,"children":10549},{"style":2028},[10550],{"type":40,"value":3185},{"type":31,"tag":1904,"props":10552,"children":10553},{"style":2108},[10554],{"type":40,"value":76},{"type":31,"tag":1904,"props":10556,"children":10557},{"style":2028},[10558],{"type":40,"value":10559},"id ",{"type":31,"tag":1904,"props":10561,"children":10562},{"style":1932},[10563],{"type":40,"value":4652},{"type":31,"tag":1904,"props":10565,"children":10566},{"class":1906,"line":8344},[10567,10571,10575],{"type":31,"tag":1904,"props":10568,"children":10569},{"style":1932},[10570],{"type":40,"value":4660},{"type":31,"tag":1904,"props":10572,"children":10573},{"style":2028},[10574],{"type":40,"value":1992},{"type":31,"tag":1904,"props":10576,"children":10577},{"style":1932},[10578],{"type":40,"value":2047},{"type":31,"tag":1904,"props":10580,"children":10581},{"class":1906,"line":8406},[10582],{"type":31,"tag":1904,"props":10583,"children":10584},{"emptyLinePlaceholder":13},[10585],{"type":40,"value":2165},{"type":31,"tag":1904,"props":10587,"children":10588},{"class":1906,"line":8458},[10589],{"type":31,"tag":1904,"props":10590,"children":10591},{"style":1911},[10592],{"type":40,"value":10593},"    // 3. Notification Brevo (12 lignes)\n",{"type":31,"tag":1904,"props":10595,"children":10596},{"class":1906,"line":8467},[10597,10601,10605,10609,10614,10618,10622,10626],{"type":31,"tag":1904,"props":10598,"children":10599},{"style":1920},[10600],{"type":40,"value":3313},{"type":31,"tag":1904,"props":10602,"children":10603},{"style":3197},[10604],{"type":40,"value":3200},{"type":31,"tag":1904,"props":10606,"children":10607},{"style":2108},[10608],{"type":40,"value":76},{"type":31,"tag":1904,"props":10610,"children":10611},{"style":2028},[10612],{"type":40,"value":10613},"brevoService",{"type":31,"tag":1904,"props":10615,"children":10616},{"style":2108},[10617],{"type":40,"value":76},{"type":31,"tag":1904,"props":10619,"children":10620},{"style":1926},[10621],{"type":40,"value":4513},{"type":31,"tag":1904,"props":10623,"children":10624},{"style":2028},[10625],{"type":40,"value":2490},{"type":31,"tag":1904,"props":10627,"children":10628},{"style":1932},[10629],{"type":40,"value":3264},{"type":31,"tag":1904,"props":10631,"children":10632},{"class":1906,"line":8484},[10633,10637,10641,10645,10649,10653,10657,10661,10665,10669,10673,10678,10682,10687,10691,10695,10700,10704,10708,10713,10717,10721,10725,10729,10733,10737,10741],{"type":31,"tag":1904,"props":10634,"children":10635},{"style":2028},[10636],{"type":40,"value":4529},{"type":31,"tag":1904,"props":10638,"children":10639},{"style":2108},[10640],{"type":40,"value":1951},{"type":31,"tag":1904,"props":10642,"children":10643},{"style":2028},[10644],{"type":40,"value":4538},{"type":31,"tag":1904,"props":10646,"children":10647},{"style":1932},[10648],{"type":40,"value":4543},{"type":31,"tag":1904,"props":10650,"children":10651},{"style":2028},[10652],{"type":40,"value":4548},{"type":31,"tag":1904,"props":10654,"children":10655},{"style":2108},[10656],{"type":40,"value":1951},{"type":31,"tag":1904,"props":10658,"children":10659},{"style":2028},[10660],{"type":40,"value":3185},{"type":31,"tag":1904,"props":10662,"children":10663},{"style":2108},[10664],{"type":40,"value":76},{"type":31,"tag":1904,"props":10666,"children":10667},{"style":2028},[10668],{"type":40,"value":10030},{"type":31,"tag":1904,"props":10670,"children":10671},{"style":1932},[10672],{"type":40,"value":4853},{"type":31,"tag":1904,"props":10674,"children":10675},{"style":2028},[10676],{"type":40,"value":10677}," name",{"type":31,"tag":1904,"props":10679,"children":10680},{"style":2108},[10681],{"type":40,"value":1951},{"type":31,"tag":1904,"props":10683,"children":10684},{"style":3399},[10685],{"type":40,"value":10686}," `",{"type":31,"tag":1904,"props":10688,"children":10689},{"style":4452},[10690],{"type":40,"value":4455},{"type":31,"tag":1904,"props":10692,"children":10693},{"style":2028},[10694],{"type":40,"value":9976},{"type":31,"tag":1904,"props":10696,"children":10698},{"style":10697},"--shiki-default:#81C8BE;--shiki-dark:#9ECBFF",[10699],{"type":40,"value":76},{"type":31,"tag":1904,"props":10701,"children":10702},{"style":2028},[10703],{"type":40,"value":10247},{"type":31,"tag":1904,"props":10705,"children":10706},{"style":4452},[10707],{"type":40,"value":4464},{"type":31,"tag":1904,"props":10709,"children":10710},{"style":4452},[10711],{"type":40,"value":10712}," ${",{"type":31,"tag":1904,"props":10714,"children":10715},{"style":2028},[10716],{"type":40,"value":9976},{"type":31,"tag":1904,"props":10718,"children":10719},{"style":10697},[10720],{"type":40,"value":76},{"type":31,"tag":1904,"props":10722,"children":10723},{"style":2028},[10724],{"type":40,"value":10276},{"type":31,"tag":1904,"props":10726,"children":10727},{"style":4452},[10728],{"type":40,"value":4464},{"type":31,"tag":1904,"props":10730,"children":10731},{"style":3399},[10732],{"type":40,"value":4469},{"type":31,"tag":1904,"props":10734,"children":10735},{"style":1932},[10736],{"type":40,"value":6488},{"type":31,"tag":1904,"props":10738,"children":10739},{"style":2028},[10740],{"type":40,"value":4574},{"type":31,"tag":1904,"props":10742,"children":10743},{"style":1932},[10744],{"type":40,"value":1962},{"type":31,"tag":1904,"props":10746,"children":10747},{"class":1906,"line":8493},[10748,10752,10756,10761],{"type":31,"tag":1904,"props":10749,"children":10750},{"style":2028},[10751],{"type":40,"value":4586},{"type":31,"tag":1904,"props":10753,"children":10754},{"style":2108},[10755],{"type":40,"value":1951},{"type":31,"tag":1904,"props":10757,"children":10758},{"style":2039},[10759],{"type":40,"value":10760}," 42",{"type":31,"tag":1904,"props":10762,"children":10763},{"style":1932},[10764],{"type":40,"value":1962},{"type":31,"tag":1904,"props":10766,"children":10767},{"class":1906,"line":8502},[10768,10772,10776,10780,10785,10789,10793,10797,10801,10805,10810,10814,10818,10822,10826],{"type":31,"tag":1904,"props":10769,"children":10770},{"style":2028},[10771],{"type":40,"value":4616},{"type":31,"tag":1904,"props":10773,"children":10774},{"style":2108},[10775],{"type":40,"value":1951},{"type":31,"tag":1904,"props":10777,"children":10778},{"style":1932},[10779],{"type":40,"value":4625},{"type":31,"tag":1904,"props":10781,"children":10782},{"style":2028},[10783],{"type":40,"value":10784}," firstName",{"type":31,"tag":1904,"props":10786,"children":10787},{"style":2108},[10788],{"type":40,"value":1951},{"type":31,"tag":1904,"props":10790,"children":10791},{"style":2028},[10792],{"type":40,"value":3185},{"type":31,"tag":1904,"props":10794,"children":10795},{"style":2108},[10796],{"type":40,"value":76},{"type":31,"tag":1904,"props":10798,"children":10799},{"style":2028},[10800],{"type":40,"value":10247},{"type":31,"tag":1904,"props":10802,"children":10803},{"style":1932},[10804],{"type":40,"value":4853},{"type":31,"tag":1904,"props":10806,"children":10807},{"style":2028},[10808],{"type":40,"value":10809}," coachName",{"type":31,"tag":1904,"props":10811,"children":10812},{"style":2108},[10813],{"type":40,"value":1951},{"type":31,"tag":1904,"props":10815,"children":10816},{"style":2028},[10817],{"type":40,"value":2644},{"type":31,"tag":1904,"props":10819,"children":10820},{"style":2108},[10821],{"type":40,"value":76},{"type":31,"tag":1904,"props":10823,"children":10824},{"style":2028},[10825],{"type":40,"value":9833},{"type":31,"tag":1904,"props":10827,"children":10828},{"style":1932},[10829],{"type":40,"value":4652},{"type":31,"tag":1904,"props":10831,"children":10832},{"class":1906,"line":8523},[10833,10837,10841],{"type":31,"tag":1904,"props":10834,"children":10835},{"style":1932},[10836],{"type":40,"value":4660},{"type":31,"tag":1904,"props":10838,"children":10839},{"style":2028},[10840],{"type":40,"value":1992},{"type":31,"tag":1904,"props":10842,"children":10843},{"style":1932},[10844],{"type":40,"value":2047},{"type":31,"tag":1904,"props":10846,"children":10847},{"class":1906,"line":8545},[10848,10852,10856,10860,10864,10868,10873,10878,10882,10886,10890,10895,10899],{"type":31,"tag":1904,"props":10849,"children":10850},{"style":1920},[10851],{"type":40,"value":3313},{"type":31,"tag":1904,"props":10853,"children":10854},{"style":3197},[10855],{"type":40,"value":3200},{"type":31,"tag":1904,"props":10857,"children":10858},{"style":2108},[10859],{"type":40,"value":76},{"type":31,"tag":1904,"props":10861,"children":10862},{"style":2028},[10863],{"type":40,"value":10613},{"type":31,"tag":1904,"props":10865,"children":10866},{"style":2108},[10867],{"type":40,"value":76},{"type":31,"tag":1904,"props":10869,"children":10870},{"style":1926},[10871],{"type":40,"value":10872},"addContactToList",{"type":31,"tag":1904,"props":10874,"children":10875},{"style":2028},[10876],{"type":40,"value":10877},"(client",{"type":31,"tag":1904,"props":10879,"children":10880},{"style":2108},[10881],{"type":40,"value":76},{"type":31,"tag":1904,"props":10883,"children":10884},{"style":2028},[10885],{"type":40,"value":10030},{"type":31,"tag":1904,"props":10887,"children":10888},{"style":1932},[10889],{"type":40,"value":4853},{"type":31,"tag":1904,"props":10891,"children":10892},{"style":3399},[10893],{"type":40,"value":10894}," 'clients-actifs'",{"type":31,"tag":1904,"props":10896,"children":10897},{"style":2028},[10898],{"type":40,"value":1992},{"type":31,"tag":1904,"props":10900,"children":10901},{"style":1932},[10902],{"type":40,"value":2047},{"type":31,"tag":1904,"props":10904,"children":10905},{"class":1906,"line":8566},[10906],{"type":31,"tag":1904,"props":10907,"children":10908},{"emptyLinePlaceholder":13},[10909],{"type":40,"value":2165},{"type":31,"tag":1904,"props":10911,"children":10912},{"class":1906,"line":8600},[10913],{"type":31,"tag":1904,"props":10914,"children":10915},{"style":1911},[10916],{"type":40,"value":10917},"    // 4. Audit (6 lignes)\n",{"type":31,"tag":1904,"props":10919,"children":10920},{"class":1906,"line":8647},[10921,10925,10929,10933,10938,10942,10947,10951],{"type":31,"tag":1904,"props":10922,"children":10923},{"style":1920},[10924],{"type":40,"value":3313},{"type":31,"tag":1904,"props":10926,"children":10927},{"style":3197},[10928],{"type":40,"value":3200},{"type":31,"tag":1904,"props":10930,"children":10931},{"style":2108},[10932],{"type":40,"value":76},{"type":31,"tag":1904,"props":10934,"children":10935},{"style":2028},[10936],{"type":40,"value":10937},"auditService",{"type":31,"tag":1904,"props":10939,"children":10940},{"style":2108},[10941],{"type":40,"value":76},{"type":31,"tag":1904,"props":10943,"children":10944},{"style":1926},[10945],{"type":40,"value":10946},"log",{"type":31,"tag":1904,"props":10948,"children":10949},{"style":2028},[10950],{"type":40,"value":2490},{"type":31,"tag":1904,"props":10952,"children":10953},{"style":1932},[10954],{"type":40,"value":3264},{"type":31,"tag":1904,"props":10956,"children":10957},{"class":1906,"line":8656},[10958,10963,10967,10972],{"type":31,"tag":1904,"props":10959,"children":10960},{"style":2028},[10961],{"type":40,"value":10962},"      action",{"type":31,"tag":1904,"props":10964,"children":10965},{"style":2108},[10966],{"type":40,"value":1951},{"type":31,"tag":1904,"props":10968,"children":10969},{"style":3399},[10970],{"type":40,"value":10971}," 'LEAD_CONVERTED'",{"type":31,"tag":1904,"props":10973,"children":10974},{"style":1932},[10975],{"type":40,"value":1962},{"type":31,"tag":1904,"props":10977,"children":10978},{"class":1906,"line":8664},[10979,10984,10988,10993],{"type":31,"tag":1904,"props":10980,"children":10981},{"style":2028},[10982],{"type":40,"value":10983},"      entityType",{"type":31,"tag":1904,"props":10985,"children":10986},{"style":2108},[10987],{"type":40,"value":1951},{"type":31,"tag":1904,"props":10989,"children":10990},{"style":3399},[10991],{"type":40,"value":10992}," 'client'",{"type":31,"tag":1904,"props":10994,"children":10995},{"style":1932},[10996],{"type":40,"value":1962},{"type":31,"tag":1904,"props":10998,"children":10999},{"class":1906,"line":8677},[11000,11005,11009,11013,11017,11021],{"type":31,"tag":1904,"props":11001,"children":11002},{"style":2028},[11003],{"type":40,"value":11004},"      entityId",{"type":31,"tag":1904,"props":11006,"children":11007},{"style":2108},[11008],{"type":40,"value":1951},{"type":31,"tag":1904,"props":11010,"children":11011},{"style":2028},[11012],{"type":40,"value":3185},{"type":31,"tag":1904,"props":11014,"children":11015},{"style":2108},[11016],{"type":40,"value":76},{"type":31,"tag":1904,"props":11018,"children":11019},{"style":2028},[11020],{"type":40,"value":5058},{"type":31,"tag":1904,"props":11022,"children":11023},{"style":1932},[11024],{"type":40,"value":1962},{"type":31,"tag":1904,"props":11026,"children":11027},{"class":1906,"line":8685},[11028,11033,11037,11041],{"type":31,"tag":1904,"props":11029,"children":11030},{"style":2028},[11031],{"type":40,"value":11032},"      userId",{"type":31,"tag":1904,"props":11034,"children":11035},{"style":2108},[11036],{"type":40,"value":1951},{"type":31,"tag":1904,"props":11038,"children":11039},{"style":2028},[11040],{"type":40,"value":9551},{"type":31,"tag":1904,"props":11042,"children":11043},{"style":1932},[11044],{"type":40,"value":1962},{"type":31,"tag":1904,"props":11046,"children":11047},{"class":1906,"line":8740},[11048,11053,11057,11061,11066,11070,11074],{"type":31,"tag":1904,"props":11049,"children":11050},{"style":2028},[11051],{"type":40,"value":11052},"      meta",{"type":31,"tag":1904,"props":11054,"children":11055},{"style":2108},[11056],{"type":40,"value":1951},{"type":31,"tag":1904,"props":11058,"children":11059},{"style":1932},[11060],{"type":40,"value":4625},{"type":31,"tag":1904,"props":11062,"children":11063},{"style":2028},[11064],{"type":40,"value":11065}," fromLeadId",{"type":31,"tag":1904,"props":11067,"children":11068},{"style":2108},[11069],{"type":40,"value":1951},{"type":31,"tag":1904,"props":11071,"children":11072},{"style":2028},[11073],{"type":40,"value":9730},{"type":31,"tag":1904,"props":11075,"children":11076},{"style":1932},[11077],{"type":40,"value":4652},{"type":31,"tag":1904,"props":11079,"children":11080},{"class":1906,"line":8748},[11081,11085,11089],{"type":31,"tag":1904,"props":11082,"children":11083},{"style":1932},[11084],{"type":40,"value":4660},{"type":31,"tag":1904,"props":11086,"children":11087},{"style":2028},[11088],{"type":40,"value":1992},{"type":31,"tag":1904,"props":11090,"children":11091},{"style":1932},[11092],{"type":40,"value":2047},{"type":31,"tag":1904,"props":11094,"children":11096},{"class":1906,"line":11095},60,[11097],{"type":31,"tag":1904,"props":11098,"children":11099},{"emptyLinePlaceholder":13},[11100],{"type":40,"value":2165},{"type":31,"tag":1904,"props":11102,"children":11104},{"class":1906,"line":11103},61,[11105],{"type":31,"tag":1904,"props":11106,"children":11107},{"style":1911},[11108],{"type":40,"value":11109},"    // 5. Événement domaine (4 lignes)\n",{"type":31,"tag":1904,"props":11111,"children":11113},{"class":1906,"line":11112},62,[11114,11118,11122,11127,11131,11136,11140,11145,11149,11153,11158,11162,11166,11170,11174,11178,11182,11186,11190],{"type":31,"tag":1904,"props":11115,"children":11116},{"style":3197},[11117],{"type":40,"value":3374},{"type":31,"tag":1904,"props":11119,"children":11120},{"style":2108},[11121],{"type":40,"value":76},{"type":31,"tag":1904,"props":11123,"children":11124},{"style":2028},[11125],{"type":40,"value":11126},"eventEmitter",{"type":31,"tag":1904,"props":11128,"children":11129},{"style":2108},[11130],{"type":40,"value":76},{"type":31,"tag":1904,"props":11132,"children":11133},{"style":1926},[11134],{"type":40,"value":11135},"emit",{"type":31,"tag":1904,"props":11137,"children":11138},{"style":2028},[11139],{"type":40,"value":2490},{"type":31,"tag":1904,"props":11141,"children":11142},{"style":3399},[11143],{"type":40,"value":11144},"'client.created'",{"type":31,"tag":1904,"props":11146,"children":11147},{"style":1932},[11148],{"type":40,"value":4853},{"type":31,"tag":1904,"props":11150,"children":11151},{"style":1932},[11152],{"type":40,"value":4625},{"type":31,"tag":1904,"props":11154,"children":11155},{"style":2028},[11156],{"type":40,"value":11157}," clientId",{"type":31,"tag":1904,"props":11159,"children":11160},{"style":2108},[11161],{"type":40,"value":1951},{"type":31,"tag":1904,"props":11163,"children":11164},{"style":2028},[11165],{"type":40,"value":3185},{"type":31,"tag":1904,"props":11167,"children":11168},{"style":2108},[11169],{"type":40,"value":76},{"type":31,"tag":1904,"props":11171,"children":11172},{"style":2028},[11173],{"type":40,"value":5058},{"type":31,"tag":1904,"props":11175,"children":11176},{"style":1932},[11177],{"type":40,"value":4853},{"type":31,"tag":1904,"props":11179,"children":11180},{"style":2028},[11181],{"type":40,"value":10039},{"type":31,"tag":1904,"props":11183,"children":11184},{"style":1932},[11185],{"type":40,"value":4464},{"type":31,"tag":1904,"props":11187,"children":11188},{"style":2028},[11189],{"type":40,"value":1992},{"type":31,"tag":1904,"props":11191,"children":11192},{"style":1932},[11193],{"type":40,"value":2047},{"type":31,"tag":1904,"props":11195,"children":11196},{"class":1906,"line":9196},[11197],{"type":31,"tag":1904,"props":11198,"children":11199},{"emptyLinePlaceholder":13},[11200],{"type":40,"value":2165},{"type":31,"tag":1904,"props":11202,"children":11203},{"class":1906,"line":4027},[11204,11208,11213,11217,11222,11226],{"type":31,"tag":1904,"props":11205,"children":11206},{"style":1920},[11207],{"type":40,"value":2639},{"type":31,"tag":1904,"props":11209,"children":11210},{"style":2028},[11211],{"type":40,"value":11212}," ClientDto",{"type":31,"tag":1904,"props":11214,"children":11215},{"style":2108},[11216],{"type":40,"value":76},{"type":31,"tag":1904,"props":11218,"children":11219},{"style":1926},[11220],{"type":40,"value":11221},"fromPrisma",{"type":31,"tag":1904,"props":11223,"children":11224},{"style":2028},[11225],{"type":40,"value":3431},{"type":31,"tag":1904,"props":11227,"children":11228},{"style":1932},[11229],{"type":40,"value":2047},{"type":31,"tag":1904,"props":11231,"children":11232},{"class":1906,"line":1749},[11233],{"type":31,"tag":1904,"props":11234,"children":11235},{"style":1932},[11236],{"type":40,"value":2717},{"type":31,"tag":1904,"props":11238,"children":11239},{"class":1906,"line":839},[11240],{"type":31,"tag":1904,"props":11241,"children":11242},{"style":1932},[11243],{"type":40,"value":2156},{"type":31,"tag":32,"props":11245,"children":11246},{},[11247,11249,11255,11257,11263,11264,11270,11271,11277,11278,11284,11285,11291],{"type":40,"value":11248},"Le contre-pattern craft, c'est l'application du Single Responsibility Principle. Cette fonction devient un orchestrateur de 10 lignes qui appelle des helpers nommés : ",{"type":31,"tag":169,"props":11250,"children":11252},{"className":11251},[],[11253],{"type":40,"value":11254},"assertLeadIsConvertible",{"type":40,"value":11256},", ",{"type":31,"tag":169,"props":11258,"children":11260},{"className":11259},[],[11261],{"type":40,"value":11262},"createClientFromLead",{"type":40,"value":11256},{"type":31,"tag":169,"props":11265,"children":11267},{"className":11266},[],[11268],{"type":40,"value":11269},"markLeadAsConverted",{"type":40,"value":11256},{"type":31,"tag":169,"props":11272,"children":11274},{"className":11273},[],[11275],{"type":40,"value":11276},"notifyClientOnboarding",{"type":40,"value":11256},{"type":31,"tag":169,"props":11279,"children":11281},{"className":11280},[],[11282],{"type":40,"value":11283},"logConversionAudit",{"type":40,"value":11256},{"type":31,"tag":169,"props":11286,"children":11288},{"className":11287},[],[11289],{"type":40,"value":11290},"emitClientCreated",{"type":40,"value":11292},". Chacun est testable isolément. Chacun est lisible en 30 secondes.",{"type":31,"tag":32,"props":11294,"children":11295},{},[11296,11298,11303],{"type":40,"value":11297},"Le prompt que j'utilise : ",{"type":31,"tag":97,"props":11299,"children":11300},{},[11301],{"type":40,"value":11302},"\"Découpe ce use case en responsabilités nommées. Chaque helper doit tenir en moins de 20 lignes et avoir un seul motif de changement.\"",{"type":40,"value":11304}," Claude exécute proprement. Le problème est qu'il ne le fait jamais spontanément.",{"type":31,"tag":48,"props":11306,"children":11307},{},[],{"type":31,"tag":52,"props":11309,"children":11311},{"id":11310},"pattern-2-couplage-métierorm",[11312],{"type":40,"value":11313},"Pattern #2 : couplage métier/ORM",{"type":31,"tag":32,"props":11315,"children":11316},{},[11317,11319,11325],{"type":40,"value":11318},"Celui-là est plus insidieux. Claude injecte directement le ",{"type":31,"tag":169,"props":11320,"children":11322},{"className":11321},[],[11323],{"type":40,"value":11324},"PrismaClient",{"type":40,"value":11326}," dans les use cases métier. Le résultat : vos règles de gestion ne peuvent plus tourner sans une base Postgres, vos tests ne peuvent plus être unitaires, et changer de stratégie de persistence devient une refonte de plusieurs mois.",{"type":31,"tag":32,"props":11328,"children":11329},{},[11330,11332,11338],{"type":40,"value":11331},"Concrètement, j'ai vu ça dans crmcoaching sur le bounded context ",{"type":31,"tag":169,"props":11333,"children":11335},{"className":11334},[],[11336],{"type":40,"value":11337},"slot-hold",{"type":40,"value":2696},{"type":31,"tag":1894,"props":11340,"children":11342},{"className":1896,"code":11341,"language":1898,"meta":8,"style":8},"// apps/api/src/application/use-cases/check-slot-availability.use-case.ts\n// Couplage direct Prisma dans le use case (anti-pattern)\n\n@Injectable()\nexport class CheckSlotAvailabilityUseCase {\n  constructor(\n    private readonly prisma: PrismaClient, // couplage direct infra\n  ) {}\n\n  async execute(slotId: string, coachId: string): Promise\u003Cboolean> {\n    const holds = await this.prisma.slotHold.count({\n      where: { slotId, status: 'ACTIVE', expiresAt: { gt: new Date() } },\n    });\n    const slot = await this.prisma.slot.findUnique({ where: { id: slotId } });\n    return slot != null && slot.coachId === coachId && holds === 0;\n  }\n}\n",[11343],{"type":31,"tag":169,"props":11344,"children":11345},{"__ignoreMap":8},[11346,11354,11362,11369,11384,11404,11415,11447,11458,11465,11538,11596,11680,11695,11793,11860,11867],{"type":31,"tag":1904,"props":11347,"children":11348},{"class":1906,"line":1907},[11349],{"type":31,"tag":1904,"props":11350,"children":11351},{"style":1911},[11352],{"type":40,"value":11353},"// apps/api/src/application/use-cases/check-slot-availability.use-case.ts\n",{"type":31,"tag":1904,"props":11355,"children":11356},{"class":1906,"line":817},[11357],{"type":31,"tag":1904,"props":11358,"children":11359},{"style":1911},[11360],{"type":40,"value":11361},"// Couplage direct Prisma dans le use case (anti-pattern)\n",{"type":31,"tag":1904,"props":11363,"children":11364},{"class":1906,"line":1938},[11365],{"type":31,"tag":1904,"props":11366,"children":11367},{"emptyLinePlaceholder":13},[11368],{"type":40,"value":2165},{"type":31,"tag":1904,"props":11370,"children":11371},{"class":1906,"line":1965},[11372,11376,11380],{"type":31,"tag":1904,"props":11373,"children":11374},{"style":2548},[11375],{"type":40,"value":2551},{"type":31,"tag":1904,"props":11377,"children":11378},{"style":1926},[11379],{"type":40,"value":2556},{"type":31,"tag":1904,"props":11381,"children":11382},{"style":2559},[11383],{"type":40,"value":2562},{"type":31,"tag":1904,"props":11385,"children":11386},{"class":1906,"line":1986},[11387,11391,11395,11400],{"type":31,"tag":1904,"props":11388,"children":11389},{"style":1920},[11390],{"type":40,"value":2462},{"type":31,"tag":1904,"props":11392,"children":11393},{"style":1920},[11394],{"type":40,"value":2574},{"type":31,"tag":1904,"props":11396,"children":11397},{"style":2470},[11398],{"type":40,"value":11399}," CheckSlotAvailabilityUseCase",{"type":31,"tag":1904,"props":11401,"children":11402},{"style":1932},[11403],{"type":40,"value":2005},{"type":31,"tag":1904,"props":11405,"children":11406},{"class":1906,"line":2008},[11407,11411],{"type":31,"tag":1904,"props":11408,"children":11409},{"style":1920},[11410],{"type":40,"value":2995},{"type":31,"tag":1904,"props":11412,"children":11413},{"style":1932},[11414],{"type":40,"value":1935},{"type":31,"tag":1904,"props":11416,"children":11417},{"class":1906,"line":2050},[11418,11422,11426,11430,11434,11438,11442],{"type":31,"tag":1904,"props":11419,"children":11420},{"style":1920},[11421],{"type":40,"value":3007},{"type":31,"tag":1904,"props":11423,"children":11424},{"style":1920},[11425],{"type":40,"value":3012},{"type":31,"tag":1904,"props":11427,"children":11428},{"style":1942},[11429],{"type":40,"value":9395},{"type":31,"tag":1904,"props":11431,"children":11432},{"style":1948},[11433],{"type":40,"value":1951},{"type":31,"tag":1904,"props":11435,"children":11436},{"style":2470},[11437],{"type":40,"value":9404},{"type":31,"tag":1904,"props":11439,"children":11440},{"style":1932},[11441],{"type":40,"value":4853},{"type":31,"tag":1904,"props":11443,"children":11444},{"style":1911},[11445],{"type":40,"value":11446}," // couplage direct infra\n",{"type":31,"tag":1904,"props":11448,"children":11449},{"class":1906,"line":2094},[11450,11454],{"type":31,"tag":1904,"props":11451,"children":11452},{"style":1932},[11453],{"type":40,"value":3096},{"type":31,"tag":1904,"props":11455,"children":11456},{"style":1932},[11457],{"type":40,"value":3101},{"type":31,"tag":1904,"props":11459,"children":11460},{"class":1906,"line":2150},[11461],{"type":31,"tag":1904,"props":11462,"children":11463},{"emptyLinePlaceholder":13},[11464],{"type":40,"value":2165},{"type":31,"tag":1904,"props":11466,"children":11467},{"class":1906,"line":2159},[11468,11472,11476,11480,11485,11489,11493,11497,11501,11505,11509,11513,11517,11521,11525,11530,11534],{"type":31,"tag":1904,"props":11469,"children":11470},{"style":1920},[11471],{"type":40,"value":3116},{"type":31,"tag":1904,"props":11473,"children":11474},{"style":1926},[11475],{"type":40,"value":9525},{"type":31,"tag":1904,"props":11477,"children":11478},{"style":1932},[11479],{"type":40,"value":2490},{"type":31,"tag":1904,"props":11481,"children":11482},{"style":1942},[11483],{"type":40,"value":11484},"slotId",{"type":31,"tag":1904,"props":11486,"children":11487},{"style":1948},[11488],{"type":40,"value":1951},{"type":31,"tag":1904,"props":11490,"children":11491},{"style":1954},[11492],{"type":40,"value":2790},{"type":31,"tag":1904,"props":11494,"children":11495},{"style":1932},[11496],{"type":40,"value":4853},{"type":31,"tag":1904,"props":11498,"children":11499},{"style":1942},[11500],{"type":40,"value":9551},{"type":31,"tag":1904,"props":11502,"children":11503},{"style":1948},[11504],{"type":40,"value":1951},{"type":31,"tag":1904,"props":11506,"children":11507},{"style":1954},[11508],{"type":40,"value":2790},{"type":31,"tag":1904,"props":11510,"children":11511},{"style":1932},[11512],{"type":40,"value":1992},{"type":31,"tag":1904,"props":11514,"children":11515},{"style":1948},[11516],{"type":40,"value":1951},{"type":31,"tag":1904,"props":11518,"children":11519},{"style":2470},[11520],{"type":40,"value":3152},{"type":31,"tag":1904,"props":11522,"children":11523},{"style":3155},[11524],{"type":40,"value":3158},{"type":31,"tag":1904,"props":11526,"children":11527},{"style":1954},[11528],{"type":40,"value":11529},"boolean",{"type":31,"tag":1904,"props":11531,"children":11532},{"style":3155},[11533],{"type":40,"value":3168},{"type":31,"tag":1904,"props":11535,"children":11536},{"style":1932},[11537],{"type":40,"value":2005},{"type":31,"tag":1904,"props":11539,"children":11540},{"class":1906,"line":2168},[11541,11545,11550,11554,11558,11562,11566,11570,11574,11579,11583,11588,11592],{"type":31,"tag":1904,"props":11542,"children":11543},{"style":1920},[11544],{"type":40,"value":3180},{"type":31,"tag":1904,"props":11546,"children":11547},{"style":2017},[11548],{"type":40,"value":11549}," holds",{"type":31,"tag":1904,"props":11551,"children":11552},{"style":1948},[11553],{"type":40,"value":2025},{"type":31,"tag":1904,"props":11555,"children":11556},{"style":1920},[11557],{"type":40,"value":3194},{"type":31,"tag":1904,"props":11559,"children":11560},{"style":3197},[11561],{"type":40,"value":3200},{"type":31,"tag":1904,"props":11563,"children":11564},{"style":2108},[11565],{"type":40,"value":76},{"type":31,"tag":1904,"props":11567,"children":11568},{"style":2028},[11569],{"type":40,"value":9678},{"type":31,"tag":1904,"props":11571,"children":11572},{"style":2108},[11573],{"type":40,"value":76},{"type":31,"tag":1904,"props":11575,"children":11576},{"style":2028},[11577],{"type":40,"value":11578},"slotHold",{"type":31,"tag":1904,"props":11580,"children":11581},{"style":2108},[11582],{"type":40,"value":76},{"type":31,"tag":1904,"props":11584,"children":11585},{"style":1926},[11586],{"type":40,"value":11587},"count",{"type":31,"tag":1904,"props":11589,"children":11590},{"style":2028},[11591],{"type":40,"value":2490},{"type":31,"tag":1904,"props":11593,"children":11594},{"style":1932},[11595],{"type":40,"value":3264},{"type":31,"tag":1904,"props":11597,"children":11598},{"class":1906,"line":2177},[11599,11603,11607,11611,11616,11620,11624,11628,11632,11636,11641,11645,11649,11654,11658,11662,11666,11671,11675],{"type":31,"tag":1904,"props":11600,"children":11601},{"style":2028},[11602],{"type":40,"value":10001},{"type":31,"tag":1904,"props":11604,"children":11605},{"style":2108},[11606],{"type":40,"value":1951},{"type":31,"tag":1904,"props":11608,"children":11609},{"style":1932},[11610],{"type":40,"value":4625},{"type":31,"tag":1904,"props":11612,"children":11613},{"style":2028},[11614],{"type":40,"value":11615}," slotId",{"type":31,"tag":1904,"props":11617,"children":11618},{"style":1932},[11619],{"type":40,"value":4853},{"type":31,"tag":1904,"props":11621,"children":11622},{"style":2028},[11623],{"type":40,"value":10500},{"type":31,"tag":1904,"props":11625,"children":11626},{"style":2108},[11627],{"type":40,"value":1951},{"type":31,"tag":1904,"props":11629,"children":11630},{"style":3399},[11631],{"type":40,"value":10338},{"type":31,"tag":1904,"props":11633,"children":11634},{"style":1932},[11635],{"type":40,"value":4853},{"type":31,"tag":1904,"props":11637,"children":11638},{"style":2028},[11639],{"type":40,"value":11640}," expiresAt",{"type":31,"tag":1904,"props":11642,"children":11643},{"style":2108},[11644],{"type":40,"value":1951},{"type":31,"tag":1904,"props":11646,"children":11647},{"style":1932},[11648],{"type":40,"value":4625},{"type":31,"tag":1904,"props":11650,"children":11651},{"style":2028},[11652],{"type":40,"value":11653}," gt",{"type":31,"tag":1904,"props":11655,"children":11656},{"style":2108},[11657],{"type":40,"value":1951},{"type":31,"tag":1904,"props":11659,"children":11660},{"style":2816},[11661],{"type":40,"value":2819},{"type":31,"tag":1904,"props":11663,"children":11664},{"style":1926},[11665],{"type":40,"value":5145},{"type":31,"tag":1904,"props":11667,"children":11668},{"style":2028},[11669],{"type":40,"value":11670},"() ",{"type":31,"tag":1904,"props":11672,"children":11673},{"style":1932},[11674],{"type":40,"value":4464},{"type":31,"tag":1904,"props":11676,"children":11677},{"style":1932},[11678],{"type":40,"value":11679}," },\n",{"type":31,"tag":1904,"props":11681,"children":11682},{"class":1906,"line":2194},[11683,11687,11691],{"type":31,"tag":1904,"props":11684,"children":11685},{"style":1932},[11686],{"type":40,"value":4660},{"type":31,"tag":1904,"props":11688,"children":11689},{"style":2028},[11690],{"type":40,"value":1992},{"type":31,"tag":1904,"props":11692,"children":11693},{"style":1932},[11694],{"type":40,"value":2047},{"type":31,"tag":1904,"props":11696,"children":11697},{"class":1906,"line":2215},[11698,11702,11707,11711,11715,11719,11723,11727,11731,11736,11740,11744,11748,11752,11756,11760,11764,11768,11772,11777,11781,11785,11789],{"type":31,"tag":1904,"props":11699,"children":11700},{"style":1920},[11701],{"type":40,"value":3180},{"type":31,"tag":1904,"props":11703,"children":11704},{"style":2017},[11705],{"type":40,"value":11706}," slot",{"type":31,"tag":1904,"props":11708,"children":11709},{"style":1948},[11710],{"type":40,"value":2025},{"type":31,"tag":1904,"props":11712,"children":11713},{"style":1920},[11714],{"type":40,"value":3194},{"type":31,"tag":1904,"props":11716,"children":11717},{"style":3197},[11718],{"type":40,"value":3200},{"type":31,"tag":1904,"props":11720,"children":11721},{"style":2108},[11722],{"type":40,"value":76},{"type":31,"tag":1904,"props":11724,"children":11725},{"style":2028},[11726],{"type":40,"value":9678},{"type":31,"tag":1904,"props":11728,"children":11729},{"style":2108},[11730],{"type":40,"value":76},{"type":31,"tag":1904,"props":11732,"children":11733},{"style":2028},[11734],{"type":40,"value":11735},"slot",{"type":31,"tag":1904,"props":11737,"children":11738},{"style":2108},[11739],{"type":40,"value":76},{"type":31,"tag":1904,"props":11741,"children":11742},{"style":1926},[11743],{"type":40,"value":9695},{"type":31,"tag":1904,"props":11745,"children":11746},{"style":2028},[11747],{"type":40,"value":2490},{"type":31,"tag":1904,"props":11749,"children":11750},{"style":1932},[11751],{"type":40,"value":4543},{"type":31,"tag":1904,"props":11753,"children":11754},{"style":2028},[11755],{"type":40,"value":9708},{"type":31,"tag":1904,"props":11757,"children":11758},{"style":2108},[11759],{"type":40,"value":1951},{"type":31,"tag":1904,"props":11761,"children":11762},{"style":1932},[11763],{"type":40,"value":4625},{"type":31,"tag":1904,"props":11765,"children":11766},{"style":2028},[11767],{"type":40,"value":9721},{"type":31,"tag":1904,"props":11769,"children":11770},{"style":2108},[11771],{"type":40,"value":1951},{"type":31,"tag":1904,"props":11773,"children":11774},{"style":2028},[11775],{"type":40,"value":11776}," slotId ",{"type":31,"tag":1904,"props":11778,"children":11779},{"style":1932},[11780],{"type":40,"value":4464},{"type":31,"tag":1904,"props":11782,"children":11783},{"style":1932},[11784],{"type":40,"value":6488},{"type":31,"tag":1904,"props":11786,"children":11787},{"style":2028},[11788],{"type":40,"value":1992},{"type":31,"tag":1904,"props":11790,"children":11791},{"style":1932},[11792],{"type":40,"value":2047},{"type":31,"tag":1904,"props":11794,"children":11795},{"class":1906,"line":2236},[11796,11800,11805,11809,11813,11818,11822,11826,11830,11834,11838,11843,11848,11852,11856],{"type":31,"tag":1904,"props":11797,"children":11798},{"style":1920},[11799],{"type":40,"value":2639},{"type":31,"tag":1904,"props":11801,"children":11802},{"style":2028},[11803],{"type":40,"value":11804}," slot ",{"type":31,"tag":1904,"props":11806,"children":11807},{"style":1948},[11808],{"type":40,"value":7736},{"type":31,"tag":1904,"props":11810,"children":11811},{"style":1954},[11812],{"type":40,"value":6879},{"type":31,"tag":1904,"props":11814,"children":11815},{"style":1948},[11816],{"type":40,"value":11817}," &&",{"type":31,"tag":1904,"props":11819,"children":11820},{"style":2028},[11821],{"type":40,"value":11706},{"type":31,"tag":1904,"props":11823,"children":11824},{"style":2108},[11825],{"type":40,"value":76},{"type":31,"tag":1904,"props":11827,"children":11828},{"style":2028},[11829],{"type":40,"value":9833},{"type":31,"tag":1904,"props":11831,"children":11832},{"style":1948},[11833],{"type":40,"value":5425},{"type":31,"tag":1904,"props":11835,"children":11836},{"style":2028},[11837],{"type":40,"value":10039},{"type":31,"tag":1904,"props":11839,"children":11840},{"style":1948},[11841],{"type":40,"value":11842},"&&",{"type":31,"tag":1904,"props":11844,"children":11845},{"style":2028},[11846],{"type":40,"value":11847}," holds ",{"type":31,"tag":1904,"props":11849,"children":11850},{"style":1948},[11851],{"type":40,"value":5425},{"type":31,"tag":1904,"props":11853,"children":11854},{"style":2039},[11855],{"type":40,"value":2701},{"type":31,"tag":1904,"props":11857,"children":11858},{"style":1932},[11859],{"type":40,"value":2047},{"type":31,"tag":1904,"props":11861,"children":11862},{"class":1906,"line":2256},[11863],{"type":31,"tag":1904,"props":11864,"children":11865},{"style":1932},[11866],{"type":40,"value":2717},{"type":31,"tag":1904,"props":11868,"children":11869},{"class":1906,"line":2290},[11870],{"type":31,"tag":1904,"props":11871,"children":11872},{"style":1932},[11873],{"type":40,"value":2156},{"type":31,"tag":32,"props":11875,"children":11876},{},[11877,11879,11884,11886,11892,11894,11900,11902,11908,11909,11915,11917,11923],{"type":40,"value":11878},"Le contre-pattern, c'est l'",{"type":31,"tag":69,"props":11880,"children":11881},{"href":3929},[11882],{"type":40,"value":11883},"architecture hexagonale d'Alistair Cockburn",{"type":40,"value":11885}," (2005). La règle métier ne connaît pas Prisma. Elle prend un port ",{"type":31,"tag":169,"props":11887,"children":11889},{"className":11888},[],[11890],{"type":40,"value":11891},"ISlotHoldRepository",{"type":40,"value":11893}," qui expose ",{"type":31,"tag":169,"props":11895,"children":11897},{"className":11896},[],[11898],{"type":40,"value":11899},"countActiveHolds(slotId)",{"type":40,"value":11901}," et un port ",{"type":31,"tag":169,"props":11903,"children":11905},{"className":11904},[],[11906],{"type":40,"value":11907},"ISlotRepository",{"type":40,"value":11893},{"type":31,"tag":169,"props":11910,"children":11912},{"className":11911},[],[11913],{"type":40,"value":11914},"findById(slotId)",{"type":40,"value":11916},". L'implémentation Prisma vit dans ",{"type":31,"tag":169,"props":11918,"children":11920},{"className":11919},[],[11921],{"type":40,"value":11922},"infrastructure/",{"type":40,"value":11924},". Les tests unitaires utilisent un fake repository en mémoire.",{"type":31,"tag":1894,"props":11926,"children":11928},{"className":1896,"code":11927,"language":1898,"meta":8,"style":8},"// apps/api/src/domain/ports/slot-hold.repository.port.ts\nexport interface ISlotHoldRepository {\n  countActiveHolds(slotId: string): Promise\u003Cnumber>;\n}\n\n// apps/api/src/application/use-cases/check-slot-availability.use-case.ts\n@Injectable()\nexport class CheckSlotAvailabilityUseCase {\n  constructor(\n    private readonly slotRepo: ISlotRepository,\n    private readonly slotHoldRepo: ISlotHoldRepository,\n  ) {}\n\n  async execute(slotId: string, coachId: string): Promise\u003Cboolean> {\n    const slot = await this.slotRepo.findById(slotId);\n    if (slot == null || slot.coachId !== coachId) return false;\n    const activeHolds = await this.slotHoldRepo.countActiveHolds(slotId);\n    return activeHolds === 0;\n  }\n}\n",[11929],{"type":31,"tag":169,"props":11930,"children":11931},{"__ignoreMap":8},[11932,11940,11960,12013,12020,12027,12034,12049,12068,12079,12108,12136,12147,12154,12225,12274,12331,12381,12405,12412],{"type":31,"tag":1904,"props":11933,"children":11934},{"class":1906,"line":1907},[11935],{"type":31,"tag":1904,"props":11936,"children":11937},{"style":1911},[11938],{"type":40,"value":11939},"// apps/api/src/domain/ports/slot-hold.repository.port.ts\n",{"type":31,"tag":1904,"props":11941,"children":11942},{"class":1906,"line":817},[11943,11947,11951,11956],{"type":31,"tag":1904,"props":11944,"children":11945},{"style":1920},[11946],{"type":40,"value":2462},{"type":31,"tag":1904,"props":11948,"children":11949},{"style":1920},[11950],{"type":40,"value":2467},{"type":31,"tag":1904,"props":11952,"children":11953},{"style":2470},[11954],{"type":40,"value":11955}," ISlotHoldRepository",{"type":31,"tag":1904,"props":11957,"children":11958},{"style":1932},[11959],{"type":40,"value":2005},{"type":31,"tag":1904,"props":11961,"children":11962},{"class":1906,"line":1938},[11963,11968,11972,11976,11980,11984,11988,11992,11996,12000,12005,12009],{"type":31,"tag":1904,"props":11964,"children":11965},{"style":1926},[11966],{"type":40,"value":11967},"  countActiveHolds",{"type":31,"tag":1904,"props":11969,"children":11970},{"style":1932},[11971],{"type":40,"value":2490},{"type":31,"tag":1904,"props":11973,"children":11974},{"style":1942},[11975],{"type":40,"value":11484},{"type":31,"tag":1904,"props":11977,"children":11978},{"style":1948},[11979],{"type":40,"value":1951},{"type":31,"tag":1904,"props":11981,"children":11982},{"style":1954},[11983],{"type":40,"value":2790},{"type":31,"tag":1904,"props":11985,"children":11986},{"style":1932},[11987],{"type":40,"value":1992},{"type":31,"tag":1904,"props":11989,"children":11990},{"style":1948},[11991],{"type":40,"value":1951},{"type":31,"tag":1904,"props":11993,"children":11994},{"style":2470},[11995],{"type":40,"value":3152},{"type":31,"tag":1904,"props":11997,"children":11998},{"style":3155},[11999],{"type":40,"value":3158},{"type":31,"tag":1904,"props":12001,"children":12002},{"style":1954},[12003],{"type":40,"value":12004},"number",{"type":31,"tag":1904,"props":12006,"children":12007},{"style":3155},[12008],{"type":40,"value":3168},{"type":31,"tag":1904,"props":12010,"children":12011},{"style":1932},[12012],{"type":40,"value":2047},{"type":31,"tag":1904,"props":12014,"children":12015},{"class":1906,"line":1965},[12016],{"type":31,"tag":1904,"props":12017,"children":12018},{"style":1932},[12019],{"type":40,"value":2156},{"type":31,"tag":1904,"props":12021,"children":12022},{"class":1906,"line":1986},[12023],{"type":31,"tag":1904,"props":12024,"children":12025},{"emptyLinePlaceholder":13},[12026],{"type":40,"value":2165},{"type":31,"tag":1904,"props":12028,"children":12029},{"class":1906,"line":2008},[12030],{"type":31,"tag":1904,"props":12031,"children":12032},{"style":1911},[12033],{"type":40,"value":11353},{"type":31,"tag":1904,"props":12035,"children":12036},{"class":1906,"line":2050},[12037,12041,12045],{"type":31,"tag":1904,"props":12038,"children":12039},{"style":2548},[12040],{"type":40,"value":2551},{"type":31,"tag":1904,"props":12042,"children":12043},{"style":1926},[12044],{"type":40,"value":2556},{"type":31,"tag":1904,"props":12046,"children":12047},{"style":2559},[12048],{"type":40,"value":2562},{"type":31,"tag":1904,"props":12050,"children":12051},{"class":1906,"line":2094},[12052,12056,12060,12064],{"type":31,"tag":1904,"props":12053,"children":12054},{"style":1920},[12055],{"type":40,"value":2462},{"type":31,"tag":1904,"props":12057,"children":12058},{"style":1920},[12059],{"type":40,"value":2574},{"type":31,"tag":1904,"props":12061,"children":12062},{"style":2470},[12063],{"type":40,"value":11399},{"type":31,"tag":1904,"props":12065,"children":12066},{"style":1932},[12067],{"type":40,"value":2005},{"type":31,"tag":1904,"props":12069,"children":12070},{"class":1906,"line":2150},[12071,12075],{"type":31,"tag":1904,"props":12072,"children":12073},{"style":1920},[12074],{"type":40,"value":2995},{"type":31,"tag":1904,"props":12076,"children":12077},{"style":1932},[12078],{"type":40,"value":1935},{"type":31,"tag":1904,"props":12080,"children":12081},{"class":1906,"line":2159},[12082,12086,12090,12095,12099,12104],{"type":31,"tag":1904,"props":12083,"children":12084},{"style":1920},[12085],{"type":40,"value":3007},{"type":31,"tag":1904,"props":12087,"children":12088},{"style":1920},[12089],{"type":40,"value":3012},{"type":31,"tag":1904,"props":12091,"children":12092},{"style":1942},[12093],{"type":40,"value":12094}," slotRepo",{"type":31,"tag":1904,"props":12096,"children":12097},{"style":1948},[12098],{"type":40,"value":1951},{"type":31,"tag":1904,"props":12100,"children":12101},{"style":2470},[12102],{"type":40,"value":12103}," ISlotRepository",{"type":31,"tag":1904,"props":12105,"children":12106},{"style":1932},[12107],{"type":40,"value":1962},{"type":31,"tag":1904,"props":12109,"children":12110},{"class":1906,"line":2168},[12111,12115,12119,12124,12128,12132],{"type":31,"tag":1904,"props":12112,"children":12113},{"style":1920},[12114],{"type":40,"value":3007},{"type":31,"tag":1904,"props":12116,"children":12117},{"style":1920},[12118],{"type":40,"value":3012},{"type":31,"tag":1904,"props":12120,"children":12121},{"style":1942},[12122],{"type":40,"value":12123}," slotHoldRepo",{"type":31,"tag":1904,"props":12125,"children":12126},{"style":1948},[12127],{"type":40,"value":1951},{"type":31,"tag":1904,"props":12129,"children":12130},{"style":2470},[12131],{"type":40,"value":11955},{"type":31,"tag":1904,"props":12133,"children":12134},{"style":1932},[12135],{"type":40,"value":1962},{"type":31,"tag":1904,"props":12137,"children":12138},{"class":1906,"line":2177},[12139,12143],{"type":31,"tag":1904,"props":12140,"children":12141},{"style":1932},[12142],{"type":40,"value":3096},{"type":31,"tag":1904,"props":12144,"children":12145},{"style":1932},[12146],{"type":40,"value":3101},{"type":31,"tag":1904,"props":12148,"children":12149},{"class":1906,"line":2194},[12150],{"type":31,"tag":1904,"props":12151,"children":12152},{"emptyLinePlaceholder":13},[12153],{"type":40,"value":2165},{"type":31,"tag":1904,"props":12155,"children":12156},{"class":1906,"line":2215},[12157,12161,12165,12169,12173,12177,12181,12185,12189,12193,12197,12201,12205,12209,12213,12217,12221],{"type":31,"tag":1904,"props":12158,"children":12159},{"style":1920},[12160],{"type":40,"value":3116},{"type":31,"tag":1904,"props":12162,"children":12163},{"style":1926},[12164],{"type":40,"value":9525},{"type":31,"tag":1904,"props":12166,"children":12167},{"style":1932},[12168],{"type":40,"value":2490},{"type":31,"tag":1904,"props":12170,"children":12171},{"style":1942},[12172],{"type":40,"value":11484},{"type":31,"tag":1904,"props":12174,"children":12175},{"style":1948},[12176],{"type":40,"value":1951},{"type":31,"tag":1904,"props":12178,"children":12179},{"style":1954},[12180],{"type":40,"value":2790},{"type":31,"tag":1904,"props":12182,"children":12183},{"style":1932},[12184],{"type":40,"value":4853},{"type":31,"tag":1904,"props":12186,"children":12187},{"style":1942},[12188],{"type":40,"value":9551},{"type":31,"tag":1904,"props":12190,"children":12191},{"style":1948},[12192],{"type":40,"value":1951},{"type":31,"tag":1904,"props":12194,"children":12195},{"style":1954},[12196],{"type":40,"value":2790},{"type":31,"tag":1904,"props":12198,"children":12199},{"style":1932},[12200],{"type":40,"value":1992},{"type":31,"tag":1904,"props":12202,"children":12203},{"style":1948},[12204],{"type":40,"value":1951},{"type":31,"tag":1904,"props":12206,"children":12207},{"style":2470},[12208],{"type":40,"value":3152},{"type":31,"tag":1904,"props":12210,"children":12211},{"style":3155},[12212],{"type":40,"value":3158},{"type":31,"tag":1904,"props":12214,"children":12215},{"style":1954},[12216],{"type":40,"value":11529},{"type":31,"tag":1904,"props":12218,"children":12219},{"style":3155},[12220],{"type":40,"value":3168},{"type":31,"tag":1904,"props":12222,"children":12223},{"style":1932},[12224],{"type":40,"value":2005},{"type":31,"tag":1904,"props":12226,"children":12227},{"class":1906,"line":2236},[12228,12232,12236,12240,12244,12248,12252,12257,12261,12265,12270],{"type":31,"tag":1904,"props":12229,"children":12230},{"style":1920},[12231],{"type":40,"value":3180},{"type":31,"tag":1904,"props":12233,"children":12234},{"style":2017},[12235],{"type":40,"value":11706},{"type":31,"tag":1904,"props":12237,"children":12238},{"style":1948},[12239],{"type":40,"value":2025},{"type":31,"tag":1904,"props":12241,"children":12242},{"style":1920},[12243],{"type":40,"value":3194},{"type":31,"tag":1904,"props":12245,"children":12246},{"style":3197},[12247],{"type":40,"value":3200},{"type":31,"tag":1904,"props":12249,"children":12250},{"style":2108},[12251],{"type":40,"value":76},{"type":31,"tag":1904,"props":12253,"children":12254},{"style":2028},[12255],{"type":40,"value":12256},"slotRepo",{"type":31,"tag":1904,"props":12258,"children":12259},{"style":2108},[12260],{"type":40,"value":76},{"type":31,"tag":1904,"props":12262,"children":12263},{"style":1926},[12264],{"type":40,"value":3218},{"type":31,"tag":1904,"props":12266,"children":12267},{"style":2028},[12268],{"type":40,"value":12269},"(slotId)",{"type":31,"tag":1904,"props":12271,"children":12272},{"style":1932},[12273],{"type":40,"value":2047},{"type":31,"tag":1904,"props":12275,"children":12276},{"class":1906,"line":2256},[12277,12281,12286,12290,12294,12298,12302,12306,12310,12314,12318,12322,12327],{"type":31,"tag":1904,"props":12278,"children":12279},{"style":1920},[12280],{"type":40,"value":3244},{"type":31,"tag":1904,"props":12282,"children":12283},{"style":2028},[12284],{"type":40,"value":12285}," (slot ",{"type":31,"tag":1904,"props":12287,"children":12288},{"style":1948},[12289],{"type":40,"value":7643},{"type":31,"tag":1904,"props":12291,"children":12292},{"style":1954},[12293],{"type":40,"value":6879},{"type":31,"tag":1904,"props":12295,"children":12296},{"style":1948},[12297],{"type":40,"value":8367},{"type":31,"tag":1904,"props":12299,"children":12300},{"style":2028},[12301],{"type":40,"value":11706},{"type":31,"tag":1904,"props":12303,"children":12304},{"style":2108},[12305],{"type":40,"value":76},{"type":31,"tag":1904,"props":12307,"children":12308},{"style":2028},[12309],{"type":40,"value":9833},{"type":31,"tag":1904,"props":12311,"children":12312},{"style":1948},[12313],{"type":40,"value":9838},{"type":31,"tag":1904,"props":12315,"children":12316},{"style":2028},[12317],{"type":40,"value":9843},{"type":31,"tag":1904,"props":12319,"children":12320},{"style":1920},[12321],{"type":40,"value":7749},{"type":31,"tag":1904,"props":12323,"children":12324},{"style":2039},[12325],{"type":40,"value":12326}," false",{"type":31,"tag":1904,"props":12328,"children":12329},{"style":1932},[12330],{"type":40,"value":2047},{"type":31,"tag":1904,"props":12332,"children":12333},{"class":1906,"line":2290},[12334,12338,12343,12347,12351,12355,12359,12364,12368,12373,12377],{"type":31,"tag":1904,"props":12335,"children":12336},{"style":1920},[12337],{"type":40,"value":3180},{"type":31,"tag":1904,"props":12339,"children":12340},{"style":2017},[12341],{"type":40,"value":12342}," activeHolds",{"type":31,"tag":1904,"props":12344,"children":12345},{"style":1948},[12346],{"type":40,"value":2025},{"type":31,"tag":1904,"props":12348,"children":12349},{"style":1920},[12350],{"type":40,"value":3194},{"type":31,"tag":1904,"props":12352,"children":12353},{"style":3197},[12354],{"type":40,"value":3200},{"type":31,"tag":1904,"props":12356,"children":12357},{"style":2108},[12358],{"type":40,"value":76},{"type":31,"tag":1904,"props":12360,"children":12361},{"style":2028},[12362],{"type":40,"value":12363},"slotHoldRepo",{"type":31,"tag":1904,"props":12365,"children":12366},{"style":2108},[12367],{"type":40,"value":76},{"type":31,"tag":1904,"props":12369,"children":12370},{"style":1926},[12371],{"type":40,"value":12372},"countActiveHolds",{"type":31,"tag":1904,"props":12374,"children":12375},{"style":2028},[12376],{"type":40,"value":12269},{"type":31,"tag":1904,"props":12378,"children":12379},{"style":1932},[12380],{"type":40,"value":2047},{"type":31,"tag":1904,"props":12382,"children":12383},{"class":1906,"line":2333},[12384,12388,12393,12397,12401],{"type":31,"tag":1904,"props":12385,"children":12386},{"style":1920},[12387],{"type":40,"value":2639},{"type":31,"tag":1904,"props":12389,"children":12390},{"style":2028},[12391],{"type":40,"value":12392}," activeHolds ",{"type":31,"tag":1904,"props":12394,"children":12395},{"style":1948},[12396],{"type":40,"value":5425},{"type":31,"tag":1904,"props":12398,"children":12399},{"style":2039},[12400],{"type":40,"value":2701},{"type":31,"tag":1904,"props":12402,"children":12403},{"style":1932},[12404],{"type":40,"value":2047},{"type":31,"tag":1904,"props":12406,"children":12407},{"class":1906,"line":2382},[12408],{"type":31,"tag":1904,"props":12409,"children":12410},{"style":1932},[12411],{"type":40,"value":2717},{"type":31,"tag":1904,"props":12413,"children":12414},{"class":1906,"line":4678},[12415],{"type":31,"tag":1904,"props":12416,"children":12417},{"style":1932},[12418],{"type":40,"value":2156},{"type":31,"tag":32,"props":12420,"children":12421},{},[12422],{"type":40,"value":12423},"Sur crmcoaching, j'ai 47 use cases qui ne dépendent d'aucun module externe. Je peux faire tourner toute la logique métier en CI sans démarrer Postgres. Le jour où je voudrai migrer vers Drizzle, ce sera 2 jours de travail au lieu de plusieurs mois.",{"type":31,"tag":48,"props":12425,"children":12426},{},[],{"type":31,"tag":52,"props":12428,"children":12430},{"id":12429},"pattern-3-tests-qui-ne-testent-rien",[12431],{"type":40,"value":12432},"Pattern #3 : tests qui ne testent rien",{"type":31,"tag":32,"props":12434,"children":12435},{},[12436,12438,12444,12446,12451],{"type":40,"value":12437},"Celui-là me fait grincer des dents à chaque fois. Claude génère des tests qui ont l'air sérieux, avec des ",{"type":31,"tag":169,"props":12439,"children":12441},{"className":12440},[],[12442],{"type":40,"value":12443},"describe",{"type":40,"value":12445},", des ",{"type":31,"tag":169,"props":12447,"children":12449},{"className":12448},[],[12450],{"type":40,"value":4709},{"type":40,"value":12452},", des assertions, et qui ne testent en réalité aucun comportement métier. Exemple typique sur crmcoaching :",{"type":31,"tag":1894,"props":12454,"children":12456},{"className":1896,"code":12455,"language":1898,"meta":8,"style":8},"// apps/api/src/application/use-cases/__tests__/create-mentoring-checkout-intent.test.ts\n// Test généré par Claude sans prompt de comportement\n\ndescribe('CreateMentoringCheckoutIntentUseCase', () => {\n  it('should call repository save', async () => {\n    const repo = { save: vi.fn().mockResolvedValue({ id: 'intent-1' }) };\n    const useCase = new CreateMentoringCheckoutIntentUseCase(repo as any);\n\n    await useCase.execute({ coachId: 'c1', clientId: 'cl1', offreId: 'o1' });\n\n    expect(repo.save).toHaveBeenCalledWith(\n      expect.objectContaining({ coachId: 'c1' }),\n    ); // vérifie un appel, pas un comportement\n  });\n});\n",[12457],{"type":31,"tag":169,"props":12458,"children":12459},{"__ignoreMap":8},[12460,12468,12476,12483,12515,12552,12640,12687,12694,12782,12789,12823,12872,12888,12903],{"type":31,"tag":1904,"props":12461,"children":12462},{"class":1906,"line":1907},[12463],{"type":31,"tag":1904,"props":12464,"children":12465},{"style":1911},[12466],{"type":40,"value":12467},"// apps/api/src/application/use-cases/__tests__/create-mentoring-checkout-intent.test.ts\n",{"type":31,"tag":1904,"props":12469,"children":12470},{"class":1906,"line":817},[12471],{"type":31,"tag":1904,"props":12472,"children":12473},{"style":1911},[12474],{"type":40,"value":12475},"// Test généré par Claude sans prompt de comportement\n",{"type":31,"tag":1904,"props":12477,"children":12478},{"class":1906,"line":1938},[12479],{"type":31,"tag":1904,"props":12480,"children":12481},{"emptyLinePlaceholder":13},[12482],{"type":40,"value":2165},{"type":31,"tag":1904,"props":12484,"children":12485},{"class":1906,"line":1965},[12486,12490,12494,12499,12503,12507,12511],{"type":31,"tag":1904,"props":12487,"children":12488},{"style":1926},[12489],{"type":40,"value":12443},{"type":31,"tag":1904,"props":12491,"children":12492},{"style":2028},[12493],{"type":40,"value":2490},{"type":31,"tag":1904,"props":12495,"children":12496},{"style":3399},[12497],{"type":40,"value":12498},"'CreateMentoringCheckoutIntentUseCase'",{"type":31,"tag":1904,"props":12500,"children":12501},{"style":1932},[12502],{"type":40,"value":4853},{"type":31,"tag":1904,"props":12504,"children":12505},{"style":1932},[12506],{"type":40,"value":4863},{"type":31,"tag":1904,"props":12508,"children":12509},{"style":1948},[12510],{"type":40,"value":4868},{"type":31,"tag":1904,"props":12512,"children":12513},{"style":1932},[12514],{"type":40,"value":2005},{"type":31,"tag":1904,"props":12516,"children":12517},{"class":1906,"line":1986},[12518,12523,12527,12532,12536,12540,12544,12548],{"type":31,"tag":1904,"props":12519,"children":12520},{"style":1926},[12521],{"type":40,"value":12522},"  it",{"type":31,"tag":1904,"props":12524,"children":12525},{"style":2028},[12526],{"type":40,"value":2490},{"type":31,"tag":1904,"props":12528,"children":12529},{"style":3399},[12530],{"type":40,"value":12531},"'should call repository save'",{"type":31,"tag":1904,"props":12533,"children":12534},{"style":1932},[12535],{"type":40,"value":4853},{"type":31,"tag":1904,"props":12537,"children":12538},{"style":1920},[12539],{"type":40,"value":4858},{"type":31,"tag":1904,"props":12541,"children":12542},{"style":1932},[12543],{"type":40,"value":4863},{"type":31,"tag":1904,"props":12545,"children":12546},{"style":1948},[12547],{"type":40,"value":4868},{"type":31,"tag":1904,"props":12549,"children":12550},{"style":1932},[12551],{"type":40,"value":2005},{"type":31,"tag":1904,"props":12553,"children":12554},{"class":1906,"line":2008},[12555,12559,12564,12568,12572,12577,12581,12585,12589,12594,12598,12602,12606,12610,12614,12618,12622,12627,12631,12635],{"type":31,"tag":1904,"props":12556,"children":12557},{"style":1920},[12558],{"type":40,"value":3180},{"type":31,"tag":1904,"props":12560,"children":12561},{"style":2017},[12562],{"type":40,"value":12563}," repo",{"type":31,"tag":1904,"props":12565,"children":12566},{"style":1948},[12567],{"type":40,"value":2025},{"type":31,"tag":1904,"props":12569,"children":12570},{"style":1932},[12571],{"type":40,"value":4625},{"type":31,"tag":1904,"props":12573,"children":12574},{"style":2028},[12575],{"type":40,"value":12576}," save",{"type":31,"tag":1904,"props":12578,"children":12579},{"style":2108},[12580],{"type":40,"value":1951},{"type":31,"tag":1904,"props":12582,"children":12583},{"style":2028},[12584],{"type":40,"value":6586},{"type":31,"tag":1904,"props":12586,"children":12587},{"style":2108},[12588],{"type":40,"value":76},{"type":31,"tag":1904,"props":12590,"children":12591},{"style":1926},[12592],{"type":40,"value":12593},"fn",{"type":31,"tag":1904,"props":12595,"children":12596},{"style":2028},[12597],{"type":40,"value":2828},{"type":31,"tag":1904,"props":12599,"children":12600},{"style":2108},[12601],{"type":40,"value":76},{"type":31,"tag":1904,"props":12603,"children":12604},{"style":1926},[12605],{"type":40,"value":5217},{"type":31,"tag":1904,"props":12607,"children":12608},{"style":2028},[12609],{"type":40,"value":2490},{"type":31,"tag":1904,"props":12611,"children":12612},{"style":1932},[12613],{"type":40,"value":4543},{"type":31,"tag":1904,"props":12615,"children":12616},{"style":2028},[12617],{"type":40,"value":9721},{"type":31,"tag":1904,"props":12619,"children":12620},{"style":2108},[12621],{"type":40,"value":1951},{"type":31,"tag":1904,"props":12623,"children":12624},{"style":3399},[12625],{"type":40,"value":12626}," 'intent-1'",{"type":31,"tag":1904,"props":12628,"children":12629},{"style":1932},[12630],{"type":40,"value":6488},{"type":31,"tag":1904,"props":12632,"children":12633},{"style":2028},[12634],{"type":40,"value":2135},{"type":31,"tag":1904,"props":12636,"children":12637},{"style":1932},[12638],{"type":40,"value":12639},"};\n",{"type":31,"tag":1904,"props":12641,"children":12642},{"class":1906,"line":2050},[12643,12647,12652,12656,12660,12665,12670,12674,12679,12683],{"type":31,"tag":1904,"props":12644,"children":12645},{"style":1920},[12646],{"type":40,"value":3180},{"type":31,"tag":1904,"props":12648,"children":12649},{"style":2017},[12650],{"type":40,"value":12651}," useCase",{"type":31,"tag":1904,"props":12653,"children":12654},{"style":1948},[12655],{"type":40,"value":2025},{"type":31,"tag":1904,"props":12657,"children":12658},{"style":2816},[12659],{"type":40,"value":2819},{"type":31,"tag":1904,"props":12661,"children":12662},{"style":1926},[12663],{"type":40,"value":12664}," CreateMentoringCheckoutIntentUseCase",{"type":31,"tag":1904,"props":12666,"children":12667},{"style":2028},[12668],{"type":40,"value":12669},"(repo ",{"type":31,"tag":1904,"props":12671,"children":12672},{"style":1920},[12673],{"type":40,"value":5915},{"type":31,"tag":1904,"props":12675,"children":12676},{"style":1954},[12677],{"type":40,"value":12678}," any",{"type":31,"tag":1904,"props":12680,"children":12681},{"style":2028},[12682],{"type":40,"value":1992},{"type":31,"tag":1904,"props":12684,"children":12685},{"style":1932},[12686],{"type":40,"value":2047},{"type":31,"tag":1904,"props":12688,"children":12689},{"class":1906,"line":2094},[12690],{"type":31,"tag":1904,"props":12691,"children":12692},{"emptyLinePlaceholder":13},[12693],{"type":40,"value":2165},{"type":31,"tag":1904,"props":12695,"children":12696},{"class":1906,"line":2150},[12697,12701,12705,12709,12714,12718,12722,12726,12730,12735,12739,12743,12747,12752,12756,12761,12765,12770,12774,12778],{"type":31,"tag":1904,"props":12698,"children":12699},{"style":1920},[12700],{"type":40,"value":3313},{"type":31,"tag":1904,"props":12702,"children":12703},{"style":2028},[12704],{"type":40,"value":12651},{"type":31,"tag":1904,"props":12706,"children":12707},{"style":2108},[12708],{"type":40,"value":76},{"type":31,"tag":1904,"props":12710,"children":12711},{"style":1926},[12712],{"type":40,"value":12713},"execute",{"type":31,"tag":1904,"props":12715,"children":12716},{"style":2028},[12717],{"type":40,"value":2490},{"type":31,"tag":1904,"props":12719,"children":12720},{"style":1932},[12721],{"type":40,"value":4543},{"type":31,"tag":1904,"props":12723,"children":12724},{"style":2028},[12725],{"type":40,"value":9551},{"type":31,"tag":1904,"props":12727,"children":12728},{"style":2108},[12729],{"type":40,"value":1951},{"type":31,"tag":1904,"props":12731,"children":12732},{"style":3399},[12733],{"type":40,"value":12734}," 'c1'",{"type":31,"tag":1904,"props":12736,"children":12737},{"style":1932},[12738],{"type":40,"value":4853},{"type":31,"tag":1904,"props":12740,"children":12741},{"style":2028},[12742],{"type":40,"value":11157},{"type":31,"tag":1904,"props":12744,"children":12745},{"style":2108},[12746],{"type":40,"value":1951},{"type":31,"tag":1904,"props":12748,"children":12749},{"style":3399},[12750],{"type":40,"value":12751}," 'cl1'",{"type":31,"tag":1904,"props":12753,"children":12754},{"style":1932},[12755],{"type":40,"value":4853},{"type":31,"tag":1904,"props":12757,"children":12758},{"style":2028},[12759],{"type":40,"value":12760}," offreId",{"type":31,"tag":1904,"props":12762,"children":12763},{"style":2108},[12764],{"type":40,"value":1951},{"type":31,"tag":1904,"props":12766,"children":12767},{"style":3399},[12768],{"type":40,"value":12769}," 'o1'",{"type":31,"tag":1904,"props":12771,"children":12772},{"style":1932},[12773],{"type":40,"value":6488},{"type":31,"tag":1904,"props":12775,"children":12776},{"style":2028},[12777],{"type":40,"value":1992},{"type":31,"tag":1904,"props":12779,"children":12780},{"style":1932},[12781],{"type":40,"value":2047},{"type":31,"tag":1904,"props":12783,"children":12784},{"class":1906,"line":2159},[12785],{"type":31,"tag":1904,"props":12786,"children":12787},{"emptyLinePlaceholder":13},[12788],{"type":40,"value":2165},{"type":31,"tag":1904,"props":12790,"children":12791},{"class":1906,"line":2168},[12792,12797,12802,12806,12810,12814,12819],{"type":31,"tag":1904,"props":12793,"children":12794},{"style":1926},[12795],{"type":40,"value":12796},"    expect",{"type":31,"tag":1904,"props":12798,"children":12799},{"style":2028},[12800],{"type":40,"value":12801},"(repo",{"type":31,"tag":1904,"props":12803,"children":12804},{"style":2108},[12805],{"type":40,"value":76},{"type":31,"tag":1904,"props":12807,"children":12808},{"style":2028},[12809],{"type":40,"value":7144},{"type":31,"tag":1904,"props":12811,"children":12812},{"style":2108},[12813],{"type":40,"value":76},{"type":31,"tag":1904,"props":12815,"children":12816},{"style":1926},[12817],{"type":40,"value":12818},"toHaveBeenCalledWith",{"type":31,"tag":1904,"props":12820,"children":12821},{"style":2028},[12822],{"type":40,"value":1935},{"type":31,"tag":1904,"props":12824,"children":12825},{"class":1906,"line":2177},[12826,12831,12835,12840,12844,12848,12852,12856,12860,12864,12868],{"type":31,"tag":1904,"props":12827,"children":12828},{"style":2028},[12829],{"type":40,"value":12830},"      expect",{"type":31,"tag":1904,"props":12832,"children":12833},{"style":2108},[12834],{"type":40,"value":76},{"type":31,"tag":1904,"props":12836,"children":12837},{"style":1926},[12838],{"type":40,"value":12839},"objectContaining",{"type":31,"tag":1904,"props":12841,"children":12842},{"style":2028},[12843],{"type":40,"value":2490},{"type":31,"tag":1904,"props":12845,"children":12846},{"style":1932},[12847],{"type":40,"value":4543},{"type":31,"tag":1904,"props":12849,"children":12850},{"style":2028},[12851],{"type":40,"value":9551},{"type":31,"tag":1904,"props":12853,"children":12854},{"style":2108},[12855],{"type":40,"value":1951},{"type":31,"tag":1904,"props":12857,"children":12858},{"style":3399},[12859],{"type":40,"value":12734},{"type":31,"tag":1904,"props":12861,"children":12862},{"style":1932},[12863],{"type":40,"value":6488},{"type":31,"tag":1904,"props":12865,"children":12866},{"style":2028},[12867],{"type":40,"value":1992},{"type":31,"tag":1904,"props":12869,"children":12870},{"style":1932},[12871],{"type":40,"value":1962},{"type":31,"tag":1904,"props":12873,"children":12874},{"class":1906,"line":2194},[12875,12879,12883],{"type":31,"tag":1904,"props":12876,"children":12877},{"style":2028},[12878],{"type":40,"value":8670},{"type":31,"tag":1904,"props":12880,"children":12881},{"style":1932},[12882],{"type":40,"value":8398},{"type":31,"tag":1904,"props":12884,"children":12885},{"style":1911},[12886],{"type":40,"value":12887}," // vérifie un appel, pas un comportement\n",{"type":31,"tag":1904,"props":12889,"children":12890},{"class":1906,"line":2215},[12891,12895,12899],{"type":31,"tag":1904,"props":12892,"children":12893},{"style":1932},[12894],{"type":40,"value":5170},{"type":31,"tag":1904,"props":12896,"children":12897},{"style":2028},[12898],{"type":40,"value":1992},{"type":31,"tag":1904,"props":12900,"children":12901},{"style":1932},[12902],{"type":40,"value":2047},{"type":31,"tag":1904,"props":12904,"children":12905},{"class":1906,"line":2236},[12906,12910,12914],{"type":31,"tag":1904,"props":12907,"children":12908},{"style":1932},[12909],{"type":40,"value":4464},{"type":31,"tag":1904,"props":12911,"children":12912},{"style":2028},[12913],{"type":40,"value":1992},{"type":31,"tag":1904,"props":12915,"children":12916},{"style":1932},[12917],{"type":40,"value":2047},{"type":31,"tag":32,"props":12919,"children":12920},{},[12921],{"type":40,"value":12922},"Ce test ne dit rien. Il vérifie que la fonction appelle une autre fonction. C'est tautologique. Si vous changez l'implémentation pour utiliser un event store au lieu d'un repository, le test casse, sans qu'aucun comportement métier ait changé. C'est le pire des deux mondes : couplage fort à l'implémentation, zéro garantie de correction.",{"type":31,"tag":32,"props":12924,"children":12925},{},[12926,12928,12933],{"type":40,"value":12927},"Le contre-pattern, c'est ce que Dan North appelait ",{"type":31,"tag":97,"props":12929,"children":12930},{},[12931],{"type":40,"value":12932},"\"Tests as Specifications\"",{"type":40,"value":12934}," dans ses articles BDD fondateurs de 2006. Le test décrit un comportement observable :",{"type":31,"tag":1894,"props":12936,"children":12938},{"className":1896,"code":12937,"language":1898,"meta":8,"style":8},"describe('CreateMentoringCheckoutIntentUseCase', () => {\n  it('étant donné une offre active, quand on crée l\\'intent, alors l\\'intent contient le prix de l\\'offre', async () => {\n    // Given\n    const offre = { id: 'o1', price: 150, currency: 'EUR', status: 'ACTIVE' };\n    const repo = new InMemoryCheckoutIntentRepository();\n    const offreRepo = new InMemoryOffreRepository([offre]);\n    const useCase = new CreateMentoringCheckoutIntentUseCase(repo, offreRepo);\n\n    // When\n    const result = await useCase.execute({ coachId: 'c1', clientId: 'cl1', offreId: 'o1' });\n\n    // Then\n    expect(result.amount).toBe(150);\n    expect(result.currency).toBe('EUR');\n    expect(result.status).toBe('PENDING');\n  });\n});\n",[12939],{"type":31,"tag":169,"props":12940,"children":12941},{"__ignoreMap":8},[12942,12973,13038,13046,13134,13166,13200,13240,13247,13255,13351,13358,13366,13412,13457,13502,13517],{"type":31,"tag":1904,"props":12943,"children":12944},{"class":1906,"line":1907},[12945,12949,12953,12957,12961,12965,12969],{"type":31,"tag":1904,"props":12946,"children":12947},{"style":1926},[12948],{"type":40,"value":12443},{"type":31,"tag":1904,"props":12950,"children":12951},{"style":2028},[12952],{"type":40,"value":2490},{"type":31,"tag":1904,"props":12954,"children":12955},{"style":3399},[12956],{"type":40,"value":12498},{"type":31,"tag":1904,"props":12958,"children":12959},{"style":1932},[12960],{"type":40,"value":4853},{"type":31,"tag":1904,"props":12962,"children":12963},{"style":1932},[12964],{"type":40,"value":4863},{"type":31,"tag":1904,"props":12966,"children":12967},{"style":1948},[12968],{"type":40,"value":4868},{"type":31,"tag":1904,"props":12970,"children":12971},{"style":1932},[12972],{"type":40,"value":2005},{"type":31,"tag":1904,"props":12974,"children":12975},{"class":1906,"line":817},[12976,12980,12984,12989,12995,13000,13004,13009,13013,13018,13022,13026,13030,13034],{"type":31,"tag":1904,"props":12977,"children":12978},{"style":1926},[12979],{"type":40,"value":12522},{"type":31,"tag":1904,"props":12981,"children":12982},{"style":2028},[12983],{"type":40,"value":2490},{"type":31,"tag":1904,"props":12985,"children":12986},{"style":3399},[12987],{"type":40,"value":12988},"'étant donné une offre active, quand on crée l",{"type":31,"tag":1904,"props":12990,"children":12992},{"style":12991},"--shiki-default:#F4B8E4;--shiki-dark:#79B8FF",[12993],{"type":40,"value":12994},"\\'",{"type":31,"tag":1904,"props":12996,"children":12997},{"style":3399},[12998],{"type":40,"value":12999},"intent, alors l",{"type":31,"tag":1904,"props":13001,"children":13002},{"style":12991},[13003],{"type":40,"value":12994},{"type":31,"tag":1904,"props":13005,"children":13006},{"style":3399},[13007],{"type":40,"value":13008},"intent contient le prix de l",{"type":31,"tag":1904,"props":13010,"children":13011},{"style":12991},[13012],{"type":40,"value":12994},{"type":31,"tag":1904,"props":13014,"children":13015},{"style":3399},[13016],{"type":40,"value":13017},"offre'",{"type":31,"tag":1904,"props":13019,"children":13020},{"style":1932},[13021],{"type":40,"value":4853},{"type":31,"tag":1904,"props":13023,"children":13024},{"style":1920},[13025],{"type":40,"value":4858},{"type":31,"tag":1904,"props":13027,"children":13028},{"style":1932},[13029],{"type":40,"value":4863},{"type":31,"tag":1904,"props":13031,"children":13032},{"style":1948},[13033],{"type":40,"value":4868},{"type":31,"tag":1904,"props":13035,"children":13036},{"style":1932},[13037],{"type":40,"value":2005},{"type":31,"tag":1904,"props":13039,"children":13040},{"class":1906,"line":1938},[13041],{"type":31,"tag":1904,"props":13042,"children":13043},{"style":1911},[13044],{"type":40,"value":13045},"    // Given\n",{"type":31,"tag":1904,"props":13047,"children":13048},{"class":1906,"line":1965},[13049,13053,13058,13062,13066,13070,13074,13078,13082,13087,13091,13096,13100,13105,13109,13114,13118,13122,13126,13130],{"type":31,"tag":1904,"props":13050,"children":13051},{"style":1920},[13052],{"type":40,"value":3180},{"type":31,"tag":1904,"props":13054,"children":13055},{"style":2017},[13056],{"type":40,"value":13057}," offre",{"type":31,"tag":1904,"props":13059,"children":13060},{"style":1948},[13061],{"type":40,"value":2025},{"type":31,"tag":1904,"props":13063,"children":13064},{"style":1932},[13065],{"type":40,"value":4625},{"type":31,"tag":1904,"props":13067,"children":13068},{"style":2028},[13069],{"type":40,"value":9721},{"type":31,"tag":1904,"props":13071,"children":13072},{"style":2108},[13073],{"type":40,"value":1951},{"type":31,"tag":1904,"props":13075,"children":13076},{"style":3399},[13077],{"type":40,"value":12769},{"type":31,"tag":1904,"props":13079,"children":13080},{"style":1932},[13081],{"type":40,"value":4853},{"type":31,"tag":1904,"props":13083,"children":13084},{"style":2028},[13085],{"type":40,"value":13086}," price",{"type":31,"tag":1904,"props":13088,"children":13089},{"style":2108},[13090],{"type":40,"value":1951},{"type":31,"tag":1904,"props":13092,"children":13093},{"style":2039},[13094],{"type":40,"value":13095}," 150",{"type":31,"tag":1904,"props":13097,"children":13098},{"style":1932},[13099],{"type":40,"value":4853},{"type":31,"tag":1904,"props":13101,"children":13102},{"style":2028},[13103],{"type":40,"value":13104}," currency",{"type":31,"tag":1904,"props":13106,"children":13107},{"style":2108},[13108],{"type":40,"value":1951},{"type":31,"tag":1904,"props":13110,"children":13111},{"style":3399},[13112],{"type":40,"value":13113}," 'EUR'",{"type":31,"tag":1904,"props":13115,"children":13116},{"style":1932},[13117],{"type":40,"value":4853},{"type":31,"tag":1904,"props":13119,"children":13120},{"style":2028},[13121],{"type":40,"value":10500},{"type":31,"tag":1904,"props":13123,"children":13124},{"style":2108},[13125],{"type":40,"value":1951},{"type":31,"tag":1904,"props":13127,"children":13128},{"style":3399},[13129],{"type":40,"value":10338},{"type":31,"tag":1904,"props":13131,"children":13132},{"style":1932},[13133],{"type":40,"value":5947},{"type":31,"tag":1904,"props":13135,"children":13136},{"class":1906,"line":1986},[13137,13141,13145,13149,13153,13158,13162],{"type":31,"tag":1904,"props":13138,"children":13139},{"style":1920},[13140],{"type":40,"value":3180},{"type":31,"tag":1904,"props":13142,"children":13143},{"style":2017},[13144],{"type":40,"value":12563},{"type":31,"tag":1904,"props":13146,"children":13147},{"style":1948},[13148],{"type":40,"value":2025},{"type":31,"tag":1904,"props":13150,"children":13151},{"style":2816},[13152],{"type":40,"value":2819},{"type":31,"tag":1904,"props":13154,"children":13155},{"style":1926},[13156],{"type":40,"value":13157}," InMemoryCheckoutIntentRepository",{"type":31,"tag":1904,"props":13159,"children":13160},{"style":2028},[13161],{"type":40,"value":2828},{"type":31,"tag":1904,"props":13163,"children":13164},{"style":1932},[13165],{"type":40,"value":2047},{"type":31,"tag":1904,"props":13167,"children":13168},{"class":1906,"line":2008},[13169,13173,13178,13182,13186,13191,13196],{"type":31,"tag":1904,"props":13170,"children":13171},{"style":1920},[13172],{"type":40,"value":3180},{"type":31,"tag":1904,"props":13174,"children":13175},{"style":2017},[13176],{"type":40,"value":13177}," offreRepo",{"type":31,"tag":1904,"props":13179,"children":13180},{"style":1948},[13181],{"type":40,"value":2025},{"type":31,"tag":1904,"props":13183,"children":13184},{"style":2816},[13185],{"type":40,"value":2819},{"type":31,"tag":1904,"props":13187,"children":13188},{"style":1926},[13189],{"type":40,"value":13190}," InMemoryOffreRepository",{"type":31,"tag":1904,"props":13192,"children":13193},{"style":2028},[13194],{"type":40,"value":13195},"([offre])",{"type":31,"tag":1904,"props":13197,"children":13198},{"style":1932},[13199],{"type":40,"value":2047},{"type":31,"tag":1904,"props":13201,"children":13202},{"class":1906,"line":2050},[13203,13207,13211,13215,13219,13223,13227,13231,13236],{"type":31,"tag":1904,"props":13204,"children":13205},{"style":1920},[13206],{"type":40,"value":3180},{"type":31,"tag":1904,"props":13208,"children":13209},{"style":2017},[13210],{"type":40,"value":12651},{"type":31,"tag":1904,"props":13212,"children":13213},{"style":1948},[13214],{"type":40,"value":2025},{"type":31,"tag":1904,"props":13216,"children":13217},{"style":2816},[13218],{"type":40,"value":2819},{"type":31,"tag":1904,"props":13220,"children":13221},{"style":1926},[13222],{"type":40,"value":12664},{"type":31,"tag":1904,"props":13224,"children":13225},{"style":2028},[13226],{"type":40,"value":12801},{"type":31,"tag":1904,"props":13228,"children":13229},{"style":1932},[13230],{"type":40,"value":4853},{"type":31,"tag":1904,"props":13232,"children":13233},{"style":2028},[13234],{"type":40,"value":13235}," offreRepo)",{"type":31,"tag":1904,"props":13237,"children":13238},{"style":1932},[13239],{"type":40,"value":2047},{"type":31,"tag":1904,"props":13241,"children":13242},{"class":1906,"line":2094},[13243],{"type":31,"tag":1904,"props":13244,"children":13245},{"emptyLinePlaceholder":13},[13246],{"type":40,"value":2165},{"type":31,"tag":1904,"props":13248,"children":13249},{"class":1906,"line":2150},[13250],{"type":31,"tag":1904,"props":13251,"children":13252},{"style":1911},[13253],{"type":40,"value":13254},"    // When\n",{"type":31,"tag":1904,"props":13256,"children":13257},{"class":1906,"line":2159},[13258,13262,13267,13271,13275,13279,13283,13287,13291,13295,13299,13303,13307,13311,13315,13319,13323,13327,13331,13335,13339,13343,13347],{"type":31,"tag":1904,"props":13259,"children":13260},{"style":1920},[13261],{"type":40,"value":3180},{"type":31,"tag":1904,"props":13263,"children":13264},{"style":2017},[13265],{"type":40,"value":13266}," result",{"type":31,"tag":1904,"props":13268,"children":13269},{"style":1948},[13270],{"type":40,"value":2025},{"type":31,"tag":1904,"props":13272,"children":13273},{"style":1920},[13274],{"type":40,"value":3194},{"type":31,"tag":1904,"props":13276,"children":13277},{"style":2028},[13278],{"type":40,"value":12651},{"type":31,"tag":1904,"props":13280,"children":13281},{"style":2108},[13282],{"type":40,"value":76},{"type":31,"tag":1904,"props":13284,"children":13285},{"style":1926},[13286],{"type":40,"value":12713},{"type":31,"tag":1904,"props":13288,"children":13289},{"style":2028},[13290],{"type":40,"value":2490},{"type":31,"tag":1904,"props":13292,"children":13293},{"style":1932},[13294],{"type":40,"value":4543},{"type":31,"tag":1904,"props":13296,"children":13297},{"style":2028},[13298],{"type":40,"value":9551},{"type":31,"tag":1904,"props":13300,"children":13301},{"style":2108},[13302],{"type":40,"value":1951},{"type":31,"tag":1904,"props":13304,"children":13305},{"style":3399},[13306],{"type":40,"value":12734},{"type":31,"tag":1904,"props":13308,"children":13309},{"style":1932},[13310],{"type":40,"value":4853},{"type":31,"tag":1904,"props":13312,"children":13313},{"style":2028},[13314],{"type":40,"value":11157},{"type":31,"tag":1904,"props":13316,"children":13317},{"style":2108},[13318],{"type":40,"value":1951},{"type":31,"tag":1904,"props":13320,"children":13321},{"style":3399},[13322],{"type":40,"value":12751},{"type":31,"tag":1904,"props":13324,"children":13325},{"style":1932},[13326],{"type":40,"value":4853},{"type":31,"tag":1904,"props":13328,"children":13329},{"style":2028},[13330],{"type":40,"value":12760},{"type":31,"tag":1904,"props":13332,"children":13333},{"style":2108},[13334],{"type":40,"value":1951},{"type":31,"tag":1904,"props":13336,"children":13337},{"style":3399},[13338],{"type":40,"value":12769},{"type":31,"tag":1904,"props":13340,"children":13341},{"style":1932},[13342],{"type":40,"value":6488},{"type":31,"tag":1904,"props":13344,"children":13345},{"style":2028},[13346],{"type":40,"value":1992},{"type":31,"tag":1904,"props":13348,"children":13349},{"style":1932},[13350],{"type":40,"value":2047},{"type":31,"tag":1904,"props":13352,"children":13353},{"class":1906,"line":2168},[13354],{"type":31,"tag":1904,"props":13355,"children":13356},{"emptyLinePlaceholder":13},[13357],{"type":40,"value":2165},{"type":31,"tag":1904,"props":13359,"children":13360},{"class":1906,"line":2177},[13361],{"type":31,"tag":1904,"props":13362,"children":13363},{"style":1911},[13364],{"type":40,"value":13365},"    // Then\n",{"type":31,"tag":1904,"props":13367,"children":13368},{"class":1906,"line":2194},[13369,13373,13378,13382,13387,13391,13395,13399,13404,13408],{"type":31,"tag":1904,"props":13370,"children":13371},{"style":1926},[13372],{"type":40,"value":12796},{"type":31,"tag":1904,"props":13374,"children":13375},{"style":2028},[13376],{"type":40,"value":13377},"(result",{"type":31,"tag":1904,"props":13379,"children":13380},{"style":2108},[13381],{"type":40,"value":76},{"type":31,"tag":1904,"props":13383,"children":13384},{"style":2028},[13385],{"type":40,"value":13386},"amount)",{"type":31,"tag":1904,"props":13388,"children":13389},{"style":2108},[13390],{"type":40,"value":76},{"type":31,"tag":1904,"props":13392,"children":13393},{"style":1926},[13394],{"type":40,"value":6086},{"type":31,"tag":1904,"props":13396,"children":13397},{"style":2028},[13398],{"type":40,"value":2490},{"type":31,"tag":1904,"props":13400,"children":13401},{"style":2039},[13402],{"type":40,"value":13403},"150",{"type":31,"tag":1904,"props":13405,"children":13406},{"style":2028},[13407],{"type":40,"value":1992},{"type":31,"tag":1904,"props":13409,"children":13410},{"style":1932},[13411],{"type":40,"value":2047},{"type":31,"tag":1904,"props":13413,"children":13414},{"class":1906,"line":2215},[13415,13419,13423,13427,13432,13436,13440,13444,13449,13453],{"type":31,"tag":1904,"props":13416,"children":13417},{"style":1926},[13418],{"type":40,"value":12796},{"type":31,"tag":1904,"props":13420,"children":13421},{"style":2028},[13422],{"type":40,"value":13377},{"type":31,"tag":1904,"props":13424,"children":13425},{"style":2108},[13426],{"type":40,"value":76},{"type":31,"tag":1904,"props":13428,"children":13429},{"style":2028},[13430],{"type":40,"value":13431},"currency)",{"type":31,"tag":1904,"props":13433,"children":13434},{"style":2108},[13435],{"type":40,"value":76},{"type":31,"tag":1904,"props":13437,"children":13438},{"style":1926},[13439],{"type":40,"value":6086},{"type":31,"tag":1904,"props":13441,"children":13442},{"style":2028},[13443],{"type":40,"value":2490},{"type":31,"tag":1904,"props":13445,"children":13446},{"style":3399},[13447],{"type":40,"value":13448},"'EUR'",{"type":31,"tag":1904,"props":13450,"children":13451},{"style":2028},[13452],{"type":40,"value":1992},{"type":31,"tag":1904,"props":13454,"children":13455},{"style":1932},[13456],{"type":40,"value":2047},{"type":31,"tag":1904,"props":13458,"children":13459},{"class":1906,"line":2236},[13460,13464,13468,13472,13477,13481,13485,13489,13494,13498],{"type":31,"tag":1904,"props":13461,"children":13462},{"style":1926},[13463],{"type":40,"value":12796},{"type":31,"tag":1904,"props":13465,"children":13466},{"style":2028},[13467],{"type":40,"value":13377},{"type":31,"tag":1904,"props":13469,"children":13470},{"style":2108},[13471],{"type":40,"value":76},{"type":31,"tag":1904,"props":13473,"children":13474},{"style":2028},[13475],{"type":40,"value":13476},"status)",{"type":31,"tag":1904,"props":13478,"children":13479},{"style":2108},[13480],{"type":40,"value":76},{"type":31,"tag":1904,"props":13482,"children":13483},{"style":1926},[13484],{"type":40,"value":6086},{"type":31,"tag":1904,"props":13486,"children":13487},{"style":2028},[13488],{"type":40,"value":2490},{"type":31,"tag":1904,"props":13490,"children":13491},{"style":3399},[13492],{"type":40,"value":13493},"'PENDING'",{"type":31,"tag":1904,"props":13495,"children":13496},{"style":2028},[13497],{"type":40,"value":1992},{"type":31,"tag":1904,"props":13499,"children":13500},{"style":1932},[13501],{"type":40,"value":2047},{"type":31,"tag":1904,"props":13503,"children":13504},{"class":1906,"line":2256},[13505,13509,13513],{"type":31,"tag":1904,"props":13506,"children":13507},{"style":1932},[13508],{"type":40,"value":5170},{"type":31,"tag":1904,"props":13510,"children":13511},{"style":2028},[13512],{"type":40,"value":1992},{"type":31,"tag":1904,"props":13514,"children":13515},{"style":1932},[13516],{"type":40,"value":2047},{"type":31,"tag":1904,"props":13518,"children":13519},{"class":1906,"line":2290},[13520,13524,13528],{"type":31,"tag":1904,"props":13521,"children":13522},{"style":1932},[13523],{"type":40,"value":4464},{"type":31,"tag":1904,"props":13525,"children":13526},{"style":2028},[13527],{"type":40,"value":1992},{"type":31,"tag":1904,"props":13529,"children":13530},{"style":1932},[13531],{"type":40,"value":2047},{"type":31,"tag":32,"props":13533,"children":13534},{},[13535,13537,13543],{"type":40,"value":13536},"L'implémentation peut changer, le test reste valable. C'est exactement la philosophie défendue dans ",{"type":31,"tag":69,"props":13538,"children":13540},{"href":13539},"/fr/pratiques-agiles/adopter-behaviour-driven-development-bdd-guide-agile",[13541],{"type":40,"value":13542},"l'adoption du Behaviour-Driven Development",{"type":40,"value":13544}," et dans la Definition of Done bien posée.",{"type":31,"tag":32,"props":13546,"children":13547},{},[13548],{"type":40,"value":13549},"Sur crmcoaching, après avoir appliqué ce changement systématiquement, le ratio de tests \"behavior-level\" est passé de 15% à 70%. La couverture brute a parfois baissé. La couverture utile a triplé.",{"type":31,"tag":48,"props":13551,"children":13552},{},[],{"type":31,"tag":52,"props":13554,"children":13556},{"id":13555},"pattern-4-catch-all-silencieux",[13557],{"type":40,"value":13558},"Pattern #4 : catch-all silencieux",{"type":31,"tag":32,"props":13560,"children":13561},{},[13562],{"type":40,"value":13563},"C'est le pattern le plus dangereux, parce qu'il masque les bugs au lieu de les révéler. Claude écrit volontiers :",{"type":31,"tag":1894,"props":13565,"children":13567},{"className":1896,"code":13566,"language":1898,"meta":8,"style":8},"// apps/api/src/infrastructure/adapters/brevo-notification.adapter.ts\n\nasync sendSlotConfirmation(clientEmail: string, slotId: string): Promise\u003Cvoid> {\n  try {\n    await this.brevoService.sendTransactionalEmail({\n      to: [{ email: clientEmail }],\n      templateId: 12,\n      params: { slotId },\n    });\n  } catch (e) {\n    console.error('notification failed', e);\n    // la suite s'exécute comme si tout allait bien\n  }\n}\n",[13568],{"type":31,"tag":169,"props":13569,"children":13570},{"__ignoreMap":8},[13571,13579,13586,13627,13639,13674,13718,13737,13760,13775,13787,13825,13833,13840],{"type":31,"tag":1904,"props":13572,"children":13573},{"class":1906,"line":1907},[13574],{"type":31,"tag":1904,"props":13575,"children":13576},{"style":1911},[13577],{"type":40,"value":13578},"// apps/api/src/infrastructure/adapters/brevo-notification.adapter.ts\n",{"type":31,"tag":1904,"props":13580,"children":13581},{"class":1906,"line":817},[13582],{"type":31,"tag":1904,"props":13583,"children":13584},{"emptyLinePlaceholder":13},[13585],{"type":40,"value":2165},{"type":31,"tag":1904,"props":13587,"children":13588},{"class":1906,"line":1938},[13589,13594,13599,13604,13608,13613,13618,13623],{"type":31,"tag":1904,"props":13590,"children":13591},{"style":2028},[13592],{"type":40,"value":13593},"async ",{"type":31,"tag":1904,"props":13595,"children":13596},{"style":1926},[13597],{"type":40,"value":13598},"sendSlotConfirmation",{"type":31,"tag":1904,"props":13600,"children":13601},{"style":2028},[13602],{"type":40,"value":13603},"(clientEmail: string",{"type":31,"tag":1904,"props":13605,"children":13606},{"style":1932},[13607],{"type":40,"value":4853},{"type":31,"tag":1904,"props":13609,"children":13610},{"style":2028},[13611],{"type":40,"value":13612}," slotId: string): ",{"type":31,"tag":1904,"props":13614,"children":13615},{"style":5264},[13616],{"type":40,"value":13617},"Promise",{"type":31,"tag":1904,"props":13619,"children":13620},{"style":1948},[13621],{"type":40,"value":13622},"\u003Cvoid>",{"type":31,"tag":1904,"props":13624,"children":13625},{"style":1932},[13626],{"type":40,"value":2005},{"type":31,"tag":1904,"props":13628,"children":13629},{"class":1906,"line":1965},[13630,13635],{"type":31,"tag":1904,"props":13631,"children":13632},{"style":2028},[13633],{"type":40,"value":13634},"  try ",{"type":31,"tag":1904,"props":13636,"children":13637},{"style":1932},[13638],{"type":40,"value":3264},{"type":31,"tag":1904,"props":13640,"children":13641},{"class":1906,"line":1986},[13642,13646,13650,13654,13658,13662,13666,13670],{"type":31,"tag":1904,"props":13643,"children":13644},{"style":1920},[13645],{"type":40,"value":3313},{"type":31,"tag":1904,"props":13647,"children":13648},{"style":3197},[13649],{"type":40,"value":3200},{"type":31,"tag":1904,"props":13651,"children":13652},{"style":2108},[13653],{"type":40,"value":76},{"type":31,"tag":1904,"props":13655,"children":13656},{"style":2028},[13657],{"type":40,"value":10613},{"type":31,"tag":1904,"props":13659,"children":13660},{"style":2108},[13661],{"type":40,"value":76},{"type":31,"tag":1904,"props":13663,"children":13664},{"style":1926},[13665],{"type":40,"value":4513},{"type":31,"tag":1904,"props":13667,"children":13668},{"style":2028},[13669],{"type":40,"value":2490},{"type":31,"tag":1904,"props":13671,"children":13672},{"style":1932},[13673],{"type":40,"value":3264},{"type":31,"tag":1904,"props":13675,"children":13676},{"class":1906,"line":2008},[13677,13681,13685,13689,13693,13697,13701,13706,13710,13714],{"type":31,"tag":1904,"props":13678,"children":13679},{"style":2028},[13680],{"type":40,"value":4529},{"type":31,"tag":1904,"props":13682,"children":13683},{"style":2108},[13684],{"type":40,"value":1951},{"type":31,"tag":1904,"props":13686,"children":13687},{"style":2028},[13688],{"type":40,"value":4538},{"type":31,"tag":1904,"props":13690,"children":13691},{"style":1932},[13692],{"type":40,"value":4543},{"type":31,"tag":1904,"props":13694,"children":13695},{"style":2028},[13696],{"type":40,"value":4548},{"type":31,"tag":1904,"props":13698,"children":13699},{"style":2108},[13700],{"type":40,"value":1951},{"type":31,"tag":1904,"props":13702,"children":13703},{"style":2028},[13704],{"type":40,"value":13705}," clientEmail ",{"type":31,"tag":1904,"props":13707,"children":13708},{"style":1932},[13709],{"type":40,"value":4464},{"type":31,"tag":1904,"props":13711,"children":13712},{"style":2028},[13713],{"type":40,"value":4574},{"type":31,"tag":1904,"props":13715,"children":13716},{"style":1932},[13717],{"type":40,"value":1962},{"type":31,"tag":1904,"props":13719,"children":13720},{"class":1906,"line":2050},[13721,13725,13729,13733],{"type":31,"tag":1904,"props":13722,"children":13723},{"style":2028},[13724],{"type":40,"value":4586},{"type":31,"tag":1904,"props":13726,"children":13727},{"style":2108},[13728],{"type":40,"value":1951},{"type":31,"tag":1904,"props":13730,"children":13731},{"style":2039},[13732],{"type":40,"value":2042},{"type":31,"tag":1904,"props":13734,"children":13735},{"style":1932},[13736],{"type":40,"value":1962},{"type":31,"tag":1904,"props":13738,"children":13739},{"class":1906,"line":2094},[13740,13744,13748,13752,13756],{"type":31,"tag":1904,"props":13741,"children":13742},{"style":2028},[13743],{"type":40,"value":4616},{"type":31,"tag":1904,"props":13745,"children":13746},{"style":2108},[13747],{"type":40,"value":1951},{"type":31,"tag":1904,"props":13749,"children":13750},{"style":1932},[13751],{"type":40,"value":4625},{"type":31,"tag":1904,"props":13753,"children":13754},{"style":2028},[13755],{"type":40,"value":11776},{"type":31,"tag":1904,"props":13757,"children":13758},{"style":1932},[13759],{"type":40,"value":4652},{"type":31,"tag":1904,"props":13761,"children":13762},{"class":1906,"line":2150},[13763,13767,13771],{"type":31,"tag":1904,"props":13764,"children":13765},{"style":1932},[13766],{"type":40,"value":4660},{"type":31,"tag":1904,"props":13768,"children":13769},{"style":2028},[13770],{"type":40,"value":1992},{"type":31,"tag":1904,"props":13772,"children":13773},{"style":1932},[13774],{"type":40,"value":2047},{"type":31,"tag":1904,"props":13776,"children":13777},{"class":1906,"line":2159},[13778,13782],{"type":31,"tag":1904,"props":13779,"children":13780},{"style":1932},[13781],{"type":40,"value":5170},{"type":31,"tag":1904,"props":13783,"children":13784},{"style":2028},[13785],{"type":40,"value":13786}," catch (e) {\n",{"type":31,"tag":1904,"props":13788,"children":13789},{"class":1906,"line":2168},[13790,13795,13799,13803,13808,13812,13817,13821],{"type":31,"tag":1904,"props":13791,"children":13792},{"style":2028},[13793],{"type":40,"value":13794},"    console.",{"type":31,"tag":1904,"props":13796,"children":13797},{"style":1926},[13798],{"type":40,"value":8585},{"type":31,"tag":1904,"props":13800,"children":13801},{"style":1932},[13802],{"type":40,"value":2490},{"type":31,"tag":1904,"props":13804,"children":13805},{"style":3399},[13806],{"type":40,"value":13807},"'notification failed'",{"type":31,"tag":1904,"props":13809,"children":13810},{"style":1932},[13811],{"type":40,"value":4853},{"type":31,"tag":1904,"props":13813,"children":13814},{"style":1942},[13815],{"type":40,"value":13816}," e",{"type":31,"tag":1904,"props":13818,"children":13819},{"style":1932},[13820],{"type":40,"value":1992},{"type":31,"tag":1904,"props":13822,"children":13823},{"style":2028},[13824],{"type":40,"value":2047},{"type":31,"tag":1904,"props":13826,"children":13827},{"class":1906,"line":2177},[13828],{"type":31,"tag":1904,"props":13829,"children":13830},{"style":1911},[13831],{"type":40,"value":13832},"    // la suite s'exécute comme si tout allait bien\n",{"type":31,"tag":1904,"props":13834,"children":13835},{"class":1906,"line":2194},[13836],{"type":31,"tag":1904,"props":13837,"children":13838},{"style":1932},[13839],{"type":40,"value":2717},{"type":31,"tag":1904,"props":13841,"children":13842},{"class":1906,"line":2215},[13843],{"type":31,"tag":1904,"props":13844,"children":13845},{"style":2028},[13846],{"type":40,"value":2156},{"type":31,"tag":32,"props":13848,"children":13849},{},[13850,13852,13858],{"type":40,"value":13851},"Et la suite du code continue normalement. Le slot a-t-il été confirmé par email ? On ne sait pas. Le ",{"type":31,"tag":169,"props":13853,"children":13855},{"className":13854},[],[13856],{"type":40,"value":13857},"console.error",{"type":40,"value":13859}," est-il regardé par quelqu'un en prod ? Probablement pas. Le client voit \"Réservation confirmée\" alors que Brevo n'a rien envoyé.",{"type":31,"tag":32,"props":13861,"children":13862},{},[13863,13865,13871,13873,13879],{"type":40,"value":13864},"Le contre-pattern craft repose sur trois règles. D'abord, ne jamais avaler une exception sans politique explicite : soit on re-throw, soit on dégrade volontairement (tracé dans une métrique), soit on rollback. Ensuite, ne jamais utiliser ",{"type":31,"tag":169,"props":13866,"children":13868},{"className":13867},[],[13869],{"type":40,"value":13870},"catch (e)",{"type":40,"value":13872}," générique sans typer l'exception attendue : une erreur réseau Brevo ne se traite pas comme une ",{"type":31,"tag":169,"props":13874,"children":13876},{"className":13875},[],[13877],{"type":40,"value":13878},"DomainException",{"type":40,"value":13880},". Enfin, instrumenter chaque catch avec une métrique ou une alerte :",{"type":31,"tag":1894,"props":13882,"children":13884},{"className":1896,"code":13883,"language":1898,"meta":8,"style":8},"async sendSlotConfirmation(clientEmail: string, slotId: string): Promise\u003Cvoid> {\n  try {\n    await this.brevoService.sendTransactionalEmail({\n      to: [{ email: clientEmail }],\n      templateId: 12,\n      params: { slotId },\n    });\n  } catch (err) {\n    this.logger.error('brevo.slot_confirmation.failed', {\n      clientEmail,\n      slotId,\n      error: err instanceof Error ? err.message : String(err),\n    });\n    this.metricsService.increment('notification_failures_total', { type: 'slot_confirmation' });\n    throw new NotificationDeliveryException(`Confirmation slot ${slotId} non envoyée`);\n  }\n}\n",[13885],{"type":31,"tag":169,"props":13886,"children":13887},{"__ignoreMap":8},[13888,13923,13934,13969,14012,14031,14054,14069,14081,14110,14122,14134,14195,14207,14252,14299,14306],{"type":31,"tag":1904,"props":13889,"children":13890},{"class":1906,"line":1907},[13891,13895,13899,13903,13907,13911,13915,13919],{"type":31,"tag":1904,"props":13892,"children":13893},{"style":2028},[13894],{"type":40,"value":13593},{"type":31,"tag":1904,"props":13896,"children":13897},{"style":1926},[13898],{"type":40,"value":13598},{"type":31,"tag":1904,"props":13900,"children":13901},{"style":2028},[13902],{"type":40,"value":13603},{"type":31,"tag":1904,"props":13904,"children":13905},{"style":1932},[13906],{"type":40,"value":4853},{"type":31,"tag":1904,"props":13908,"children":13909},{"style":2028},[13910],{"type":40,"value":13612},{"type":31,"tag":1904,"props":13912,"children":13913},{"style":5264},[13914],{"type":40,"value":13617},{"type":31,"tag":1904,"props":13916,"children":13917},{"style":1948},[13918],{"type":40,"value":13622},{"type":31,"tag":1904,"props":13920,"children":13921},{"style":1932},[13922],{"type":40,"value":2005},{"type":31,"tag":1904,"props":13924,"children":13925},{"class":1906,"line":817},[13926,13930],{"type":31,"tag":1904,"props":13927,"children":13928},{"style":2028},[13929],{"type":40,"value":13634},{"type":31,"tag":1904,"props":13931,"children":13932},{"style":1932},[13933],{"type":40,"value":3264},{"type":31,"tag":1904,"props":13935,"children":13936},{"class":1906,"line":1938},[13937,13941,13945,13949,13953,13957,13961,13965],{"type":31,"tag":1904,"props":13938,"children":13939},{"style":1920},[13940],{"type":40,"value":3313},{"type":31,"tag":1904,"props":13942,"children":13943},{"style":3197},[13944],{"type":40,"value":3200},{"type":31,"tag":1904,"props":13946,"children":13947},{"style":2108},[13948],{"type":40,"value":76},{"type":31,"tag":1904,"props":13950,"children":13951},{"style":2028},[13952],{"type":40,"value":10613},{"type":31,"tag":1904,"props":13954,"children":13955},{"style":2108},[13956],{"type":40,"value":76},{"type":31,"tag":1904,"props":13958,"children":13959},{"style":1926},[13960],{"type":40,"value":4513},{"type":31,"tag":1904,"props":13962,"children":13963},{"style":2028},[13964],{"type":40,"value":2490},{"type":31,"tag":1904,"props":13966,"children":13967},{"style":1932},[13968],{"type":40,"value":3264},{"type":31,"tag":1904,"props":13970,"children":13971},{"class":1906,"line":1965},[13972,13976,13980,13984,13988,13992,13996,14000,14004,14008],{"type":31,"tag":1904,"props":13973,"children":13974},{"style":2028},[13975],{"type":40,"value":4529},{"type":31,"tag":1904,"props":13977,"children":13978},{"style":2108},[13979],{"type":40,"value":1951},{"type":31,"tag":1904,"props":13981,"children":13982},{"style":2028},[13983],{"type":40,"value":4538},{"type":31,"tag":1904,"props":13985,"children":13986},{"style":1932},[13987],{"type":40,"value":4543},{"type":31,"tag":1904,"props":13989,"children":13990},{"style":2028},[13991],{"type":40,"value":4548},{"type":31,"tag":1904,"props":13993,"children":13994},{"style":2108},[13995],{"type":40,"value":1951},{"type":31,"tag":1904,"props":13997,"children":13998},{"style":2028},[13999],{"type":40,"value":13705},{"type":31,"tag":1904,"props":14001,"children":14002},{"style":1932},[14003],{"type":40,"value":4464},{"type":31,"tag":1904,"props":14005,"children":14006},{"style":2028},[14007],{"type":40,"value":4574},{"type":31,"tag":1904,"props":14009,"children":14010},{"style":1932},[14011],{"type":40,"value":1962},{"type":31,"tag":1904,"props":14013,"children":14014},{"class":1906,"line":1986},[14015,14019,14023,14027],{"type":31,"tag":1904,"props":14016,"children":14017},{"style":2028},[14018],{"type":40,"value":4586},{"type":31,"tag":1904,"props":14020,"children":14021},{"style":2108},[14022],{"type":40,"value":1951},{"type":31,"tag":1904,"props":14024,"children":14025},{"style":2039},[14026],{"type":40,"value":2042},{"type":31,"tag":1904,"props":14028,"children":14029},{"style":1932},[14030],{"type":40,"value":1962},{"type":31,"tag":1904,"props":14032,"children":14033},{"class":1906,"line":2008},[14034,14038,14042,14046,14050],{"type":31,"tag":1904,"props":14035,"children":14036},{"style":2028},[14037],{"type":40,"value":4616},{"type":31,"tag":1904,"props":14039,"children":14040},{"style":2108},[14041],{"type":40,"value":1951},{"type":31,"tag":1904,"props":14043,"children":14044},{"style":1932},[14045],{"type":40,"value":4625},{"type":31,"tag":1904,"props":14047,"children":14048},{"style":2028},[14049],{"type":40,"value":11776},{"type":31,"tag":1904,"props":14051,"children":14052},{"style":1932},[14053],{"type":40,"value":4652},{"type":31,"tag":1904,"props":14055,"children":14056},{"class":1906,"line":2050},[14057,14061,14065],{"type":31,"tag":1904,"props":14058,"children":14059},{"style":1932},[14060],{"type":40,"value":4660},{"type":31,"tag":1904,"props":14062,"children":14063},{"style":2028},[14064],{"type":40,"value":1992},{"type":31,"tag":1904,"props":14066,"children":14067},{"style":1932},[14068],{"type":40,"value":2047},{"type":31,"tag":1904,"props":14070,"children":14071},{"class":1906,"line":2094},[14072,14076],{"type":31,"tag":1904,"props":14073,"children":14074},{"style":1932},[14075],{"type":40,"value":5170},{"type":31,"tag":1904,"props":14077,"children":14078},{"style":2028},[14079],{"type":40,"value":14080}," catch (err) {\n",{"type":31,"tag":1904,"props":14082,"children":14083},{"class":1906,"line":2150},[14084,14089,14093,14097,14102,14106],{"type":31,"tag":1904,"props":14085,"children":14086},{"style":2028},[14087],{"type":40,"value":14088},"    this.logger.",{"type":31,"tag":1904,"props":14090,"children":14091},{"style":1926},[14092],{"type":40,"value":8585},{"type":31,"tag":1904,"props":14094,"children":14095},{"style":1932},[14096],{"type":40,"value":2490},{"type":31,"tag":1904,"props":14098,"children":14099},{"style":3399},[14100],{"type":40,"value":14101},"'brevo.slot_confirmation.failed'",{"type":31,"tag":1904,"props":14103,"children":14104},{"style":1932},[14105],{"type":40,"value":4853},{"type":31,"tag":1904,"props":14107,"children":14108},{"style":1932},[14109],{"type":40,"value":2005},{"type":31,"tag":1904,"props":14111,"children":14112},{"class":1906,"line":2159},[14113,14118],{"type":31,"tag":1904,"props":14114,"children":14115},{"style":1942},[14116],{"type":40,"value":14117},"      clientEmail",{"type":31,"tag":1904,"props":14119,"children":14120},{"style":1932},[14121],{"type":40,"value":1962},{"type":31,"tag":1904,"props":14123,"children":14124},{"class":1906,"line":2168},[14125,14130],{"type":31,"tag":1904,"props":14126,"children":14127},{"style":1942},[14128],{"type":40,"value":14129},"      slotId",{"type":31,"tag":1904,"props":14131,"children":14132},{"style":1932},[14133],{"type":40,"value":1962},{"type":31,"tag":1904,"props":14135,"children":14136},{"class":1906,"line":2177},[14137,14142,14146,14150,14155,14159,14164,14168,14172,14177,14181,14186,14191],{"type":31,"tag":1904,"props":14138,"children":14139},{"style":5931},[14140],{"type":40,"value":14141},"      error",{"type":31,"tag":1904,"props":14143,"children":14144},{"style":1932},[14145],{"type":40,"value":1951},{"type":31,"tag":1904,"props":14147,"children":14148},{"style":1942},[14149],{"type":40,"value":5885},{"type":31,"tag":1904,"props":14151,"children":14152},{"style":1942},[14153],{"type":40,"value":14154}," instanceof",{"type":31,"tag":1904,"props":14156,"children":14157},{"style":1942},[14158],{"type":40,"value":4440},{"type":31,"tag":1904,"props":14160,"children":14161},{"style":2028},[14162],{"type":40,"value":14163}," ? ",{"type":31,"tag":1904,"props":14165,"children":14166},{"style":1942},[14167],{"type":40,"value":8163},{"type":31,"tag":1904,"props":14169,"children":14170},{"style":2028},[14171],{"type":40,"value":76},{"type":31,"tag":1904,"props":14173,"children":14174},{"style":5931},[14175],{"type":40,"value":14176},"message",{"type":31,"tag":1904,"props":14178,"children":14179},{"style":1932},[14180],{"type":40,"value":2696},{"type":31,"tag":1904,"props":14182,"children":14183},{"style":1942},[14184],{"type":40,"value":14185}," String",{"type":31,"tag":1904,"props":14187,"children":14188},{"style":2028},[14189],{"type":40,"value":14190},"(err)",{"type":31,"tag":1904,"props":14192,"children":14193},{"style":1932},[14194],{"type":40,"value":1962},{"type":31,"tag":1904,"props":14196,"children":14197},{"class":1906,"line":2194},[14198,14203],{"type":31,"tag":1904,"props":14199,"children":14200},{"style":1932},[14201],{"type":40,"value":14202},"    })",{"type":31,"tag":1904,"props":14204,"children":14205},{"style":2028},[14206],{"type":40,"value":2047},{"type":31,"tag":1904,"props":14208,"children":14209},{"class":1906,"line":2215},[14210,14215,14220,14224,14228,14234,14238,14243,14247],{"type":31,"tag":1904,"props":14211,"children":14212},{"style":2028},[14213],{"type":40,"value":14214},"    this.metricsService.increment(",{"type":31,"tag":1904,"props":14216,"children":14217},{"style":3399},[14218],{"type":40,"value":14219},"'notification_failures_total'",{"type":31,"tag":1904,"props":14221,"children":14222},{"style":1932},[14223],{"type":40,"value":4853},{"type":31,"tag":1904,"props":14225,"children":14226},{"style":1932},[14227],{"type":40,"value":4625},{"type":31,"tag":1904,"props":14229,"children":14231},{"style":14230},"--shiki-default:#C6D0F5;--shiki-dark:#B392F0",[14232],{"type":40,"value":14233}," type",{"type":31,"tag":1904,"props":14235,"children":14236},{"style":1932},[14237],{"type":40,"value":1951},{"type":31,"tag":1904,"props":14239,"children":14240},{"style":3399},[14241],{"type":40,"value":14242}," 'slot_confirmation'",{"type":31,"tag":1904,"props":14244,"children":14245},{"style":1932},[14246],{"type":40,"value":6488},{"type":31,"tag":1904,"props":14248,"children":14249},{"style":2028},[14250],{"type":40,"value":14251},");\n",{"type":31,"tag":1904,"props":14253,"children":14254},{"class":1906,"line":2236},[14255,14260,14265,14269,14274,14278,14282,14286,14291,14295],{"type":31,"tag":1904,"props":14256,"children":14257},{"style":2028},[14258],{"type":40,"value":14259},"    throw new ",{"type":31,"tag":1904,"props":14261,"children":14262},{"style":1926},[14263],{"type":40,"value":14264},"NotificationDeliveryException",{"type":31,"tag":1904,"props":14266,"children":14267},{"style":1932},[14268],{"type":40,"value":2490},{"type":31,"tag":1904,"props":14270,"children":14271},{"style":3399},[14272],{"type":40,"value":14273},"`Confirmation slot ",{"type":31,"tag":1904,"props":14275,"children":14276},{"style":4452},[14277],{"type":40,"value":4455},{"type":31,"tag":1904,"props":14279,"children":14280},{"style":2028},[14281],{"type":40,"value":11484},{"type":31,"tag":1904,"props":14283,"children":14284},{"style":4452},[14285],{"type":40,"value":4464},{"type":31,"tag":1904,"props":14287,"children":14288},{"style":3399},[14289],{"type":40,"value":14290}," non envoyée`",{"type":31,"tag":1904,"props":14292,"children":14293},{"style":1932},[14294],{"type":40,"value":1992},{"type":31,"tag":1904,"props":14296,"children":14297},{"style":2028},[14298],{"type":40,"value":2047},{"type":31,"tag":1904,"props":14300,"children":14301},{"class":1906,"line":2256},[14302],{"type":31,"tag":1904,"props":14303,"children":14304},{"style":1932},[14305],{"type":40,"value":2717},{"type":31,"tag":1904,"props":14307,"children":14308},{"class":1906,"line":2290},[14309],{"type":31,"tag":1904,"props":14310,"children":14311},{"style":2028},[14312],{"type":40,"value":2156},{"type":31,"tag":32,"props":14314,"children":14315},{},[14316,14318,14322,14324,14329],{"type":40,"value":14317},"Michael Nygard a documenté ce sujet en profondeur dans ",{"type":31,"tag":97,"props":14319,"children":14320},{},[14321],{"type":40,"value":790},{"type":40,"value":14323}," (2007). Les ",{"type":31,"tag":69,"props":14325,"children":14326},{"href":8768},[14327],{"type":40,"value":14328},"patterns de résilience type circuit breaker et retry",{"type":40,"value":14330}," n'ont de sens que si les erreurs sont visibles. Un catch-all silencieux casse toute la stratégie de résilience en amont.",{"type":31,"tag":48,"props":14332,"children":14333},{},[],{"type":31,"tag":52,"props":14335,"children":14337},{"id":14336},"pattern-5-dépendances-non-auditées",[14338],{"type":40,"value":14339},"Pattern #5 : dépendances non auditées",{"type":31,"tag":32,"props":14341,"children":14342},{},[14343,14345,14351,14353,14359,14361,14367,14369,14375],{"type":40,"value":14344},"Le dernier pattern est le plus invisible. Claude propose une dépendance pour résoudre un problème : \"Ajoute ",{"type":31,"tag":169,"props":14346,"children":14348},{"className":14347},[],[14349],{"type":40,"value":14350},"stripe",{"type":40,"value":14352}," pour les checkouts\", \"Utilise ",{"type":31,"tag":169,"props":14354,"children":14356},{"className":14355},[],[14357],{"type":40,"value":14358},"jose",{"type":40,"value":14360}," pour signer ce token\", \"Importe ",{"type":31,"tag":169,"props":14362,"children":14364},{"className":14363},[],[14365],{"type":40,"value":14366},"date-fns",{"type":40,"value":14368}," pour ce calcul de durée\". Le développeur lance ",{"type":31,"tag":169,"props":14370,"children":14372},{"className":14371},[],[14373],{"type":40,"value":14374},"pnpm add \u003Cpkg>",{"type":40,"value":14376},", ça compile, ça passe les tests, ça merge. Et l'artefact entre dans le repo, sans audit, sans justification.",{"type":31,"tag":32,"props":14378,"children":14379},{},[14380,14382,14388],{"type":40,"value":14381},"Le problème, ce sont les chiffres du Snyk Open Source Security Report 2024 : les attaques sur la supply chain ont augmenté de 156% en un an. Les écosystèmes les plus touchés incluent npm, PyPI et Maven Central, précisément ceux que Claude suggère le plus. Sur le cas xz-utils (CVE-2024-3094, mars 2024), une backdoor s'est glissée pendant 2 ans dans un package que tout le monde utilisait sans relire. Le sujet de fond est traité dans ",{"type":31,"tag":69,"props":14383,"children":14385},{"href":14384},"/fr/intelligence-artificielle/llm-securite-code-vulnerabilites",[14386],{"type":40,"value":14387},"les vulnérabilités de sécurité dans le code LLM-généré",{"type":40,"value":76},{"type":31,"tag":32,"props":14390,"children":14391},{},[14392,14394,14400,14402,14407],{"type":40,"value":14393},"Le contre-pattern craft repose sur 3 réflexes. D'abord, refuser toute nouvelle dépendance qui n'a pas été justifiée par un commentaire de PR (quelle alternative native Node ? quel score de vulnérabilités npm audit ? combien de mainteneurs actifs ?). Ensuite, mesurer la ",{"type":31,"tag":169,"props":14395,"children":14397},{"className":14396},[],[14398],{"type":40,"value":14399},"time-to-patch",{"type":40,"value":14401}," sur les CVE critiques (en dessous de 7 jours = sain). Enfin, automatiser la veille via ",{"type":31,"tag":69,"props":14403,"children":14404},{"href":364},[14405],{"type":40,"value":14406},"Dependabot configuré craft",{"type":40,"value":14408}," avec auto-merge sur les patches et review humaine sur les majors.",{"type":31,"tag":32,"props":14410,"children":14411},{},[14412,14414,14420],{"type":40,"value":14413},"Sur crmcoaching, j'audite chaque dépendance que Claude propose. Je vérifie le nombre de mainteneurs, la date du dernier commit, le score ",{"type":31,"tag":169,"props":14415,"children":14417},{"className":14416},[],[14418],{"type":40,"value":14419},"pnpm audit",{"type":40,"value":14421},". 30 secondes par dépendance. C'est ce qui fait la différence entre un repo sain et un repo qui exfiltre des données dans 2 ans.",{"type":31,"tag":48,"props":14423,"children":14424},{},[],{"type":31,"tag":52,"props":14426,"children":14428},{"id":14427},"les-5-garde-fous-craft-à-installer-dès-lundi",[14429],{"type":40,"value":14430},"Les 5 garde-fous craft à installer dès lundi",{"type":31,"tag":32,"props":14432,"children":14433},{},[14434],{"type":40,"value":14435},"Voici la grille condensée. Mettez-la en checklist GitHub PR template.",{"type":31,"tag":398,"props":14437,"children":14438},{},[14439,14459],{"type":31,"tag":402,"props":14440,"children":14441},{},[14442],{"type":31,"tag":406,"props":14443,"children":14444},{},[14445,14450,14455],{"type":31,"tag":410,"props":14446,"children":14447},{},[14448],{"type":40,"value":14449},"Pattern",{"type":31,"tag":410,"props":14451,"children":14452},{},[14453],{"type":40,"value":14454},"Signal en review",{"type":31,"tag":410,"props":14456,"children":14457},{},[14458],{"type":40,"value":424},{"type":31,"tag":426,"props":14460,"children":14461},{},[14462,14478,14517,14540,14562],{"type":31,"tag":406,"props":14463,"children":14464},{},[14465,14469,14474],{"type":31,"tag":433,"props":14466,"children":14467},{},[14468],{"type":40,"value":455},{"type":31,"tag":433,"props":14470,"children":14471},{},[14472],{"type":40,"value":14473},"Fonction > 40 lignes ou > 3 niveaux d'indentation",{"type":31,"tag":433,"props":14475,"children":14476},{},[14477],{"type":40,"value":465},{"type":31,"tag":406,"props":14479,"children":14480},{},[14481,14485,14507],{"type":31,"tag":433,"props":14482,"children":14483},{},[14484],{"type":40,"value":473},{"type":31,"tag":433,"props":14486,"children":14487},{},[14488,14493,14495,14501,14502],{"type":31,"tag":169,"props":14489,"children":14491},{"className":14490},[],[14492],{"type":40,"value":11324},{"type":40,"value":14494}," injecté dans ",{"type":31,"tag":169,"props":14496,"children":14498},{"className":14497},[],[14499],{"type":40,"value":14500},"application/",{"type":40,"value":4801},{"type":31,"tag":169,"props":14503,"children":14505},{"className":14504},[],[14506],{"type":40,"value":484},{"type":31,"tag":433,"props":14508,"children":14509},{},[14510,14512],{"type":40,"value":14511},"Interface Repository (port), adapter Prisma en ",{"type":31,"tag":169,"props":14513,"children":14515},{"className":14514},[],[14516],{"type":40,"value":11922},{"type":31,"tag":406,"props":14518,"children":14519},{},[14520,14524,14535],{"type":31,"tag":433,"props":14521,"children":14522},{},[14523],{"type":40,"value":497},{"type":31,"tag":433,"props":14525,"children":14526},{},[14527,14533],{"type":31,"tag":169,"props":14528,"children":14530},{"className":14529},[],[14531],{"type":40,"value":14532},"expect(repo.save).toHaveBeenCalled()",{"type":40,"value":14534}," sans assertion comportementale",{"type":31,"tag":433,"props":14536,"children":14537},{},[14538],{"type":40,"value":14539},"Format Given/When/Then sur comportement observable",{"type":31,"tag":406,"props":14541,"children":14542},{},[14543,14547,14557],{"type":31,"tag":433,"props":14544,"children":14545},{},[14546],{"type":40,"value":520},{"type":31,"tag":433,"props":14548,"children":14549},{},[14550,14556],{"type":31,"tag":169,"props":14551,"children":14553},{"className":14552},[],[14554],{"type":40,"value":14555},"catch (e) { console.error(e) }",{"type":40,"value":531},{"type":31,"tag":433,"props":14558,"children":14559},{},[14560],{"type":40,"value":14561},"Re-throw typé, métrique, ou rollback",{"type":31,"tag":406,"props":14563,"children":14564},{},[14565,14570,14583],{"type":31,"tag":433,"props":14566,"children":14567},{},[14568],{"type":40,"value":14569},"Dépendance non auditée",{"type":31,"tag":433,"props":14571,"children":14572},{},[14573,14575,14581],{"type":40,"value":14574},"Entrée ",{"type":31,"tag":169,"props":14576,"children":14578},{"className":14577},[],[14579],{"type":40,"value":14580},"package.json",{"type":40,"value":14582}," sans commentaire de justification",{"type":31,"tag":433,"props":14584,"children":14585},{},[14586,14588,14593],{"type":40,"value":14587},"Audit 30 sec (",{"type":31,"tag":169,"props":14589,"children":14591},{"className":14590},[],[14592],{"type":40,"value":14419},{"type":40,"value":14594},") + Dependabot configuré craft",{"type":31,"tag":32,"props":14596,"children":14597},{},[14598],{"type":40,"value":14599},"Cette grille tient en 5 minutes par PR. Elle attrape 80% des patterns dangereux que j'ai vus en construisant crmcoaching et lors de mes accompagnements. Elle s'inscrit naturellement dans la philosophie Boy Scout Rule : on laisse le code un peu mieux qu'on l'a trouvé, à chaque PR.",{"type":31,"tag":48,"props":14601,"children":14602},{},[],{"type":31,"tag":229,"props":14604,"children":14606},{"cta":231,"href":232,"title":14605,"type":234},"Vous voulez voir ces patterns dans une PR Claude avant qu'ils ne deviennent de la dette ?",[14607],{"type":31,"tag":32,"props":14608,"children":14609},{},[14610],{"type":40,"value":14611},"Repérer une God Function ou un catch-all silencieux dans une suggestion de Claude, ça ne s'apprend pas en lisant un article : ça se travaille. En mentoring 1:1, je relis votre code avec vous, on rejoue vos prompts, et on installe ensemble le réflexe de review qui transforme Claude en exécutant discipliné. Vous repartez en voyant ce que le modèle ne voit pas.",{"type":31,"tag":48,"props":14613,"children":14614},{},[],{"type":31,"tag":52,"props":14616,"children":14617},{"id":1463},[14618],{"type":40,"value":1466},{"type":31,"tag":32,"props":14620,"children":14621},{},[14622],{"type":40,"value":14623},"Sur crmcoaching, après avoir installé cette grille et appliqué une vraie discipline de code review, voici les chiffres avant/après mesurés sur 6 mois.",{"type":31,"tag":398,"props":14625,"children":14626},{},[14627,14646],{"type":31,"tag":402,"props":14628,"children":14629},{},[14630],{"type":31,"tag":406,"props":14631,"children":14632},{},[14633,14637,14642],{"type":31,"tag":410,"props":14634,"children":14635},{},[14636],{"type":40,"value":1198},{"type":31,"tag":410,"props":14638,"children":14639},{},[14640],{"type":40,"value":14641},"Avant grille",{"type":31,"tag":410,"props":14643,"children":14644},{},[14645],{"type":40,"value":3735},{"type":31,"tag":426,"props":14647,"children":14648},{},[14649,14667,14685,14702,14720],{"type":31,"tag":406,"props":14650,"children":14651},{},[14652,14657,14662],{"type":31,"tag":433,"props":14653,"children":14654},{},[14655],{"type":40,"value":14656},"Fonctions > 40 lignes dans le repo",{"type":31,"tag":433,"props":14658,"children":14659},{},[14660],{"type":40,"value":14661},"22% des fonctions",{"type":31,"tag":433,"props":14663,"children":14664},{},[14665],{"type":40,"value":14666},"4% des fonctions",{"type":31,"tag":406,"props":14668,"children":14669},{},[14670,14675,14680],{"type":31,"tag":433,"props":14671,"children":14672},{},[14673],{"type":40,"value":14674},"Couverture de tests behavior-level",{"type":31,"tag":433,"props":14676,"children":14677},{},[14678],{"type":40,"value":14679},"15%",{"type":31,"tag":433,"props":14681,"children":14682},{},[14683],{"type":40,"value":14684},"70%",{"type":31,"tag":406,"props":14686,"children":14687},{},[14688,14693,14698],{"type":31,"tag":433,"props":14689,"children":14690},{},[14691],{"type":40,"value":14692},"Incidents prod liés à exception swallowed",{"type":31,"tag":433,"props":14694,"children":14695},{},[14696],{"type":40,"value":14697},"4 par trimestre",{"type":31,"tag":433,"props":14699,"children":14700},{},[14701],{"type":40,"value":8906},{"type":31,"tag":406,"props":14703,"children":14704},{},[14705,14710,14715],{"type":31,"tag":433,"props":14706,"children":14707},{},[14708],{"type":40,"value":14709},"Time-to-patch CVE critique",{"type":31,"tag":433,"props":14711,"children":14712},{},[14713],{"type":40,"value":14714},"38 jours",{"type":31,"tag":433,"props":14716,"children":14717},{},[14718],{"type":40,"value":14719},"6 jours",{"type":31,"tag":406,"props":14721,"children":14722},{},[14723,14728,14733],{"type":31,"tag":433,"props":14724,"children":14725},{},[14726],{"type":40,"value":14727},"Heures consacrées au refactoring d'urgence",{"type":31,"tag":433,"props":14729,"children":14730},{},[14731],{"type":40,"value":14732},"12h/semaine",{"type":31,"tag":433,"props":14734,"children":14735},{},[14736],{"type":40,"value":14737},"3h/semaine",{"type":31,"tag":32,"props":14739,"children":14740},{},[14741,14743,14747],{"type":40,"value":14742},"Le gain est mesurable, et il est financier. Une heure de dev senior coûte entre 80 et 150 euros chargée. Économiser 9 heures par semaine, c'est une différence considérable sur l'année. Pour une équipe qui a peur de \"ralentir\" en imposant des règles de review, le calcul retourne le sens : c'est l'absence de règles qui ralentit, pas leur présence. C'est exactement l'angle que je détaille dans ",{"type":31,"tag":69,"props":14744,"children":14745},{"href":3629},[14746],{"type":40,"value":3632},{"type":40,"value":76},{"type":31,"tag":48,"props":14749,"children":14750},{},[],{"type":31,"tag":52,"props":14752,"children":14753},{"id":637},[14754],{"type":40,"value":640},{"type":31,"tag":32,"props":14756,"children":14757},{},[14758],{"type":40,"value":14759},"Ce que je veux que vous reteniez de cet article, c'est que Claude n'écrit pas de mauvais code par malveillance. Il écrit le code statistiquement moyen de son training data, et ce code moyen est plein d'anti-patterns silencieux que les équipes humaines apprenaient à éviter en 5 ans de mentoring. Sans grille explicite, ces patterns rentrent dans votre repo à 2 PR par jour, et au bout de 12 mois votre dette technique a triplé.",{"type":31,"tag":32,"props":14761,"children":14762},{},[14763],{"type":40,"value":14764},"La bonne nouvelle, c'est que Claude répond très bien à un prompt précis et à un contre-pattern nommé. Il n'a pas d'ego. Il ne défend pas ses choix. Si vous lui dites \"réécris ce use case en respectant le SRP, chaque helper de moins de 20 lignes\", il s'exécute proprement. Le craft, en 2026, consiste à savoir nommer les patterns qu'on attend, à les imposer en review, et à transformer Claude en exécutant discipliné plutôt qu'en générateur de moyenne statistique.",{"type":31,"tag":32,"props":14766,"children":14767},{},[14768],{"type":40,"value":14769},"Si en lisant ces lignes vous reconnaissez votre situation, vous avez deux choix. Vous pouvez laisser les 5 patterns s'installer un peu plus chaque jour. Ou vous pouvez commencer lundi matin, par une grille de 5 questions en review, et reprendre le contrôle de votre codebase.",{"type":31,"tag":32,"props":14771,"children":14772},{},[14773,14775,14780],{"type":40,"value":14774},"Pour suivre la suite des patterns craft que je documente chaque semaine, retrouvez-moi sur ",{"type":31,"tag":69,"props":14776,"children":14778},{"href":663,"rel":14777},[665],[14779],{"type":40,"value":668},{"type":40,"value":76},{"type":31,"tag":48,"props":14782,"children":14783},{},[],{"type":31,"tag":229,"props":14785,"children":14787},{"cta":673,"href":674,"title":14786,"type":676},"Ces 5 garde-fous ne sont qu'un début : il en existe 100",[14788],{"type":31,"tag":32,"props":14789,"children":14790},{},[14791],{"type":40,"value":14792},"La grille de review décrite ici neutralise 5 anti-patterns que Claude reproduit en silence. Elle fait partie d'un référentiel bien plus large : le Craft Bundle, les 100 pratiques craft que j'applique pour coder propre. Ce sont celles que l'IA ne vous apprendra jamais, parce qu'elle ne les a jamais vues tenir en production sur le long terme.",{"type":31,"tag":48,"props":14794,"children":14795},{},[],{"type":31,"tag":52,"props":14797,"children":14799},{"id":14798},"faq-sur-les-anti-patterns-claude-et-la-review-craft",[14800],{"type":40,"value":14801},"FAQ sur les anti-patterns Claude et la review craft",{"type":31,"tag":693,"props":14803,"children":14804},{},[14805,14810],{"type":31,"tag":697,"props":14806,"children":14807},{},[14808],{"type":40,"value":14809},"1. Comment introduire cette grille sans braquer une équipe qui aime Claude ?",{"type":31,"tag":32,"props":14811,"children":14812},{},[14813],{"type":40,"value":14814},"La meilleure approche que j'ai vue, c'est de présenter la grille non comme \"Claude écrit du mauvais code\" mais comme \"Claude écrit le code moyen, et notre standard est plus haut que la moyenne\". L'équipe ne se sent pas attaquée, elle se sent élevée. Combiné à une démo concrète sur leur propre repo (3 exemples de God Function trouvés en 5 minutes), l'adhésion vient en 2 sprints. C'est aussi ce que permet une vraie culture engineering de rituels bien posée.",{"type":31,"tag":693,"props":14816,"children":14817},{},[14818,14823],{"type":31,"tag":697,"props":14819,"children":14820},{},[14821],{"type":40,"value":14822},"2. Faut-il refuser Claude sur les use cases critiques (paiement, auth) ?",{"type":31,"tag":32,"props":14824,"children":14825},{},[14826,14828,14833],{"type":40,"value":14827},"Non, mais il faut prompter différemment. Sur du critique, je donne explicitement à Claude le contexte de concurrence, de criticité, et les patterns attendus. Exemple : ",{"type":31,"tag":97,"props":14829,"children":14830},{},[14831],{"type":40,"value":14832},"\"Ce use case gère un checkout Stripe sur un SaaS multi-tenant. Utilise une transaction Prisma, type les exceptions, ne swallow rien.\"",{"type":40,"value":14834}," Le résultat est radicalement meilleur.",{"type":31,"tag":693,"props":14836,"children":14837},{},[14838,14843],{"type":31,"tag":697,"props":14839,"children":14840},{},[14841],{"type":40,"value":14842},"3. Comment automatiser la détection de ces 5 patterns ?",{"type":31,"tag":32,"props":14844,"children":14845},{},[14846,14848,14854,14856,14862,14864,14869,14871,14876],{"type":40,"value":14847},"Partiellement. Biome détecte les fonctions trop longues (",{"type":31,"tag":169,"props":14849,"children":14851},{"className":14850},[],[14852],{"type":40,"value":14853},"noExcessiveLinesPerFunction",{"type":40,"value":14855},"), la complexité cognitive (",{"type":31,"tag":169,"props":14857,"children":14859},{"className":14858},[],[14860],{"type":40,"value":14861},"noExcessiveCognitiveComplexity",{"type":40,"value":14863},"), et les ",{"type":31,"tag":169,"props":14865,"children":14867},{"className":14866},[],[14868],{"type":40,"value":13870},{"type":40,"value":14870}," génériques. Les patterns \"tests vides\" et \"dépendances non auditées\" demandent une vigilance humaine ou des outils spécialisés (Vitest coverage + mutation testing pour les tests, ",{"type":31,"tag":169,"props":14872,"children":14874},{"className":14873},[],[14875],{"type":40,"value":14419},{"type":40,"value":14877}," + Dependabot pour les packages npm). L'arsenal complet est détaillé dans les outils d'analyse statique en 2026.",{"type":31,"tag":693,"props":14879,"children":14880},{},[14881,14886],{"type":31,"tag":697,"props":14882,"children":14883},{},[14884],{"type":40,"value":14885},"4. Le pattern God Function vient-il vraiment de Claude ou existait-il déjà ?",{"type":31,"tag":32,"props":14887,"children":14888},{},[14889],{"type":40,"value":14890},"Il existait déjà, mais Claude l'amplifie. Avant 2023, une fonction de 80 lignes existait dans 8% des PR humaines selon mes mesures. En 2025, elle existe dans 23% des PR contenant du code IA-généré non révisé. L'IA ne crée pas le pattern, elle le multiplie par 3.",{"type":31,"tag":693,"props":14892,"children":14893},{},[14894,14899],{"type":31,"tag":697,"props":14895,"children":14896},{},[14897],{"type":40,"value":14898},"5. Quelle taille maximum recommander pour une fonction ?",{"type":31,"tag":32,"props":14900,"children":14901},{},[14902,14904,14908,14910,14915],{"type":40,"value":14903},"Robert C. Martin disait dans ",{"type":31,"tag":97,"props":14905,"children":14906},{},[14907],{"type":40,"value":101},{"type":40,"value":14909}," : \"Functions should be small. Then they should be smaller than that.\" Concrètement, je m'impose 20 lignes maximum pour une fonction métier, 5 niveaux d'indentation maximum, 3 paramètres maximum (au-delà, c'est un objet). Ce sont des règles arbitraires, mais elles forcent à découper. Sur crmcoaching, 94% des fonctions respectent ces seuils, et Biome (",{"type":31,"tag":169,"props":14911,"children":14913},{"className":14912},[],[14914],{"type":40,"value":14853},{"type":40,"value":14916},") fait échouer le lint si on dépasse.",{"type":31,"tag":693,"props":14918,"children":14919},{},[14920,14925],{"type":31,"tag":697,"props":14921,"children":14922},{},[14923],{"type":40,"value":14924},"6. Les tests behavior-level ne ralentissent-ils pas la CI ?",{"type":31,"tag":32,"props":14926,"children":14927},{},[14928],{"type":40,"value":14929},"Au contraire. Les tests behavior-level sont souvent plus rapides que les tests unitaires couplés à l'implémentation, parce qu'ils ne re-testent pas la même chose à 5 endroits. Sur crmcoaching, la CI tourne en 4 minutes pour 1 200 tests behavior-level. Le facteur limitant n'est plus le temps, c'est la qualité du test, ce qui est aussi le sujet de fond traité dans la checklist pour tester du code généré par IA.",{"type":31,"tag":48,"props":14931,"children":14932},{},[],{"type":31,"tag":229,"props":14934,"children":14935},{"cta":806,"href":807,"title":808,"type":809},[14936],{"type":31,"tag":32,"props":14937,"children":14938},{},[14939],{"type":40,"value":14940},"L'EMA est l'outil que je propose au début de chaque mission. Il mesure la maturité de votre équipe sur plusieurs axes engineering : qualité du code, gouvernance IA, dette technique, code review. Quelques minutes pour identifier lequel des 5 patterns vous touche le plus, et où concentrer vos efforts en priorité.",{"type":31,"tag":4005,"props":14942,"children":14943},{},[14944],{"type":40,"value":4009},{"title":8,"searchDepth":817,"depth":817,"links":14946},[14947,14948,14949,14950,14951,14952,14953,14954,14955,14956],{"id":9228,"depth":817,"text":9231},{"id":9290,"depth":817,"text":9293},{"id":11310,"depth":817,"text":11313},{"id":12429,"depth":817,"text":12432},{"id":13555,"depth":817,"text":13558},{"id":14336,"depth":817,"text":14339},{"id":14427,"depth":817,"text":14430},{"id":1463,"depth":817,"text":1466},{"id":637,"depth":817,"text":640},{"id":14798,"depth":817,"text":14801},"content:fr:intelligence-artificielle:5-patterns-dangereux-claude.md","fr/intelligence-artificielle/5-patterns-dangereux-claude.md","fr/intelligence-artificielle/5-patterns-dangereux-claude",{"_path":135,"_dir":6,"_draft":7,"_partial":7,"_locale":8,"title":14961,"description":14962,"id":11112,"date":14963,"listed":13,"nocomments":7,"hidden":7,"categories":14964,"tags":14965,"cover":14967,"readingTime":14968,"body":14973,"_type":830,"_id":17342,"_source":832,"_file":17343,"_stem":17344,"_extension":835},"Le bug que Claude vous a fait coder vendredi dernier (sans que vous le sachiez)","Anatomie d'une race condition générée par IA dans le module slot-hold de crmcoaching, et la méthode craft pour la voir avant la prod.","2026-05-04",[6],[16,14966,9201,18,19],"race-condition","covers/articles/bug-claude-vendredi-dernier.jpg",{"text":14969,"minutes":14970,"time":14971,"words":14972},"12 min read",11.12,667200,2224,{"type":28,"children":14974,"toc":17333},[14975,14991,14996,15004,15007,15013,15024,15052,15071,15097,15100,15106,15118,15632,15658,15677,15688,15691,15700,15703,15709,15714,16233,16238,16406,16449,16466,16469,16475,16480,16497,16514,16545,16576,17043,17048,17051,17055,17060,17156,17168,17171,17180,17183,17187,17192,17197,17202,17214,17217,17223,17241,17254,17279,17292,17305,17318,17321,17329],{"type":31,"tag":32,"props":14976,"children":14977},{},[14978],{"type":31,"tag":36,"props":14979,"children":14980},{},[14981,14983,14989],{"type":40,"value":14982},"Un vendredi de février 2026, je relisais une PR que Claude venait d'écrire pour le module de réservation de créneau (slot-hold) de crmcoaching. 47 lignes, tests verts, tout avait l'air propre. Sauf qu'au beau milieu du use case ",{"type":31,"tag":169,"props":14984,"children":14986},{"className":14985},[],[14987],{"type":40,"value":14988},"holdSlot",{"type":40,"value":14990}," se cachait une race condition qui, en prod, aurait permis à deux clients de réserver le même créneau au même instant. Personne ne l'avait vue. Pas même moi, au premier regard.",{"type":31,"tag":32,"props":14992,"children":14993},{},[14994],{"type":40,"value":14995},"C'est ce genre de PR qui m'a fait changer ma méthode de review depuis que je développe crmcoaching avec Claude. Voici ce que j'ai appris à repérer, pourquoi Claude écrit ce genre de code, et la grille en 4 points que j'applique aujourd'hui sur chaque PR IA-générée.",{"type":31,"tag":32,"props":14997,"children":14998},{},[14999],{"type":31,"tag":1810,"props":15000,"children":15003},{"alt":15001,"src":15002},"Le module client de crmcoaching, que je développe avec Claude","/images/crm/client.png",[],{"type":31,"tag":48,"props":15005,"children":15006},{},[],{"type":31,"tag":52,"props":15008,"children":15010},{"id":15009},"pourquoi-les-bugs-claude-passent-en-review",[15011],{"type":40,"value":15012},"Pourquoi les bugs Claude passent en review",{"type":31,"tag":32,"props":15014,"children":15015},{},[15016,15017,15022],{"type":40,"value":4067},{"type":31,"tag":69,"props":15018,"children":15020},{"href":1793,"rel":15019},[665],[15021],{"type":40,"value":1797},{"type":40,"value":15023},", les équipes qui s'appuient sur Claude voient le ratio de code \"moved or refactored\" baisser de 39%, et le code \"copied\" augmenter de 8 fois. Concrètement, le code IA-généré ressemble à du code propre, mais il transporte des patterns silencieux que la review humaine n'attrape plus.",{"type":31,"tag":32,"props":15025,"children":15026},{},[15027,15029,15034,15036,15042,15044,15050],{"type":40,"value":15028},"Le vendredi dont je parle, la PR portait sur ",{"type":31,"tag":169,"props":15030,"children":15032},{"className":15031},[],[15033],{"type":40,"value":14988},{"type":40,"value":15035}," : un use case NestJS qui lisait le statut du créneau en base, vérifiait qu'il était ",{"type":31,"tag":169,"props":15037,"children":15039},{"className":15038},[],[15040],{"type":40,"value":15041},"AVAILABLE",{"type":40,"value":15043},", puis écrivait ",{"type":31,"tag":169,"props":15045,"children":15047},{"className":15046},[],[15048],{"type":40,"value":15049},"HELD",{"type":40,"value":15051},". Tests verts parce que les tests unitaires mockaient le repository Prisma. Tests d'intégration verts parce qu'ils tournaient en séquentiel. La race condition était invisible jusqu'au jour où deux clients allaient soumettre leur réservation à 50 ms d'écart.",{"type":31,"tag":78,"props":15053,"children":15054},{},[15055],{"type":31,"tag":32,"props":15056,"children":15057},{},[15058,15063,15065,15069],{"type":31,"tag":36,"props":15059,"children":15060},{},[15061],{"type":40,"value":15062},"Ce que j'observe sur crmcoaching",{"type":40,"value":15064}," : je mesure régulièrement mon taux d'acceptation des suggestions Claude sur les PR du projet. Autour de 73% des suggestions sont acceptées telles quelles. Sur les PR que je retravaille, la majorité des retouches concernent le nommage ou le style. Jamais une race condition ou un problème de concurrence ne remonte spontanément. Le filtre humain ne voit plus ce genre de bug, exactement comme le décrit le ",{"type":31,"tag":69,"props":15066,"children":15067},{"href":71},[15068],{"type":40,"value":74},{"type":40,"value":15070}," que j'ai publié l'année dernière.",{"type":31,"tag":32,"props":15072,"children":15073},{},[15074,15076,15081,15083,15088,15090,15095],{"type":40,"value":15075},"C'est exactement ce que Bruce Schneier appelait ",{"type":31,"tag":97,"props":15077,"children":15078},{},[15079],{"type":40,"value":15080},"\"Security is a process, not a product\"",{"type":40,"value":15082}," dans son livre fondateur de 2000. La robustesse d'un ",{"type":31,"tag":169,"props":15084,"children":15086},{"className":15085},[],[15087],{"type":40,"value":14988},{"type":40,"value":15089}," n'est pas dans le code lui-même, elle est dans la discipline de review qui le précède. Si la discipline tombe, le code ne peut pas la remplacer. C'est la même logique qui anime ",{"type":31,"tag":69,"props":15091,"children":15092},{"href":113},[15093],{"type":40,"value":15094},"les principes de clean code et software craftsmanship",{"type":40,"value":15096}," que je rappelle systématiquement en mission.",{"type":31,"tag":48,"props":15098,"children":15099},{},[],{"type":31,"tag":52,"props":15101,"children":15103},{"id":15102},"anatomie-dune-race-condition-typique-générée-par-ia",[15104],{"type":40,"value":15105},"Anatomie d'une race condition typique générée par IA",{"type":31,"tag":32,"props":15107,"children":15108},{},[15109,15111,15116],{"type":40,"value":15110},"Reprenons le code que Claude m'avait produit pour ",{"type":31,"tag":169,"props":15112,"children":15114},{"className":15113},[],[15115],{"type":40,"value":14988},{"type":40,"value":15117},". Voici la version simplifiée qui illustre le pattern :",{"type":31,"tag":1894,"props":15119,"children":15121},{"className":1896,"code":15120,"language":1898,"meta":8,"style":8},"// apps/api/src/application/slot-hold/hold-slot.use-case.ts\n@Injectable()\nexport class HoldSlotUseCase {\n  constructor(private readonly prisma: PrismaService) {}\n\n  async execute(slotId: string, clientId: string): Promise\u003Cvoid> {\n    const slot = await this.prisma.slot.findUniqueOrThrow({\n      where: { id: slotId },\n    });\n\n    if (slot.status !== 'AVAILABLE') {\n      throw new Error('Slot not available');\n    }\n\n    await this.prisma.slot.update({\n      where: { id: slotId },\n      data: { status: 'HELD', heldByClientId: clientId },\n    });\n  }\n}\n",[15122],{"type":31,"tag":169,"props":15123,"children":15124},{"__ignoreMap":8},[15125,15133,15148,15168,15209,15216,15287,15343,15374,15389,15396,15433,15465,15472,15479,15522,15553,15603,15618,15625],{"type":31,"tag":1904,"props":15126,"children":15127},{"class":1906,"line":1907},[15128],{"type":31,"tag":1904,"props":15129,"children":15130},{"style":1911},[15131],{"type":40,"value":15132},"// apps/api/src/application/slot-hold/hold-slot.use-case.ts\n",{"type":31,"tag":1904,"props":15134,"children":15135},{"class":1906,"line":817},[15136,15140,15144],{"type":31,"tag":1904,"props":15137,"children":15138},{"style":2548},[15139],{"type":40,"value":2551},{"type":31,"tag":1904,"props":15141,"children":15142},{"style":1926},[15143],{"type":40,"value":2556},{"type":31,"tag":1904,"props":15145,"children":15146},{"style":2559},[15147],{"type":40,"value":2562},{"type":31,"tag":1904,"props":15149,"children":15150},{"class":1906,"line":1938},[15151,15155,15159,15164],{"type":31,"tag":1904,"props":15152,"children":15153},{"style":1920},[15154],{"type":40,"value":2462},{"type":31,"tag":1904,"props":15156,"children":15157},{"style":1920},[15158],{"type":40,"value":2574},{"type":31,"tag":1904,"props":15160,"children":15161},{"style":2470},[15162],{"type":40,"value":15163}," HoldSlotUseCase",{"type":31,"tag":1904,"props":15165,"children":15166},{"style":1932},[15167],{"type":40,"value":2005},{"type":31,"tag":1904,"props":15169,"children":15170},{"class":1906,"line":1965},[15171,15175,15179,15184,15188,15192,15196,15201,15205],{"type":31,"tag":1904,"props":15172,"children":15173},{"style":1920},[15174],{"type":40,"value":2995},{"type":31,"tag":1904,"props":15176,"children":15177},{"style":1932},[15178],{"type":40,"value":2490},{"type":31,"tag":1904,"props":15180,"children":15181},{"style":1920},[15182],{"type":40,"value":15183},"private",{"type":31,"tag":1904,"props":15185,"children":15186},{"style":1920},[15187],{"type":40,"value":3012},{"type":31,"tag":1904,"props":15189,"children":15190},{"style":1942},[15191],{"type":40,"value":9395},{"type":31,"tag":1904,"props":15193,"children":15194},{"style":1948},[15195],{"type":40,"value":1951},{"type":31,"tag":1904,"props":15197,"children":15198},{"style":2470},[15199],{"type":40,"value":15200}," PrismaService",{"type":31,"tag":1904,"props":15202,"children":15203},{"style":1932},[15204],{"type":40,"value":1992},{"type":31,"tag":1904,"props":15206,"children":15207},{"style":1932},[15208],{"type":40,"value":3101},{"type":31,"tag":1904,"props":15210,"children":15211},{"class":1906,"line":1986},[15212],{"type":31,"tag":1904,"props":15213,"children":15214},{"emptyLinePlaceholder":13},[15215],{"type":40,"value":2165},{"type":31,"tag":1904,"props":15217,"children":15218},{"class":1906,"line":2008},[15219,15223,15227,15231,15235,15239,15243,15247,15251,15255,15259,15263,15267,15271,15275,15279,15283],{"type":31,"tag":1904,"props":15220,"children":15221},{"style":1920},[15222],{"type":40,"value":3116},{"type":31,"tag":1904,"props":15224,"children":15225},{"style":1926},[15226],{"type":40,"value":9525},{"type":31,"tag":1904,"props":15228,"children":15229},{"style":1932},[15230],{"type":40,"value":2490},{"type":31,"tag":1904,"props":15232,"children":15233},{"style":1942},[15234],{"type":40,"value":11484},{"type":31,"tag":1904,"props":15236,"children":15237},{"style":1948},[15238],{"type":40,"value":1951},{"type":31,"tag":1904,"props":15240,"children":15241},{"style":1954},[15242],{"type":40,"value":2790},{"type":31,"tag":1904,"props":15244,"children":15245},{"style":1932},[15246],{"type":40,"value":4853},{"type":31,"tag":1904,"props":15248,"children":15249},{"style":1942},[15250],{"type":40,"value":11157},{"type":31,"tag":1904,"props":15252,"children":15253},{"style":1948},[15254],{"type":40,"value":1951},{"type":31,"tag":1904,"props":15256,"children":15257},{"style":1954},[15258],{"type":40,"value":2790},{"type":31,"tag":1904,"props":15260,"children":15261},{"style":1932},[15262],{"type":40,"value":1992},{"type":31,"tag":1904,"props":15264,"children":15265},{"style":1948},[15266],{"type":40,"value":1951},{"type":31,"tag":1904,"props":15268,"children":15269},{"style":2470},[15270],{"type":40,"value":3152},{"type":31,"tag":1904,"props":15272,"children":15273},{"style":3155},[15274],{"type":40,"value":3158},{"type":31,"tag":1904,"props":15276,"children":15277},{"style":1954},[15278],{"type":40,"value":4348},{"type":31,"tag":1904,"props":15280,"children":15281},{"style":3155},[15282],{"type":40,"value":3168},{"type":31,"tag":1904,"props":15284,"children":15285},{"style":1932},[15286],{"type":40,"value":2005},{"type":31,"tag":1904,"props":15288,"children":15289},{"class":1906,"line":2050},[15290,15294,15298,15302,15306,15310,15314,15318,15322,15326,15330,15335,15339],{"type":31,"tag":1904,"props":15291,"children":15292},{"style":1920},[15293],{"type":40,"value":3180},{"type":31,"tag":1904,"props":15295,"children":15296},{"style":2017},[15297],{"type":40,"value":11706},{"type":31,"tag":1904,"props":15299,"children":15300},{"style":1948},[15301],{"type":40,"value":2025},{"type":31,"tag":1904,"props":15303,"children":15304},{"style":1920},[15305],{"type":40,"value":3194},{"type":31,"tag":1904,"props":15307,"children":15308},{"style":3197},[15309],{"type":40,"value":3200},{"type":31,"tag":1904,"props":15311,"children":15312},{"style":2108},[15313],{"type":40,"value":76},{"type":31,"tag":1904,"props":15315,"children":15316},{"style":2028},[15317],{"type":40,"value":9678},{"type":31,"tag":1904,"props":15319,"children":15320},{"style":2108},[15321],{"type":40,"value":76},{"type":31,"tag":1904,"props":15323,"children":15324},{"style":2028},[15325],{"type":40,"value":11735},{"type":31,"tag":1904,"props":15327,"children":15328},{"style":2108},[15329],{"type":40,"value":76},{"type":31,"tag":1904,"props":15331,"children":15332},{"style":1926},[15333],{"type":40,"value":15334},"findUniqueOrThrow",{"type":31,"tag":1904,"props":15336,"children":15337},{"style":2028},[15338],{"type":40,"value":2490},{"type":31,"tag":1904,"props":15340,"children":15341},{"style":1932},[15342],{"type":40,"value":3264},{"type":31,"tag":1904,"props":15344,"children":15345},{"class":1906,"line":2094},[15346,15350,15354,15358,15362,15366,15370],{"type":31,"tag":1904,"props":15347,"children":15348},{"style":2028},[15349],{"type":40,"value":10001},{"type":31,"tag":1904,"props":15351,"children":15352},{"style":2108},[15353],{"type":40,"value":1951},{"type":31,"tag":1904,"props":15355,"children":15356},{"style":1932},[15357],{"type":40,"value":4625},{"type":31,"tag":1904,"props":15359,"children":15360},{"style":2028},[15361],{"type":40,"value":9721},{"type":31,"tag":1904,"props":15363,"children":15364},{"style":2108},[15365],{"type":40,"value":1951},{"type":31,"tag":1904,"props":15367,"children":15368},{"style":2028},[15369],{"type":40,"value":11776},{"type":31,"tag":1904,"props":15371,"children":15372},{"style":1932},[15373],{"type":40,"value":4652},{"type":31,"tag":1904,"props":15375,"children":15376},{"class":1906,"line":2150},[15377,15381,15385],{"type":31,"tag":1904,"props":15378,"children":15379},{"style":1932},[15380],{"type":40,"value":4660},{"type":31,"tag":1904,"props":15382,"children":15383},{"style":2028},[15384],{"type":40,"value":1992},{"type":31,"tag":1904,"props":15386,"children":15387},{"style":1932},[15388],{"type":40,"value":2047},{"type":31,"tag":1904,"props":15390,"children":15391},{"class":1906,"line":2159},[15392],{"type":31,"tag":1904,"props":15393,"children":15394},{"emptyLinePlaceholder":13},[15395],{"type":40,"value":2165},{"type":31,"tag":1904,"props":15397,"children":15398},{"class":1906,"line":2168},[15399,15403,15408,15412,15416,15420,15425,15429],{"type":31,"tag":1904,"props":15400,"children":15401},{"style":1920},[15402],{"type":40,"value":3244},{"type":31,"tag":1904,"props":15404,"children":15405},{"style":2028},[15406],{"type":40,"value":15407}," (slot",{"type":31,"tag":1904,"props":15409,"children":15410},{"style":2108},[15411],{"type":40,"value":76},{"type":31,"tag":1904,"props":15413,"children":15414},{"style":2028},[15415],{"type":40,"value":5420},{"type":31,"tag":1904,"props":15417,"children":15418},{"style":1948},[15419],{"type":40,"value":9838},{"type":31,"tag":1904,"props":15421,"children":15422},{"style":3399},[15423],{"type":40,"value":15424}," 'AVAILABLE'",{"type":31,"tag":1904,"props":15426,"children":15427},{"style":2028},[15428],{"type":40,"value":2135},{"type":31,"tag":1904,"props":15430,"children":15431},{"style":1932},[15432],{"type":40,"value":3264},{"type":31,"tag":1904,"props":15434,"children":15435},{"class":1906,"line":2177},[15436,15440,15444,15448,15452,15457,15461],{"type":31,"tag":1904,"props":15437,"children":15438},{"style":1920},[15439],{"type":40,"value":3272},{"type":31,"tag":1904,"props":15441,"children":15442},{"style":2816},[15443],{"type":40,"value":2819},{"type":31,"tag":1904,"props":15445,"children":15446},{"style":1926},[15447],{"type":40,"value":4440},{"type":31,"tag":1904,"props":15449,"children":15450},{"style":2028},[15451],{"type":40,"value":2490},{"type":31,"tag":1904,"props":15453,"children":15454},{"style":3399},[15455],{"type":40,"value":15456},"'Slot not available'",{"type":31,"tag":1904,"props":15458,"children":15459},{"style":2028},[15460],{"type":40,"value":1992},{"type":31,"tag":1904,"props":15462,"children":15463},{"style":1932},[15464],{"type":40,"value":2047},{"type":31,"tag":1904,"props":15466,"children":15467},{"class":1906,"line":2194},[15468],{"type":31,"tag":1904,"props":15469,"children":15470},{"style":1932},[15471],{"type":40,"value":3305},{"type":31,"tag":1904,"props":15473,"children":15474},{"class":1906,"line":2215},[15475],{"type":31,"tag":1904,"props":15476,"children":15477},{"emptyLinePlaceholder":13},[15478],{"type":40,"value":2165},{"type":31,"tag":1904,"props":15480,"children":15481},{"class":1906,"line":2236},[15482,15486,15490,15494,15498,15502,15506,15510,15514,15518],{"type":31,"tag":1904,"props":15483,"children":15484},{"style":1920},[15485],{"type":40,"value":3313},{"type":31,"tag":1904,"props":15487,"children":15488},{"style":3197},[15489],{"type":40,"value":3200},{"type":31,"tag":1904,"props":15491,"children":15492},{"style":2108},[15493],{"type":40,"value":76},{"type":31,"tag":1904,"props":15495,"children":15496},{"style":2028},[15497],{"type":40,"value":9678},{"type":31,"tag":1904,"props":15499,"children":15500},{"style":2108},[15501],{"type":40,"value":76},{"type":31,"tag":1904,"props":15503,"children":15504},{"style":2028},[15505],{"type":40,"value":11735},{"type":31,"tag":1904,"props":15507,"children":15508},{"style":2108},[15509],{"type":40,"value":76},{"type":31,"tag":1904,"props":15511,"children":15512},{"style":1926},[15513],{"type":40,"value":10441},{"type":31,"tag":1904,"props":15515,"children":15516},{"style":2028},[15517],{"type":40,"value":2490},{"type":31,"tag":1904,"props":15519,"children":15520},{"style":1932},[15521],{"type":40,"value":3264},{"type":31,"tag":1904,"props":15523,"children":15524},{"class":1906,"line":2256},[15525,15529,15533,15537,15541,15545,15549],{"type":31,"tag":1904,"props":15526,"children":15527},{"style":2028},[15528],{"type":40,"value":10001},{"type":31,"tag":1904,"props":15530,"children":15531},{"style":2108},[15532],{"type":40,"value":1951},{"type":31,"tag":1904,"props":15534,"children":15535},{"style":1932},[15536],{"type":40,"value":4625},{"type":31,"tag":1904,"props":15538,"children":15539},{"style":2028},[15540],{"type":40,"value":9721},{"type":31,"tag":1904,"props":15542,"children":15543},{"style":2108},[15544],{"type":40,"value":1951},{"type":31,"tag":1904,"props":15546,"children":15547},{"style":2028},[15548],{"type":40,"value":11776},{"type":31,"tag":1904,"props":15550,"children":15551},{"style":1932},[15552],{"type":40,"value":4652},{"type":31,"tag":1904,"props":15554,"children":15555},{"class":1906,"line":2290},[15556,15560,15564,15568,15572,15576,15581,15585,15590,15594,15599],{"type":31,"tag":1904,"props":15557,"children":15558},{"style":2028},[15559],{"type":40,"value":10186},{"type":31,"tag":1904,"props":15561,"children":15562},{"style":2108},[15563],{"type":40,"value":1951},{"type":31,"tag":1904,"props":15565,"children":15566},{"style":1932},[15567],{"type":40,"value":4625},{"type":31,"tag":1904,"props":15569,"children":15570},{"style":2028},[15571],{"type":40,"value":10500},{"type":31,"tag":1904,"props":15573,"children":15574},{"style":2108},[15575],{"type":40,"value":1951},{"type":31,"tag":1904,"props":15577,"children":15578},{"style":3399},[15579],{"type":40,"value":15580}," 'HELD'",{"type":31,"tag":1904,"props":15582,"children":15583},{"style":1932},[15584],{"type":40,"value":4853},{"type":31,"tag":1904,"props":15586,"children":15587},{"style":2028},[15588],{"type":40,"value":15589}," heldByClientId",{"type":31,"tag":1904,"props":15591,"children":15592},{"style":2108},[15593],{"type":40,"value":1951},{"type":31,"tag":1904,"props":15595,"children":15596},{"style":2028},[15597],{"type":40,"value":15598}," clientId ",{"type":31,"tag":1904,"props":15600,"children":15601},{"style":1932},[15602],{"type":40,"value":4652},{"type":31,"tag":1904,"props":15604,"children":15605},{"class":1906,"line":2333},[15606,15610,15614],{"type":31,"tag":1904,"props":15607,"children":15608},{"style":1932},[15609],{"type":40,"value":4660},{"type":31,"tag":1904,"props":15611,"children":15612},{"style":2028},[15613],{"type":40,"value":1992},{"type":31,"tag":1904,"props":15615,"children":15616},{"style":1932},[15617],{"type":40,"value":2047},{"type":31,"tag":1904,"props":15619,"children":15620},{"class":1906,"line":2382},[15621],{"type":31,"tag":1904,"props":15622,"children":15623},{"style":1932},[15624],{"type":40,"value":2717},{"type":31,"tag":1904,"props":15626,"children":15627},{"class":1906,"line":4678},[15628],{"type":31,"tag":1904,"props":15629,"children":15630},{"style":1932},[15631],{"type":40,"value":2156},{"type":31,"tag":32,"props":15633,"children":15634},{},[15635,15637,15643,15645,15650,15652,15657],{"type":40,"value":15636},"Le bug est à deux endroits. D'abord, la lecture de ",{"type":31,"tag":169,"props":15638,"children":15640},{"className":15639},[],[15641],{"type":40,"value":15642},"slot.status",{"type":40,"value":15644}," n'est pas verrouillée : deux requêtes parallèles peuvent toutes les deux lire ",{"type":31,"tag":169,"props":15646,"children":15648},{"className":15647},[],[15649],{"type":40,"value":15041},{"type":40,"value":15651}," et valider la condition indépendamment. Ensuite, l'écriture utilise la valeur lue en mémoire au lieu de demander à Postgres de faire le calcul atomique avec une condition. Résultat : deux clients se retrouvent avec le même créneau marqué ",{"type":31,"tag":169,"props":15653,"children":15655},{"className":15654},[],[15656],{"type":40,"value":15049},{"type":40,"value":76},{"type":31,"tag":32,"props":15659,"children":15660},{},[15661,15663,15668,15670,15675],{"type":40,"value":15662},"Pourquoi Claude écrit ce code-là ? Parce que c'est le pattern dominant dans son training data. Sur GitHub, des dizaines de milliers d'exemples Prisma montrent exactement cette séquence ",{"type":31,"tag":169,"props":15664,"children":15666},{"className":15665},[],[15667],{"type":40,"value":9695},{"type":40,"value":15669}," + ",{"type":31,"tag":169,"props":15671,"children":15673},{"className":15672},[],[15674],{"type":40,"value":10441},{"type":40,"value":15676},". Claude n'a pas conscience que dans un contexte de réservation, la concurrence est la norme et non l'exception. Il code comme un développeur junior bien intentionné qui n'a jamais vu de prod sous charge.",{"type":31,"tag":32,"props":15678,"children":15679},{},[15680,15682,15686],{"type":40,"value":15681},"C'est aussi ce que Martin Fowler a documenté dans ",{"type":31,"tag":97,"props":15683,"children":15684},{},[15685],{"type":40,"value":2889},{"type":40,"value":15687}," (2018) : le code qui marche dans un test unitaire n'est pas le code qui marche en production. La différence est dans les conditions d'exécution, et l'IA n'a pas accès à ces conditions au moment où elle génère. C'est exactement le genre de risque qui transforme un repo récent en legacy à évaluer urgemment à 12 mois si la discipline de review ne se met pas en place rapidement.",{"type":31,"tag":48,"props":15689,"children":15690},{},[],{"type":31,"tag":229,"props":15692,"children":15694},{"cta":231,"href":232,"title":15693,"type":234},"Vous voulez développer le réflexe qui attrape ces bugs avant la prod ?",[15695],{"type":31,"tag":32,"props":15696,"children":15697},{},[15698],{"type":40,"value":15699},"Repérer une race condition dans une PR Claude, ça ne s'apprend pas en lisant un article : ça se travaille. En mentoring 1:1, je relis votre code et vos PR IA-générées avec vous, et je vous transmets la grille de lecture que j'applique sur crmcoaching. En quelques sessions, vous arrêtez de relire les accolades et vous commencez à voir ce que le modèle ne voit pas.",{"type":31,"tag":48,"props":15701,"children":15702},{},[],{"type":31,"tag":52,"props":15704,"children":15706},{"id":15705},"le-fix-craft-transaction-atomique-et-garde-explicite",[15707],{"type":40,"value":15708},"Le fix craft : transaction atomique et garde explicite",{"type":31,"tag":32,"props":15710,"children":15711},{},[15712],{"type":40,"value":15713},"Voici la version que j'ai réécrite avec Claude, en lui donnant le bon contexte cette fois :",{"type":31,"tag":1894,"props":15715,"children":15717},{"className":1896,"code":15716,"language":1898,"meta":8,"style":8},"// apps/api/src/application/slot-hold/hold-slot.use-case.ts\n@Injectable()\nexport class HoldSlotUseCase {\n  constructor(private readonly prisma: PrismaService) {}\n\n  async execute(slotId: string, clientId: string): Promise\u003Cvoid> {\n    await this.prisma.$transaction(\n      async (tx) => {\n        const result = await tx.slot.updateMany({\n          where: { id: slotId, status: 'AVAILABLE' },\n          data: { status: 'HELD', heldByClientId: clientId },\n        });\n\n        if (result.count !== 1) {\n          throw new SlotAlreadyHeldError(slotId);\n        }\n      },\n      { isolationLevel: 'Serializable' },\n    );\n  }\n}\n",[15718],{"type":31,"tag":169,"props":15719,"children":15720},{"__ignoreMap":8},[15721,15728,15743,15762,15801,15808,15879,15911,15939,15988,16036,16084,16099,16106,16144,16168,16175,16182,16208,16219,16226],{"type":31,"tag":1904,"props":15722,"children":15723},{"class":1906,"line":1907},[15724],{"type":31,"tag":1904,"props":15725,"children":15726},{"style":1911},[15727],{"type":40,"value":15132},{"type":31,"tag":1904,"props":15729,"children":15730},{"class":1906,"line":817},[15731,15735,15739],{"type":31,"tag":1904,"props":15732,"children":15733},{"style":2548},[15734],{"type":40,"value":2551},{"type":31,"tag":1904,"props":15736,"children":15737},{"style":1926},[15738],{"type":40,"value":2556},{"type":31,"tag":1904,"props":15740,"children":15741},{"style":2559},[15742],{"type":40,"value":2562},{"type":31,"tag":1904,"props":15744,"children":15745},{"class":1906,"line":1938},[15746,15750,15754,15758],{"type":31,"tag":1904,"props":15747,"children":15748},{"style":1920},[15749],{"type":40,"value":2462},{"type":31,"tag":1904,"props":15751,"children":15752},{"style":1920},[15753],{"type":40,"value":2574},{"type":31,"tag":1904,"props":15755,"children":15756},{"style":2470},[15757],{"type":40,"value":15163},{"type":31,"tag":1904,"props":15759,"children":15760},{"style":1932},[15761],{"type":40,"value":2005},{"type":31,"tag":1904,"props":15763,"children":15764},{"class":1906,"line":1965},[15765,15769,15773,15777,15781,15785,15789,15793,15797],{"type":31,"tag":1904,"props":15766,"children":15767},{"style":1920},[15768],{"type":40,"value":2995},{"type":31,"tag":1904,"props":15770,"children":15771},{"style":1932},[15772],{"type":40,"value":2490},{"type":31,"tag":1904,"props":15774,"children":15775},{"style":1920},[15776],{"type":40,"value":15183},{"type":31,"tag":1904,"props":15778,"children":15779},{"style":1920},[15780],{"type":40,"value":3012},{"type":31,"tag":1904,"props":15782,"children":15783},{"style":1942},[15784],{"type":40,"value":9395},{"type":31,"tag":1904,"props":15786,"children":15787},{"style":1948},[15788],{"type":40,"value":1951},{"type":31,"tag":1904,"props":15790,"children":15791},{"style":2470},[15792],{"type":40,"value":15200},{"type":31,"tag":1904,"props":15794,"children":15795},{"style":1932},[15796],{"type":40,"value":1992},{"type":31,"tag":1904,"props":15798,"children":15799},{"style":1932},[15800],{"type":40,"value":3101},{"type":31,"tag":1904,"props":15802,"children":15803},{"class":1906,"line":1986},[15804],{"type":31,"tag":1904,"props":15805,"children":15806},{"emptyLinePlaceholder":13},[15807],{"type":40,"value":2165},{"type":31,"tag":1904,"props":15809,"children":15810},{"class":1906,"line":2008},[15811,15815,15819,15823,15827,15831,15835,15839,15843,15847,15851,15855,15859,15863,15867,15871,15875],{"type":31,"tag":1904,"props":15812,"children":15813},{"style":1920},[15814],{"type":40,"value":3116},{"type":31,"tag":1904,"props":15816,"children":15817},{"style":1926},[15818],{"type":40,"value":9525},{"type":31,"tag":1904,"props":15820,"children":15821},{"style":1932},[15822],{"type":40,"value":2490},{"type":31,"tag":1904,"props":15824,"children":15825},{"style":1942},[15826],{"type":40,"value":11484},{"type":31,"tag":1904,"props":15828,"children":15829},{"style":1948},[15830],{"type":40,"value":1951},{"type":31,"tag":1904,"props":15832,"children":15833},{"style":1954},[15834],{"type":40,"value":2790},{"type":31,"tag":1904,"props":15836,"children":15837},{"style":1932},[15838],{"type":40,"value":4853},{"type":31,"tag":1904,"props":15840,"children":15841},{"style":1942},[15842],{"type":40,"value":11157},{"type":31,"tag":1904,"props":15844,"children":15845},{"style":1948},[15846],{"type":40,"value":1951},{"type":31,"tag":1904,"props":15848,"children":15849},{"style":1954},[15850],{"type":40,"value":2790},{"type":31,"tag":1904,"props":15852,"children":15853},{"style":1932},[15854],{"type":40,"value":1992},{"type":31,"tag":1904,"props":15856,"children":15857},{"style":1948},[15858],{"type":40,"value":1951},{"type":31,"tag":1904,"props":15860,"children":15861},{"style":2470},[15862],{"type":40,"value":3152},{"type":31,"tag":1904,"props":15864,"children":15865},{"style":3155},[15866],{"type":40,"value":3158},{"type":31,"tag":1904,"props":15868,"children":15869},{"style":1954},[15870],{"type":40,"value":4348},{"type":31,"tag":1904,"props":15872,"children":15873},{"style":3155},[15874],{"type":40,"value":3168},{"type":31,"tag":1904,"props":15876,"children":15877},{"style":1932},[15878],{"type":40,"value":2005},{"type":31,"tag":1904,"props":15880,"children":15881},{"class":1906,"line":2050},[15882,15886,15890,15894,15898,15902,15907],{"type":31,"tag":1904,"props":15883,"children":15884},{"style":1920},[15885],{"type":40,"value":3313},{"type":31,"tag":1904,"props":15887,"children":15888},{"style":3197},[15889],{"type":40,"value":3200},{"type":31,"tag":1904,"props":15891,"children":15892},{"style":2108},[15893],{"type":40,"value":76},{"type":31,"tag":1904,"props":15895,"children":15896},{"style":2028},[15897],{"type":40,"value":9678},{"type":31,"tag":1904,"props":15899,"children":15900},{"style":2108},[15901],{"type":40,"value":76},{"type":31,"tag":1904,"props":15903,"children":15904},{"style":1926},[15905],{"type":40,"value":15906},"$transaction",{"type":31,"tag":1904,"props":15908,"children":15909},{"style":2028},[15910],{"type":40,"value":1935},{"type":31,"tag":1904,"props":15912,"children":15913},{"class":1906,"line":2094},[15914,15918,15922,15927,15931,15935],{"type":31,"tag":1904,"props":15915,"children":15916},{"style":1920},[15917],{"type":40,"value":7783},{"type":31,"tag":1904,"props":15919,"children":15920},{"style":1932},[15921],{"type":40,"value":3249},{"type":31,"tag":1904,"props":15923,"children":15924},{"style":1942},[15925],{"type":40,"value":15926},"tx",{"type":31,"tag":1904,"props":15928,"children":15929},{"style":1932},[15930],{"type":40,"value":1992},{"type":31,"tag":1904,"props":15932,"children":15933},{"style":1948},[15934],{"type":40,"value":4868},{"type":31,"tag":1904,"props":15936,"children":15937},{"style":1932},[15938],{"type":40,"value":2005},{"type":31,"tag":1904,"props":15940,"children":15941},{"class":1906,"line":2150},[15942,15946,15950,15954,15958,15963,15967,15971,15975,15980,15984],{"type":31,"tag":1904,"props":15943,"children":15944},{"style":1920},[15945],{"type":40,"value":7804},{"type":31,"tag":1904,"props":15947,"children":15948},{"style":2017},[15949],{"type":40,"value":13266},{"type":31,"tag":1904,"props":15951,"children":15952},{"style":1948},[15953],{"type":40,"value":2025},{"type":31,"tag":1904,"props":15955,"children":15956},{"style":1920},[15957],{"type":40,"value":3194},{"type":31,"tag":1904,"props":15959,"children":15960},{"style":2028},[15961],{"type":40,"value":15962}," tx",{"type":31,"tag":1904,"props":15964,"children":15965},{"style":2108},[15966],{"type":40,"value":76},{"type":31,"tag":1904,"props":15968,"children":15969},{"style":2028},[15970],{"type":40,"value":11735},{"type":31,"tag":1904,"props":15972,"children":15973},{"style":2108},[15974],{"type":40,"value":76},{"type":31,"tag":1904,"props":15976,"children":15977},{"style":1926},[15978],{"type":40,"value":15979},"updateMany",{"type":31,"tag":1904,"props":15981,"children":15982},{"style":2028},[15983],{"type":40,"value":2490},{"type":31,"tag":1904,"props":15985,"children":15986},{"style":1932},[15987],{"type":40,"value":3264},{"type":31,"tag":1904,"props":15989,"children":15990},{"class":1906,"line":2159},[15991,15996,16000,16004,16008,16012,16016,16020,16024,16028,16032],{"type":31,"tag":1904,"props":15992,"children":15993},{"style":2028},[15994],{"type":40,"value":15995},"          where",{"type":31,"tag":1904,"props":15997,"children":15998},{"style":2108},[15999],{"type":40,"value":1951},{"type":31,"tag":1904,"props":16001,"children":16002},{"style":1932},[16003],{"type":40,"value":4625},{"type":31,"tag":1904,"props":16005,"children":16006},{"style":2028},[16007],{"type":40,"value":9721},{"type":31,"tag":1904,"props":16009,"children":16010},{"style":2108},[16011],{"type":40,"value":1951},{"type":31,"tag":1904,"props":16013,"children":16014},{"style":2028},[16015],{"type":40,"value":11615},{"type":31,"tag":1904,"props":16017,"children":16018},{"style":1932},[16019],{"type":40,"value":4853},{"type":31,"tag":1904,"props":16021,"children":16022},{"style":2028},[16023],{"type":40,"value":10500},{"type":31,"tag":1904,"props":16025,"children":16026},{"style":2108},[16027],{"type":40,"value":1951},{"type":31,"tag":1904,"props":16029,"children":16030},{"style":3399},[16031],{"type":40,"value":15424},{"type":31,"tag":1904,"props":16033,"children":16034},{"style":1932},[16035],{"type":40,"value":11679},{"type":31,"tag":1904,"props":16037,"children":16038},{"class":1906,"line":2168},[16039,16044,16048,16052,16056,16060,16064,16068,16072,16076,16080],{"type":31,"tag":1904,"props":16040,"children":16041},{"style":2028},[16042],{"type":40,"value":16043},"          data",{"type":31,"tag":1904,"props":16045,"children":16046},{"style":2108},[16047],{"type":40,"value":1951},{"type":31,"tag":1904,"props":16049,"children":16050},{"style":1932},[16051],{"type":40,"value":4625},{"type":31,"tag":1904,"props":16053,"children":16054},{"style":2028},[16055],{"type":40,"value":10500},{"type":31,"tag":1904,"props":16057,"children":16058},{"style":2108},[16059],{"type":40,"value":1951},{"type":31,"tag":1904,"props":16061,"children":16062},{"style":3399},[16063],{"type":40,"value":15580},{"type":31,"tag":1904,"props":16065,"children":16066},{"style":1932},[16067],{"type":40,"value":4853},{"type":31,"tag":1904,"props":16069,"children":16070},{"style":2028},[16071],{"type":40,"value":15589},{"type":31,"tag":1904,"props":16073,"children":16074},{"style":2108},[16075],{"type":40,"value":1951},{"type":31,"tag":1904,"props":16077,"children":16078},{"style":2028},[16079],{"type":40,"value":15598},{"type":31,"tag":1904,"props":16081,"children":16082},{"style":1932},[16083],{"type":40,"value":4652},{"type":31,"tag":1904,"props":16085,"children":16086},{"class":1906,"line":2177},[16087,16091,16095],{"type":31,"tag":1904,"props":16088,"children":16089},{"style":1932},[16090],{"type":40,"value":8149},{"type":31,"tag":1904,"props":16092,"children":16093},{"style":2028},[16094],{"type":40,"value":1992},{"type":31,"tag":1904,"props":16096,"children":16097},{"style":1932},[16098],{"type":40,"value":2047},{"type":31,"tag":1904,"props":16100,"children":16101},{"class":1906,"line":2194},[16102],{"type":31,"tag":1904,"props":16103,"children":16104},{"emptyLinePlaceholder":13},[16105],{"type":40,"value":2165},{"type":31,"tag":1904,"props":16107,"children":16108},{"class":1906,"line":2215},[16109,16114,16119,16123,16128,16132,16136,16140],{"type":31,"tag":1904,"props":16110,"children":16111},{"style":1920},[16112],{"type":40,"value":16113},"        if",{"type":31,"tag":1904,"props":16115,"children":16116},{"style":2028},[16117],{"type":40,"value":16118}," (result",{"type":31,"tag":1904,"props":16120,"children":16121},{"style":2108},[16122],{"type":40,"value":76},{"type":31,"tag":1904,"props":16124,"children":16125},{"style":2028},[16126],{"type":40,"value":16127},"count ",{"type":31,"tag":1904,"props":16129,"children":16130},{"style":1948},[16131],{"type":40,"value":9838},{"type":31,"tag":1904,"props":16133,"children":16134},{"style":2039},[16135],{"type":40,"value":5840},{"type":31,"tag":1904,"props":16137,"children":16138},{"style":2028},[16139],{"type":40,"value":2135},{"type":31,"tag":1904,"props":16141,"children":16142},{"style":1932},[16143],{"type":40,"value":3264},{"type":31,"tag":1904,"props":16145,"children":16146},{"class":1906,"line":2236},[16147,16151,16155,16160,16164],{"type":31,"tag":1904,"props":16148,"children":16149},{"style":1920},[16150],{"type":40,"value":8412},{"type":31,"tag":1904,"props":16152,"children":16153},{"style":2816},[16154],{"type":40,"value":2819},{"type":31,"tag":1904,"props":16156,"children":16157},{"style":1926},[16158],{"type":40,"value":16159}," SlotAlreadyHeldError",{"type":31,"tag":1904,"props":16161,"children":16162},{"style":2028},[16163],{"type":40,"value":12269},{"type":31,"tag":1904,"props":16165,"children":16166},{"style":1932},[16167],{"type":40,"value":2047},{"type":31,"tag":1904,"props":16169,"children":16170},{"class":1906,"line":2256},[16171],{"type":31,"tag":1904,"props":16172,"children":16173},{"style":1932},[16174],{"type":40,"value":8464},{"type":31,"tag":1904,"props":16176,"children":16177},{"class":1906,"line":2290},[16178],{"type":31,"tag":1904,"props":16179,"children":16180},{"style":1932},[16181],{"type":40,"value":8490},{"type":31,"tag":1904,"props":16183,"children":16184},{"class":1906,"line":2333},[16185,16190,16195,16199,16204],{"type":31,"tag":1904,"props":16186,"children":16187},{"style":1932},[16188],{"type":40,"value":16189},"      {",{"type":31,"tag":1904,"props":16191,"children":16192},{"style":2028},[16193],{"type":40,"value":16194}," isolationLevel",{"type":31,"tag":1904,"props":16196,"children":16197},{"style":2108},[16198],{"type":40,"value":1951},{"type":31,"tag":1904,"props":16200,"children":16201},{"style":3399},[16202],{"type":40,"value":16203}," 'Serializable'",{"type":31,"tag":1904,"props":16205,"children":16206},{"style":1932},[16207],{"type":40,"value":11679},{"type":31,"tag":1904,"props":16209,"children":16210},{"class":1906,"line":2382},[16211,16215],{"type":31,"tag":1904,"props":16212,"children":16213},{"style":2028},[16214],{"type":40,"value":8670},{"type":31,"tag":1904,"props":16216,"children":16217},{"style":1932},[16218],{"type":40,"value":2047},{"type":31,"tag":1904,"props":16220,"children":16221},{"class":1906,"line":4678},[16222],{"type":31,"tag":1904,"props":16223,"children":16224},{"style":1932},[16225],{"type":40,"value":2717},{"type":31,"tag":1904,"props":16227,"children":16228},{"class":1906,"line":5525},[16229],{"type":31,"tag":1904,"props":16230,"children":16231},{"style":1932},[16232],{"type":40,"value":2156},{"type":31,"tag":32,"props":16234,"children":16235},{},[16236],{"type":40,"value":16237},"avec l'exception typée dans le domaine :",{"type":31,"tag":1894,"props":16239,"children":16241},{"className":1896,"code":16240,"language":1898,"meta":8,"style":8},"// apps/api/src/domain/slot-hold/slot-already-held.error.ts\nexport class SlotAlreadyHeldError extends Error {\n  constructor(public readonly slotId: string) {\n    super(`Slot ${slotId} is no longer available`);\n    this.name = 'SlotAlreadyHeldError';\n  }\n}\n",[16242],{"type":31,"tag":169,"props":16243,"children":16244},{"__ignoreMap":8},[16245,16253,16281,16321,16363,16392,16399],{"type":31,"tag":1904,"props":16246,"children":16247},{"class":1906,"line":1907},[16248],{"type":31,"tag":1904,"props":16249,"children":16250},{"style":1911},[16251],{"type":40,"value":16252},"// apps/api/src/domain/slot-hold/slot-already-held.error.ts\n",{"type":31,"tag":1904,"props":16254,"children":16255},{"class":1906,"line":817},[16256,16260,16264,16268,16273,16277],{"type":31,"tag":1904,"props":16257,"children":16258},{"style":1920},[16259],{"type":40,"value":2462},{"type":31,"tag":1904,"props":16261,"children":16262},{"style":1920},[16263],{"type":40,"value":2574},{"type":31,"tag":1904,"props":16265,"children":16266},{"style":2470},[16267],{"type":40,"value":16159},{"type":31,"tag":1904,"props":16269,"children":16270},{"style":1920},[16271],{"type":40,"value":16272}," extends",{"type":31,"tag":1904,"props":16274,"children":16275},{"style":2470},[16276],{"type":40,"value":4440},{"type":31,"tag":1904,"props":16278,"children":16279},{"style":1932},[16280],{"type":40,"value":2005},{"type":31,"tag":1904,"props":16282,"children":16283},{"class":1906,"line":1938},[16284,16288,16292,16297,16301,16305,16309,16313,16317],{"type":31,"tag":1904,"props":16285,"children":16286},{"style":1920},[16287],{"type":40,"value":2995},{"type":31,"tag":1904,"props":16289,"children":16290},{"style":1932},[16291],{"type":40,"value":2490},{"type":31,"tag":1904,"props":16293,"children":16294},{"style":1920},[16295],{"type":40,"value":16296},"public",{"type":31,"tag":1904,"props":16298,"children":16299},{"style":1920},[16300],{"type":40,"value":3012},{"type":31,"tag":1904,"props":16302,"children":16303},{"style":1942},[16304],{"type":40,"value":11615},{"type":31,"tag":1904,"props":16306,"children":16307},{"style":1948},[16308],{"type":40,"value":1951},{"type":31,"tag":1904,"props":16310,"children":16311},{"style":1954},[16312],{"type":40,"value":2790},{"type":31,"tag":1904,"props":16314,"children":16315},{"style":1932},[16316],{"type":40,"value":1992},{"type":31,"tag":1904,"props":16318,"children":16319},{"style":1932},[16320],{"type":40,"value":2005},{"type":31,"tag":1904,"props":16322,"children":16323},{"class":1906,"line":1965},[16324,16329,16333,16338,16342,16346,16350,16355,16359],{"type":31,"tag":1904,"props":16325,"children":16326},{"style":1954},[16327],{"type":40,"value":16328},"    super",{"type":31,"tag":1904,"props":16330,"children":16331},{"style":2028},[16332],{"type":40,"value":2490},{"type":31,"tag":1904,"props":16334,"children":16335},{"style":3399},[16336],{"type":40,"value":16337},"`Slot ",{"type":31,"tag":1904,"props":16339,"children":16340},{"style":4452},[16341],{"type":40,"value":4455},{"type":31,"tag":1904,"props":16343,"children":16344},{"style":2028},[16345],{"type":40,"value":11484},{"type":31,"tag":1904,"props":16347,"children":16348},{"style":4452},[16349],{"type":40,"value":4464},{"type":31,"tag":1904,"props":16351,"children":16352},{"style":3399},[16353],{"type":40,"value":16354}," is no longer available`",{"type":31,"tag":1904,"props":16356,"children":16357},{"style":2028},[16358],{"type":40,"value":1992},{"type":31,"tag":1904,"props":16360,"children":16361},{"style":1932},[16362],{"type":40,"value":2047},{"type":31,"tag":1904,"props":16364,"children":16365},{"class":1906,"line":1986},[16366,16370,16374,16379,16383,16388],{"type":31,"tag":1904,"props":16367,"children":16368},{"style":3197},[16369],{"type":40,"value":3374},{"type":31,"tag":1904,"props":16371,"children":16372},{"style":2108},[16373],{"type":40,"value":76},{"type":31,"tag":1904,"props":16375,"children":16376},{"style":2028},[16377],{"type":40,"value":16378},"name ",{"type":31,"tag":1904,"props":16380,"children":16381},{"style":1948},[16382],{"type":40,"value":5759},{"type":31,"tag":1904,"props":16384,"children":16385},{"style":3399},[16386],{"type":40,"value":16387}," 'SlotAlreadyHeldError'",{"type":31,"tag":1904,"props":16389,"children":16390},{"style":1932},[16391],{"type":40,"value":2047},{"type":31,"tag":1904,"props":16393,"children":16394},{"class":1906,"line":2008},[16395],{"type":31,"tag":1904,"props":16396,"children":16397},{"style":1932},[16398],{"type":40,"value":2717},{"type":31,"tag":1904,"props":16400,"children":16401},{"class":1906,"line":2050},[16402],{"type":31,"tag":1904,"props":16403,"children":16404},{"style":1932},[16405],{"type":40,"value":2156},{"type":31,"tag":32,"props":16407,"children":16408},{},[16409,16411,16417,16418,16424,16426,16431,16433,16439,16441,16447],{"type":40,"value":16410},"Trois changements comptent. D'abord le recours à ",{"type":31,"tag":169,"props":16412,"children":16414},{"className":16413},[],[16415],{"type":40,"value":16416},"prisma.$transaction",{"type":40,"value":4703},{"type":31,"tag":169,"props":16419,"children":16421},{"className":16420},[],[16422],{"type":40,"value":16423},"isolationLevel: 'Serializable'",{"type":40,"value":16425}," qui rend l'opération atomique : soit tout passe, soit rien ne passe, et Postgres empêche deux transactions concurrentes de lire le même état incohérent. Ensuite l'",{"type":31,"tag":169,"props":16427,"children":16429},{"className":16428},[],[16430],{"type":40,"value":15979},{"type":40,"value":16432}," conditionnel (avec ",{"type":31,"tag":169,"props":16434,"children":16436},{"className":16435},[],[16437],{"type":40,"value":16438},"where: { status: 'AVAILABLE' }",{"type":40,"value":16440},") qui fait vérifier la condition par Postgres au moment de l'écriture, pas par la mémoire Node.js au moment de la lecture. Enfin l'exception typée ",{"type":31,"tag":169,"props":16442,"children":16444},{"className":16443},[],[16445],{"type":40,"value":16446},"SlotAlreadyHeldError",{"type":40,"value":16448}," qui porte le contexte nécessaire aux couches supérieures.",{"type":31,"tag":32,"props":16450,"children":16451},{},[16452,16454,16459,16461,16465],{"type":40,"value":16453},"Quand je prompte Claude pour ce fix, je ne dis pas \"ajoute une transaction\". Je dis : ",{"type":31,"tag":97,"props":16455,"children":16456},{},[16457],{"type":40,"value":16458},"\"Ce use case sera appelé en concurrence. Deux clients peuvent réserver le même créneau à 10 ms d'écart. Réécris-le pour qu'il reste correct sous cette contrainte, en utilisant les primitives Prisma adaptées.\"",{"type":40,"value":16460}," Le résultat est radicalement meilleur. Claude n'invente pas, il applique. Le craft consiste à lui donner le bon contexte pour qu'il applique le bon pattern, comme le formalise une vraie ",{"type":31,"tag":69,"props":16462,"children":16463},{"href":8846},[16464],{"type":40,"value":8849},{"type":40,"value":76},{"type":31,"tag":48,"props":16467,"children":16468},{},[],{"type":31,"tag":52,"props":16470,"children":16472},{"id":16471},"les-4-garde-fous-à-appliquer-dès-lundi",[16473],{"type":40,"value":16474},"Les 4 garde-fous à appliquer dès lundi",{"type":31,"tag":32,"props":16476,"children":16477},{},[16478],{"type":40,"value":16479},"Voici les 4 points que je passe systématiquement en review sur chaque PR Claude qui touche à de l'état partagé (DB, cache, fichier, queue).",{"type":31,"tag":32,"props":16481,"children":16482},{},[16483,16488,16490,16495],{"type":31,"tag":36,"props":16484,"children":16485},{},[16486],{"type":40,"value":16487},"Garde-fou 1 : la concurrence est-elle nommée explicitement ?",{"type":40,"value":16489}," Pour toute fonction qui lit puis écrit, je me pose la question : ",{"type":31,"tag":97,"props":16491,"children":16492},{},[16493],{"type":40,"value":16494},"\"Ce use case peut-il être appelé par 2 requêtes simultanées ? Si oui, que se passe-t-il ?\"",{"type":40,"value":16496}," Si la réponse est \"je ne sais pas\", la PR retourne en draft.",{"type":31,"tag":32,"props":16498,"children":16499},{},[16500,16505,16507,16512],{"type":31,"tag":36,"props":16501,"children":16502},{},[16503],{"type":40,"value":16504},"Garde-fou 2 : les écritures qui dépendent de lectures passent-elles par une transaction ?",{"type":40,"value":16506}," Pas de read-modify-write hors ",{"type":31,"tag":169,"props":16508,"children":16510},{"className":16509},[],[16511],{"type":40,"value":16416},{"type":40,"value":16513},". C'est la règle. Si Claude n'a pas utilisé une transaction avec un niveau d'isolation explicite, c'est un signal qu'il a écrit le pattern naïf.",{"type":31,"tag":32,"props":16515,"children":16516},{},[16517,16522,16523,16529,16531,16537,16539,16543],{"type":31,"tag":36,"props":16518,"children":16519},{},[16520],{"type":40,"value":16521},"Garde-fou 3 : les exceptions sont-elles typées et porteuses de contexte ?",{"type":40,"value":3668},{"type":31,"tag":169,"props":16524,"children":16526},{"className":16525},[],[16527],{"type":40,"value":16528},"throw new Error('Slot not available')",{"type":40,"value":16530}," est insuffisant. ",{"type":31,"tag":169,"props":16532,"children":16534},{"className":16533},[],[16535],{"type":40,"value":16536},"throw new SlotAlreadyHeldError(slotId)",{"type":40,"value":16538}," permet à la couche supérieure de prendre des décisions différenciées, et à l'observabilité de remonter les bons signaux. Ce détail est ce qui sépare le code junior du code senior, et c'est aussi ce qui permet de construire les ",{"type":31,"tag":69,"props":16540,"children":16541},{"href":8768},[16542],{"type":40,"value":14328},{"type":40,"value":16544}," en aval.",{"type":31,"tag":32,"props":16546,"children":16547},{},[16548,16553,16555,16560,16562,16567,16569,16574],{"type":31,"tag":36,"props":16549,"children":16550},{},[16551],{"type":40,"value":16552},"Garde-fou 4 : un test de concurrence existe-t-il ?",{"type":40,"value":16554}," Pour toute méthode critique, j'exige un test Vitest qui soumet le use case en parallèle via ",{"type":31,"tag":169,"props":16556,"children":16558},{"className":16557},[],[16559],{"type":40,"value":4120},{"type":40,"value":16561}," sur le même créneau, et qui vérifie que l'état final est cohérent (un seul ",{"type":31,"tag":169,"props":16563,"children":16565},{"className":16564},[],[16566],{"type":40,"value":15049},{"type":40,"value":16568},", une seule erreur ",{"type":31,"tag":169,"props":16570,"children":16572},{"className":16571},[],[16573],{"type":40,"value":16446},{"type":40,"value":16575},"). Si ce test n'existe pas, Claude ne l'a pas écrit. C'est à la review de l'exiger.",{"type":31,"tag":1894,"props":16577,"children":16579},{"className":1896,"code":16578,"language":1898,"meta":8,"style":8},"// Exemple de test de concurrence Vitest\nit('ne doit accorder le créneau qu'à un seul client en concurrence', async () => {\n  const slotId = 'slot-test-id';\n  const results = await Promise.allSettled([\n    holdSlotUseCase.execute(slotId, 'client-A'),\n    holdSlotUseCase.execute(slotId, 'client-B'),\n  ]);\n\n  const fulfilled = results.filter((r) => r.status === 'fulfilled');\n  const rejected = results.filter((r) => r.status === 'rejected');\n\n  expect(fulfilled).toHaveLength(1);\n  expect(rejected).toHaveLength(1);\n  expect((rejected[0] as PromiseRejectedResult).reason).toBeInstanceOf(SlotAlreadyHeldError);\n});\n",[16580],{"type":31,"tag":169,"props":16581,"children":16582},{"__ignoreMap":8},[16583,16591,16622,16643,16676,16714,16750,16758,16765,16834,16902,16909,16942,16974,17031],{"type":31,"tag":1904,"props":16584,"children":16585},{"class":1906,"line":1907},[16586],{"type":31,"tag":1904,"props":16587,"children":16588},{"style":1911},[16589],{"type":40,"value":16590},"// Exemple de test de concurrence Vitest\n",{"type":31,"tag":1904,"props":16592,"children":16593},{"class":1906,"line":817},[16594,16598,16602,16607,16612,16617],{"type":31,"tag":1904,"props":16595,"children":16596},{"style":1926},[16597],{"type":40,"value":4839},{"type":31,"tag":1904,"props":16599,"children":16600},{"style":2028},[16601],{"type":40,"value":2490},{"type":31,"tag":1904,"props":16603,"children":16604},{"style":3399},[16605],{"type":40,"value":16606},"'ne doit accorder le créneau qu'",{"type":31,"tag":1904,"props":16608,"children":16609},{"style":2028},[16610],{"type":40,"value":16611},"à un seul client en concurrence",{"type":31,"tag":1904,"props":16613,"children":16614},{"style":3399},[16615],{"type":40,"value":16616},"', async () => ",{"type":31,"tag":1904,"props":16618,"children":16620},{"style":16619},"--shiki-default:#A6D189;--shiki-default-font-style:inherit;--shiki-dark:#FDAEB7;--shiki-dark-font-style:italic",[16621],{"type":40,"value":3264},{"type":31,"tag":1904,"props":16623,"children":16624},{"class":1906,"line":1938},[16625,16630,16634,16639],{"type":31,"tag":1904,"props":16626,"children":16627},{"style":2028},[16628],{"type":40,"value":16629},"  const slotId ",{"type":31,"tag":1904,"props":16631,"children":16632},{"style":1948},[16633],{"type":40,"value":5759},{"type":31,"tag":1904,"props":16635,"children":16636},{"style":3399},[16637],{"type":40,"value":16638}," 'slot-test-id'",{"type":31,"tag":1904,"props":16640,"children":16641},{"style":2028},[16642],{"type":40,"value":2047},{"type":31,"tag":1904,"props":16644,"children":16645},{"class":1906,"line":1965},[16646,16651,16655,16659,16663,16667,16671],{"type":31,"tag":1904,"props":16647,"children":16648},{"style":2028},[16649],{"type":40,"value":16650},"  const results ",{"type":31,"tag":1904,"props":16652,"children":16653},{"style":1948},[16654],{"type":40,"value":5759},{"type":31,"tag":1904,"props":16656,"children":16657},{"style":1920},[16658],{"type":40,"value":3194},{"type":31,"tag":1904,"props":16660,"children":16661},{"style":5264},[16662],{"type":40,"value":3152},{"type":31,"tag":1904,"props":16664,"children":16665},{"style":2108},[16666],{"type":40,"value":76},{"type":31,"tag":1904,"props":16668,"children":16669},{"style":1926},[16670],{"type":40,"value":5275},{"type":31,"tag":1904,"props":16672,"children":16673},{"style":2028},[16674],{"type":40,"value":16675},"([\n",{"type":31,"tag":1904,"props":16677,"children":16678},{"class":1906,"line":1986},[16679,16684,16688,16692,16697,16701,16706,16710],{"type":31,"tag":1904,"props":16680,"children":16681},{"style":2028},[16682],{"type":40,"value":16683},"    holdSlotUseCase",{"type":31,"tag":1904,"props":16685,"children":16686},{"style":2108},[16687],{"type":40,"value":76},{"type":31,"tag":1904,"props":16689,"children":16690},{"style":1926},[16691],{"type":40,"value":12713},{"type":31,"tag":1904,"props":16693,"children":16694},{"style":2028},[16695],{"type":40,"value":16696},"(slotId",{"type":31,"tag":1904,"props":16698,"children":16699},{"style":1932},[16700],{"type":40,"value":4853},{"type":31,"tag":1904,"props":16702,"children":16703},{"style":3399},[16704],{"type":40,"value":16705}," 'client-A'",{"type":31,"tag":1904,"props":16707,"children":16708},{"style":2028},[16709],{"type":40,"value":1992},{"type":31,"tag":1904,"props":16711,"children":16712},{"style":1932},[16713],{"type":40,"value":1962},{"type":31,"tag":1904,"props":16715,"children":16716},{"class":1906,"line":2008},[16717,16721,16725,16729,16733,16737,16742,16746],{"type":31,"tag":1904,"props":16718,"children":16719},{"style":2028},[16720],{"type":40,"value":16683},{"type":31,"tag":1904,"props":16722,"children":16723},{"style":2108},[16724],{"type":40,"value":76},{"type":31,"tag":1904,"props":16726,"children":16727},{"style":1926},[16728],{"type":40,"value":12713},{"type":31,"tag":1904,"props":16730,"children":16731},{"style":2028},[16732],{"type":40,"value":16696},{"type":31,"tag":1904,"props":16734,"children":16735},{"style":1932},[16736],{"type":40,"value":4853},{"type":31,"tag":1904,"props":16738,"children":16739},{"style":3399},[16740],{"type":40,"value":16741}," 'client-B'",{"type":31,"tag":1904,"props":16743,"children":16744},{"style":2028},[16745],{"type":40,"value":1992},{"type":31,"tag":1904,"props":16747,"children":16748},{"style":1932},[16749],{"type":40,"value":1962},{"type":31,"tag":1904,"props":16751,"children":16752},{"class":1906,"line":2050},[16753],{"type":31,"tag":1904,"props":16754,"children":16755},{"style":2028},[16756],{"type":40,"value":16757},"  ]);\n",{"type":31,"tag":1904,"props":16759,"children":16760},{"class":1906,"line":2094},[16761],{"type":31,"tag":1904,"props":16762,"children":16763},{"emptyLinePlaceholder":13},[16764],{"type":40,"value":2165},{"type":31,"tag":1904,"props":16766,"children":16767},{"class":1906,"line":2150},[16768,16773,16777,16781,16785,16789,16793,16797,16801,16805,16809,16813,16817,16821,16825,16830],{"type":31,"tag":1904,"props":16769,"children":16770},{"style":2028},[16771],{"type":40,"value":16772},"  const fulfilled ",{"type":31,"tag":1904,"props":16774,"children":16775},{"style":1948},[16776],{"type":40,"value":5759},{"type":31,"tag":1904,"props":16778,"children":16779},{"style":2028},[16780],{"type":40,"value":5253},{"type":31,"tag":1904,"props":16782,"children":16783},{"style":2108},[16784],{"type":40,"value":76},{"type":31,"tag":1904,"props":16786,"children":16787},{"style":1926},[16788],{"type":40,"value":5385},{"type":31,"tag":1904,"props":16790,"children":16791},{"style":2028},[16792],{"type":40,"value":2490},{"type":31,"tag":1904,"props":16794,"children":16795},{"style":1932},[16796],{"type":40,"value":2490},{"type":31,"tag":1904,"props":16798,"children":16799},{"style":1942},[16800],{"type":40,"value":5398},{"type":31,"tag":1904,"props":16802,"children":16803},{"style":1932},[16804],{"type":40,"value":1992},{"type":31,"tag":1904,"props":16806,"children":16807},{"style":1948},[16808],{"type":40,"value":4868},{"type":31,"tag":1904,"props":16810,"children":16811},{"style":2028},[16812],{"type":40,"value":5411},{"type":31,"tag":1904,"props":16814,"children":16815},{"style":2108},[16816],{"type":40,"value":76},{"type":31,"tag":1904,"props":16818,"children":16819},{"style":2028},[16820],{"type":40,"value":5420},{"type":31,"tag":1904,"props":16822,"children":16823},{"style":1948},[16824],{"type":40,"value":5425},{"type":31,"tag":1904,"props":16826,"children":16827},{"style":3399},[16828],{"type":40,"value":16829}," 'fulfilled'",{"type":31,"tag":1904,"props":16831,"children":16832},{"style":2028},[16833],{"type":40,"value":14251},{"type":31,"tag":1904,"props":16835,"children":16836},{"class":1906,"line":2159},[16837,16842,16846,16850,16854,16858,16862,16866,16870,16874,16878,16882,16886,16890,16894,16898],{"type":31,"tag":1904,"props":16838,"children":16839},{"style":2028},[16840],{"type":40,"value":16841},"  const rejected ",{"type":31,"tag":1904,"props":16843,"children":16844},{"style":1948},[16845],{"type":40,"value":5759},{"type":31,"tag":1904,"props":16847,"children":16848},{"style":2028},[16849],{"type":40,"value":5253},{"type":31,"tag":1904,"props":16851,"children":16852},{"style":2108},[16853],{"type":40,"value":76},{"type":31,"tag":1904,"props":16855,"children":16856},{"style":1926},[16857],{"type":40,"value":5385},{"type":31,"tag":1904,"props":16859,"children":16860},{"style":2028},[16861],{"type":40,"value":2490},{"type":31,"tag":1904,"props":16863,"children":16864},{"style":1932},[16865],{"type":40,"value":2490},{"type":31,"tag":1904,"props":16867,"children":16868},{"style":1942},[16869],{"type":40,"value":5398},{"type":31,"tag":1904,"props":16871,"children":16872},{"style":1932},[16873],{"type":40,"value":1992},{"type":31,"tag":1904,"props":16875,"children":16876},{"style":1948},[16877],{"type":40,"value":4868},{"type":31,"tag":1904,"props":16879,"children":16880},{"style":2028},[16881],{"type":40,"value":5411},{"type":31,"tag":1904,"props":16883,"children":16884},{"style":2108},[16885],{"type":40,"value":76},{"type":31,"tag":1904,"props":16887,"children":16888},{"style":2028},[16889],{"type":40,"value":5420},{"type":31,"tag":1904,"props":16891,"children":16892},{"style":1948},[16893],{"type":40,"value":5425},{"type":31,"tag":1904,"props":16895,"children":16896},{"style":3399},[16897],{"type":40,"value":5430},{"type":31,"tag":1904,"props":16899,"children":16900},{"style":2028},[16901],{"type":40,"value":14251},{"type":31,"tag":1904,"props":16903,"children":16904},{"class":1906,"line":2168},[16905],{"type":31,"tag":1904,"props":16906,"children":16907},{"emptyLinePlaceholder":13},[16908],{"type":40,"value":2165},{"type":31,"tag":1904,"props":16910,"children":16911},{"class":1906,"line":2177},[16912,16916,16921,16925,16929,16933,16938],{"type":31,"tag":1904,"props":16913,"children":16914},{"style":1926},[16915],{"type":40,"value":5446},{"type":31,"tag":1904,"props":16917,"children":16918},{"style":2028},[16919],{"type":40,"value":16920},"(fulfilled)",{"type":31,"tag":1904,"props":16922,"children":16923},{"style":2108},[16924],{"type":40,"value":76},{"type":31,"tag":1904,"props":16926,"children":16927},{"style":1926},[16928],{"type":40,"value":5460},{"type":31,"tag":1904,"props":16930,"children":16931},{"style":2028},[16932],{"type":40,"value":2490},{"type":31,"tag":1904,"props":16934,"children":16935},{"style":2039},[16936],{"type":40,"value":16937},"1",{"type":31,"tag":1904,"props":16939,"children":16940},{"style":2028},[16941],{"type":40,"value":14251},{"type":31,"tag":1904,"props":16943,"children":16944},{"class":1906,"line":2194},[16945,16949,16954,16958,16962,16966,16970],{"type":31,"tag":1904,"props":16946,"children":16947},{"style":1926},[16948],{"type":40,"value":5446},{"type":31,"tag":1904,"props":16950,"children":16951},{"style":2028},[16952],{"type":40,"value":16953},"(rejected)",{"type":31,"tag":1904,"props":16955,"children":16956},{"style":2108},[16957],{"type":40,"value":76},{"type":31,"tag":1904,"props":16959,"children":16960},{"style":1926},[16961],{"type":40,"value":5460},{"type":31,"tag":1904,"props":16963,"children":16964},{"style":2028},[16965],{"type":40,"value":2490},{"type":31,"tag":1904,"props":16967,"children":16968},{"style":2039},[16969],{"type":40,"value":16937},{"type":31,"tag":1904,"props":16971,"children":16972},{"style":2028},[16973],{"type":40,"value":14251},{"type":31,"tag":1904,"props":16975,"children":16976},{"class":1906,"line":2215},[16977,16981,16986,16990,16995,16999,17004,17008,17012,17017,17021,17026],{"type":31,"tag":1904,"props":16978,"children":16979},{"style":1926},[16980],{"type":40,"value":5446},{"type":31,"tag":1904,"props":16982,"children":16983},{"style":2028},[16984],{"type":40,"value":16985},"((rejected[",{"type":31,"tag":1904,"props":16987,"children":16988},{"style":2039},[16989],{"type":40,"value":5469},{"type":31,"tag":1904,"props":16991,"children":16992},{"style":2028},[16993],{"type":40,"value":16994},"] ",{"type":31,"tag":1904,"props":16996,"children":16997},{"style":1920},[16998],{"type":40,"value":5915},{"type":31,"tag":1904,"props":17000,"children":17001},{"style":2470},[17002],{"type":40,"value":17003}," PromiseRejectedResult",{"type":31,"tag":1904,"props":17005,"children":17006},{"style":2028},[17007],{"type":40,"value":1992},{"type":31,"tag":1904,"props":17009,"children":17010},{"style":2108},[17011],{"type":40,"value":76},{"type":31,"tag":1904,"props":17013,"children":17014},{"style":2028},[17015],{"type":40,"value":17016},"reason)",{"type":31,"tag":1904,"props":17018,"children":17019},{"style":2108},[17020],{"type":40,"value":76},{"type":31,"tag":1904,"props":17022,"children":17023},{"style":1926},[17024],{"type":40,"value":17025},"toBeInstanceOf",{"type":31,"tag":1904,"props":17027,"children":17028},{"style":2028},[17029],{"type":40,"value":17030},"(SlotAlreadyHeldError);\n",{"type":31,"tag":1904,"props":17032,"children":17033},{"class":1906,"line":2236},[17034,17039],{"type":31,"tag":1904,"props":17035,"children":17036},{"style":2028},[17037],{"type":40,"value":17038},"})",{"type":31,"tag":1904,"props":17040,"children":17041},{"style":1932},[17042],{"type":40,"value":2047},{"type":31,"tag":32,"props":17044,"children":17045},{},[17046],{"type":40,"value":17047},"Ces 4 garde-fous tiennent en 2 minutes par PR. Ils attrapent 90% des bugs de concurrence que j'ai vus passer en prod sur des codebases IA-heavy. Le coût d'application est bas. Le coût d'omission peut, lui, se chiffrer en heures de débogage sur un incident un vendredi soir.",{"type":31,"tag":48,"props":17049,"children":17050},{},[],{"type":31,"tag":52,"props":17052,"children":17053},{"id":1463},[17054],{"type":40,"value":1466},{"type":31,"tag":32,"props":17056,"children":17057},{},[17058],{"type":40,"value":17059},"Sur les 3 dernières missions où j'ai déployé cette grille de review, voici les chiffres avant/après mesurés sur 4 mois.",{"type":31,"tag":398,"props":17061,"children":17062},{},[17063,17082],{"type":31,"tag":402,"props":17064,"children":17065},{},[17066],{"type":31,"tag":406,"props":17067,"children":17068},{},[17069,17073,17077],{"type":31,"tag":410,"props":17070,"children":17071},{},[17072],{"type":40,"value":1198},{"type":31,"tag":410,"props":17074,"children":17075},{},[17076],{"type":40,"value":14641},{"type":31,"tag":410,"props":17078,"children":17079},{},[17080],{"type":40,"value":17081},"Après 4 mois",{"type":31,"tag":426,"props":17083,"children":17084},{},[17085,17103,17121,17139],{"type":31,"tag":406,"props":17086,"children":17087},{},[17088,17093,17098],{"type":31,"tag":433,"props":17089,"children":17090},{},[17091],{"type":40,"value":17092},"Bugs de concurrence trouvés en review",{"type":31,"tag":433,"props":17094,"children":17095},{},[17096],{"type":40,"value":17097},"2 par mois en moyenne",{"type":31,"tag":433,"props":17099,"children":17100},{},[17101],{"type":40,"value":17102},"11 par mois en moyenne",{"type":31,"tag":406,"props":17104,"children":17105},{},[17106,17111,17116],{"type":31,"tag":433,"props":17107,"children":17108},{},[17109],{"type":40,"value":17110},"Bugs de concurrence remontés depuis la prod",{"type":31,"tag":433,"props":17112,"children":17113},{},[17114],{"type":40,"value":17115},"5 par trimestre",{"type":31,"tag":433,"props":17117,"children":17118},{},[17119],{"type":40,"value":17120},"1 par trimestre",{"type":31,"tag":406,"props":17122,"children":17123},{},[17124,17129,17134],{"type":31,"tag":433,"props":17125,"children":17126},{},[17127],{"type":40,"value":17128},"Temps moyen de review d'une PR Claude",{"type":31,"tag":433,"props":17130,"children":17131},{},[17132],{"type":40,"value":17133},"8 minutes",{"type":31,"tag":433,"props":17135,"children":17136},{},[17137],{"type":40,"value":17138},"11 minutes",{"type":31,"tag":406,"props":17140,"children":17141},{},[17142,17147,17151],{"type":31,"tag":433,"props":17143,"children":17144},{},[17145],{"type":40,"value":17146},"Confiance équipe dans le code IA-généré (sondage 1-10)",{"type":31,"tag":433,"props":17148,"children":17149},{},[17150],{"type":40,"value":1301},{"type":31,"tag":433,"props":17152,"children":17153},{},[17154],{"type":40,"value":17155},"8,1",{"type":31,"tag":32,"props":17157,"children":17158},{},[17159,17161,17166],{"type":40,"value":17160},"Le coût est de 3 minutes supplémentaires par PR. Le gain est de 4 bugs de prod évités par trimestre. Sur une équipe de 5 développeurs avec 60 PR par mois, c'est environ 3 heures par semaine investies pour éviter 8 à 12 incidents par an. Le rapport est nettement favorable. C'est aussi ce qu'une ",{"type":31,"tag":69,"props":17162,"children":17163},{"href":148},[17164],{"type":40,"value":17165},"revue de code structurée et appliquée à l'ère IA",{"type":40,"value":17167}," permet d'enclencher : pas un contrôle qualité figé, mais un filet adaptatif qui suit là où l'IA produit ses angles morts.",{"type":31,"tag":48,"props":17169,"children":17170},{},[],{"type":31,"tag":229,"props":17172,"children":17174},{"cta":673,"href":674,"title":17173,"type":676},"Ces 4 garde-fous ne sont qu'un début : il en existe 100",[17175],{"type":31,"tag":32,"props":17176,"children":17177},{},[17178],{"type":40,"value":17179},"La grille de review concurrence décrite ici fait partie d'un référentiel plus large : le Craft Bundle, les 100 pratiques craft que j'applique pour écrire du code propre et robuste, celles que l'IA ne vous apprendra jamais parce qu'elle ne les a jamais vues tourner en prod. De quoi transformer vos réflexes, une pratique à la fois.",{"type":31,"tag":48,"props":17181,"children":17182},{},[],{"type":31,"tag":52,"props":17184,"children":17185},{"id":637},[17186],{"type":40,"value":640},{"type":31,"tag":32,"props":17188,"children":17189},{},[17190],{"type":40,"value":17191},"Ce que je veux que vous reteniez de cet article, c'est que Claude n'écrit pas de bugs au sens où on l'entendait avant. Il écrit du code qui passe les tests qu'on lui demande de passer, dans les conditions qu'on lui décrit. Quand ces conditions ne couvrent pas la concurrence, la latence réseau, les partial failures, le code est silencieusement faux. Le bug est là, mais il dort.",{"type":31,"tag":32,"props":17193,"children":17194},{},[17195],{"type":40,"value":17196},"Votre rôle de senior, en 2026, n'est pas de relire les accolades. C'est de poser à chaque PR Claude les 4 questions que l'IA ne se pose pas elle-même. Si vous tenez cette discipline, vous transformez Claude d'un junior risqué en un copilote fiable. Si vous la lâchez, vous accumulez de la dette qui se révèlera un vendredi soir, quand il ne faudra surtout pas qu'elle se révèle.",{"type":31,"tag":32,"props":17198,"children":17199},{},[17200],{"type":40,"value":17201},"Si en lisant ces lignes vous reconnaissez votre situation, vous avez deux choix. Vous pouvez attendre votre prochain incident pour réagir. Ou vous pouvez commencer lundi matin, par une grille de review en 4 points, et apprendre à voir ce que Claude vous fait coder sans que vous le sachiez.",{"type":31,"tag":32,"props":17203,"children":17204},{},[17205,17207,17212],{"type":40,"value":17206},"Pour la suite des patterns craft + IA en format court, retrouvez-moi sur ",{"type":31,"tag":69,"props":17208,"children":17210},{"href":663,"rel":17209},[665],[17211],{"type":40,"value":668},{"type":40,"value":17213},", où je publie chaque semaine les pièges que je vois revenir en mission.",{"type":31,"tag":48,"props":17215,"children":17216},{},[],{"type":31,"tag":52,"props":17218,"children":17220},{"id":17219},"faq-sur-les-bugs-claude-et-la-review-ia-générée",[17221],{"type":40,"value":17222},"FAQ sur les bugs Claude et la review IA-générée",{"type":31,"tag":693,"props":17224,"children":17225},{},[17226,17231],{"type":31,"tag":697,"props":17227,"children":17228},{},[17229],{"type":40,"value":17230},"1. Comment justifier auprès de mon équipe le temps supplémentaire de review ?",{"type":31,"tag":32,"props":17232,"children":17233},{},[17234,17236,17240],{"type":40,"value":17235},"Le calcul est simple. 3 minutes de review supplémentaires par PR, sur 60 PR par mois, c'est 3 heures par mois. Un seul incident de race condition en prod sur une fonctionnalité critique peut coûter entre 5 000 et 50 000 euros en remédiation, perte de confiance client et heures de war room. Le ROI est calculable et défendable devant n'importe quel CTO, et c'est exactement l'angle que je détaille dans ",{"type":31,"tag":69,"props":17237,"children":17238},{"href":3629},[17239],{"type":40,"value":3632},{"type":40,"value":76},{"type":31,"tag":693,"props":17242,"children":17243},{},[17244,17249],{"type":31,"tag":697,"props":17245,"children":17246},{},[17247],{"type":40,"value":17248},"2. Faut-il refuser systématiquement les PR Claude qui touchent à l'état partagé ?",{"type":31,"tag":32,"props":17250,"children":17251},{},[17252],{"type":40,"value":17253},"Non, ce serait contre-productif et casserait la vélocité. Ce qu'il faut, c'est instrumenter la review avec les 4 garde-fous décrits ici, et exiger explicitement que Claude soit re-prompté avec le contexte de concurrence quand il manque. Le test : si vous ne savez pas répondre à \"que se passe-t-il si 2 appels simultanés\", la PR retourne en draft.",{"type":31,"tag":693,"props":17255,"children":17256},{},[17257,17262],{"type":31,"tag":697,"props":17258,"children":17259},{},[17260],{"type":40,"value":17261},"3. Les tests automatisés ne devraient-ils pas attraper ces bugs ?",{"type":31,"tag":32,"props":17263,"children":17264},{},[17265,17267,17272,17274,17278],{"type":40,"value":17266},"En théorie oui, en pratique non. Les tests unitaires mockent la DB, donc ils ne voient pas la concurrence. Les tests d'intégration tournent en séquentiel par défaut, donc ils ne déclenchent pas la race. Il faut écrire des tests de concurrence explicites (via ",{"type":31,"tag":169,"props":17268,"children":17270},{"className":17269},[],[17271],{"type":40,"value":4120},{"type":40,"value":17273}," sur la même ressource en Vitest), et ces tests, Claude ne les écrit jamais spontanément. C'est aussi ce que pointe ",{"type":31,"tag":69,"props":17275,"children":17276},{"href":219},[17277],{"type":40,"value":4079},{"type":40,"value":76},{"type":31,"tag":693,"props":17280,"children":17281},{},[17282,17287],{"type":31,"tag":697,"props":17283,"children":17284},{},[17285],{"type":40,"value":17286},"4. Quels autres patterns dangereux faut-il surveiller dans le code Claude ?",{"type":31,"tag":32,"props":17288,"children":17289},{},[17290],{"type":40,"value":17291},"J'en ai documenté 5 récurrents : la God Function, le couplage métier/ORM, les tests qui ne testent rien, le catch-all silencieux et les dépendances non auditées. Chacun mérite un traitement spécifique en review. Le sujet est aussi lié aux vulnérabilités de sécurité dans le code LLM-généré pour les patterns les plus sensibles.",{"type":31,"tag":693,"props":17293,"children":17294},{},[17295,17300],{"type":31,"tag":697,"props":17296,"children":17297},{},[17298],{"type":40,"value":17299},"5. Comment former mon équipe à voir ces bugs sans alourdir la charge cognitive ?",{"type":31,"tag":32,"props":17301,"children":17302},{},[17303],{"type":40,"value":17304},"La meilleure méthode que j'ai vue fonctionner, c'est de transformer la grille en 4 garde-fous en checklist GitHub PR template, visible à chaque review. Les juniors la suivent par discipline, les seniors la suivent par réflexe, et au bout de 3 mois tout le monde l'a intégrée sans s'en rendre compte. Le rituel s'inscrit dans une culture engineering de rituels craft qui transforme les bonnes intentions en habitudes durables.",{"type":31,"tag":693,"props":17306,"children":17307},{},[17308,17313],{"type":31,"tag":697,"props":17309,"children":17310},{},[17311],{"type":40,"value":17312},"6. Est-ce que ce problème va disparaître avec les prochaines versions de Claude ?",{"type":31,"tag":32,"props":17314,"children":17315},{},[17316],{"type":40,"value":17317},"Non, et c'est important de le comprendre. Le problème n'est pas dans la qualité du modèle, il est dans l'absence de contexte d'exécution au moment de la génération. Tant que Claude génère du code sans observer la prod réelle (charge, concurrence, latence), il continuera à produire des patterns qui passent les tests et plantent sous contrainte. L'amélioration viendra des outils d'exécution autour de l'IA, pas du modèle lui-même.",{"type":31,"tag":48,"props":17319,"children":17320},{},[],{"type":31,"tag":229,"props":17322,"children":17323},{"cta":806,"href":807,"title":808,"type":809},[17324],{"type":31,"tag":32,"props":17325,"children":17326},{},[17327],{"type":40,"value":17328},"L'EMA est l'outil que je propose au début de chaque mission. Il mesure la maturité de votre équipe sur plusieurs axes engineering, dont la code review, la gouvernance IA et la résilience prod. Quelques minutes pour identifier où votre filet de review craque le plus, et où concentrer vos efforts en priorité.",{"type":31,"tag":4005,"props":17330,"children":17331},{},[17332],{"type":40,"value":4009},{"title":8,"searchDepth":817,"depth":817,"links":17334},[17335,17336,17337,17338,17339,17340,17341],{"id":15009,"depth":817,"text":15012},{"id":15102,"depth":817,"text":15105},{"id":15705,"depth":817,"text":15708},{"id":16471,"depth":817,"text":16474},{"id":1463,"depth":817,"text":1466},{"id":637,"depth":817,"text":640},{"id":17219,"depth":817,"text":17222},"content:fr:intelligence-artificielle:bug-claude-vendredi-dernier.md","fr/intelligence-artificielle/bug-claude-vendredi-dernier.md","fr/intelligence-artificielle/bug-claude-vendredi-dernier",1782669247376]