[{"data":1,"prerenderedAt":10122},["ShallowReactive",2],{"search-api":-1,"listing-tag-software-craftsmanship-page-1":3},[4,973,1756,7709],{"_path":5,"_dir":6,"_draft":7,"_partial":7,"_locale":8,"title":9,"description":10,"id":11,"date":12,"listed":13,"nocomments":7,"hidden":7,"categories":14,"tags":15,"cover":20,"readingTime":21,"body":26,"_type":967,"_id":968,"_source":969,"_file":970,"_stem":971,"_extension":972},"/fr/dette-technique/5-raisons-app-meurt-18-mois","dette-technique",false,"","5 raisons pour lesquelles votre app meurt à 18 mois (et 5 pratiques pour 10 ans)","On dit code legacy comme si c'était une fatalité. La plupart des apps meurent à 18 mois pour 5 raisons craft précises. Voici lesquelles, et comment tenir.",69,"2026-05-25",true,[6],[6,16,17,18,19],"software-craftsmanship","ddd","adr","code-durable","covers/articles/5-raisons-app-meurt-18-mois.jpg",{"text":22,"minutes":23,"time":24,"words":25},"15 min read",14.865,891900,2973,{"type":27,"children":28,"toc":954},"root",[29,49,54,58,65,77,82,96,118,140,143,149,166,176,193,206,211,214,220,229,238,256,334,339,342,348,357,366,383,388,391,404,407,413,422,431,441,454,457,463,472,481,491,496,509,512,518,523,531,536,629,634,637,643,648,783,796,799,805,810,815,820,831,843,846,852,867,880,893,906,926,939,942],{"type":30,"tag":31,"props":32,"children":33},"element","p",{},[34],{"type":30,"tag":35,"props":36,"children":37},"strong",{},[38,41,47],{"type":39,"value":40},"text","En 2024, j'ai assisté en consultant externe à la décision de réécrire complètement une application chez un client dans le secteur bancaire. L'app avait 22 mois. 480 000 lignes de code. Toute l'équipe d'origine était partie. Le coût de modification d'une feature simple était devenu prohibitif. Le verdict du CTO : ",{"type":30,"tag":42,"props":43,"children":44},"em",{},[45],{"type":39,"value":46},"\"on repart de zéro, c'est moins cher.\"",{"type":39,"value":48}," Cette phrase, je l'ai entendue 7 fois en 25 ans. Et à chaque fois, ce n'est pas le temps qui a tué l'application. C'est 5 choix craft qui n'avaient pas été faits.",{"type":30,"tag":31,"props":50,"children":51},{},[52],{"type":39,"value":53},"Cet article est le compagnon de fond de la série sur le code durable. Voici les 5 raisons systémiques de la mort à 18 mois, et les 5 pratiques craft qui changent radicalement la trajectoire.",{"type":30,"tag":55,"props":56,"children":57},"hr",{},[],{"type":30,"tag":59,"props":60,"children":62},"h2",{"id":61},"le-mythe-de-lappli-qui-meurt-parce-quelle-vieillit",[63],{"type":39,"value":64},"Le mythe de l'appli qui meurt parce qu'elle vieillit",{"type":30,"tag":31,"props":66,"children":67},{},[68,70,75],{"type":39,"value":69},"On parle de ",{"type":30,"tag":42,"props":71,"children":72},{},[73],{"type":39,"value":74},"\"code legacy\"",{"type":39,"value":76}," comme si c'était une fatalité du temps. Comme si toute application atteignait fatalement un point où elle devenait impossible à maintenir. C'est faux, et c'est démontré.",{"type":30,"tag":31,"props":78,"children":79},{},[80],{"type":39,"value":81},"Sur les 11 codebases bancaires que j'ai auditées depuis 2024, j'ai trouvé une application de 19 ans encore activement développée, lisible, modifiable, avec un onboarding nouvel-arrivant de 3 semaines. À côté, j'ai vu 4 applications de moins de 24 mois où le CTO planifiait une réécriture parce que la modification coûtait trop cher.",{"type":30,"tag":31,"props":83,"children":84},{},[85,87,94],{"type":39,"value":86},"Le facteur âge n'est pas la variable explicative. Le facteur discipline craft l'est. Selon la classification du ",{"type":30,"tag":88,"props":89,"children":91},"a",{"href":90},"/fr/dette-technique/introduction-maturite-engineering-5-niveaux",[92],{"type":39,"value":93},"niveau de maturité engineering",{"type":39,"value":95}," que j'utilise en mission, une équipe de niveau 3+ peut maintenir une application 10 à 15 ans sans réécriture majeure. Une équipe de niveau 1-2 voit la fatigue de codebase apparaître à 12-18 mois.",{"type":30,"tag":97,"props":98,"children":99},"blockquote",{},[100],{"type":30,"tag":31,"props":101,"children":102},{},[103,108,110,116],{"type":30,"tag":35,"props":104,"children":105},{},[106],{"type":39,"value":107},"Ce que j'ai observé",{"type":39,"value":109}," : dans l'équipe bancaire dont je parle en intro, j'ai fait un audit post-mortem du repo en cours de mort. Les 5 mécanismes ci-dessous étaient tous présents. Aucun n'avait été identifié pendant la vie de l'application. Tous auraient pu être évités avec une discipline craft installée dès les 3 premiers mois, en s'inspirant des ",{"type":30,"tag":88,"props":111,"children":113},{"href":112},"/fr/dette-technique/clean-code-software-craftsmanship-principes-java",[114],{"type":39,"value":115},"principes Clean Code et software craftsmanship",{"type":39,"value":117}," que je rappelle systématiquement.",{"type":30,"tag":31,"props":119,"children":120},{},[121,123,131,133,138],{"type":39,"value":122},"Cet article s'appuie aussi sur ce que je vois revenir dans les Reels storytelling que je publie sur ",{"type":30,"tag":88,"props":124,"children":128},{"href":125,"rel":126},"https://www.instagram.com/kamangacode/",[127],"nofollow",[129],{"type":39,"value":130},"mon profil Instagram kamangacode",{"type":39,"value":132},". Le cas n°1 du ",{"type":30,"tag":42,"props":134,"children":135},{},[136],{"type":39,"value":137},"\"projet que j'ai vu mourir à 18 mois\"",{"type":39,"value":139}," est celui-ci. Et il est rejouable autant de fois qu'on veut. Voici comment ne plus jamais le rejouer.",{"type":30,"tag":55,"props":141,"children":142},{},[],{"type":30,"tag":59,"props":144,"children":146},{"id":145},"raison-1-aucun-pourquoi-tracé-et-la-pratique-adr",[147],{"type":39,"value":148},"Raison #1 : aucun POURQUOI tracé (et la pratique ADR)",{"type":30,"tag":31,"props":150,"children":151},{},[152,157,159,164],{"type":30,"tag":35,"props":153,"children":154},{},[155],{"type":39,"value":156},"Symptôme",{"type":39,"value":158}," : à 12 mois, plus personne dans l'équipe ne sait ",{"type":30,"tag":42,"props":160,"children":161},{},[162],{"type":39,"value":163},"pourquoi",{"type":39,"value":165}," on a choisi cette architecture, ce framework, ce pattern. Chaque refacto devient une redécouverte du métier. Le coût n'est pas dans le code, il est dans la fouille archéologique.",{"type":30,"tag":31,"props":167,"children":168},{},[169,174],{"type":30,"tag":35,"props":170,"children":171},{},[172],{"type":39,"value":173},"Mécanisme",{"type":39,"value":175}," : pendant les 3 premiers mois d'une app, les décisions architecturales sont prises rapidement, oralement, en stand-up ou en pair. Personne ne les trace. Six mois plus tard, le développeur qui a pris la décision part. Douze mois plus tard, la décision est devenue une coutume non expliquée. À 18 mois, c'est une contrainte non négociée dont plus personne ne se souvient de la raison.",{"type":30,"tag":31,"props":177,"children":178},{},[179,184,186,191],{"type":30,"tag":35,"props":180,"children":181},{},[182],{"type":39,"value":183},"Pratique craft : ADR (Architecture Decision Records).",{"type":39,"value":185}," Michael Nygard a écrit en 2011 l'article fondateur ",{"type":30,"tag":42,"props":187,"children":188},{},[189],{"type":39,"value":190},"\"Documenting Architecture Decisions\"",{"type":39,"value":192}," qui propose un format ultra-minimaliste : Contexte, Options envisagées, Décision, Conséquences. 15 lignes. 30 minutes à rédiger. Versionné dans le repo comme du code.",{"type":30,"tag":31,"props":194,"children":195},{},[196,198,204],{"type":39,"value":197},"Sur le repo crmcoaching que je maintiens depuis 6 mois, je suis à 52 ADRs. Chaque décision structurante (choix de stack, pattern, dépendance, trade-off) a sa trace. Quand je revisite une décision 4 mois plus tard, je retrouve mon raisonnement en 30 secondes. Quand un nouveau dev arrive, il lit la collection d'ADRs comme une généalogie de l'application. C'est exactement ce que recommande ",{"type":30,"tag":88,"props":199,"children":201},{"href":200},"/fr/architecture-craft/adr-architecture-decision-record",[202],{"type":39,"value":203},"la pratique des ADR pour les décisions structurantes",{"type":39,"value":205},".",{"type":30,"tag":31,"props":207,"children":208},{},[209],{"type":39,"value":210},"Sur les missions où j'installe cette discipline, le ratio ADR / 100 commits passe de 0,3 à 2,5 en 6 mois. Et le temps d'onboarding d'un nouveau dev baisse de 35% en moyenne.",{"type":30,"tag":55,"props":212,"children":213},{},[],{"type":30,"tag":59,"props":215,"children":217},{"id":216},"raison-2-pas-de-frontières-métier-et-la-pratique-bounded-contexts",[218],{"type":39,"value":219},"Raison #2 : pas de frontières métier (et la pratique Bounded Contexts)",{"type":30,"tag":31,"props":221,"children":222},{},[223,227],{"type":30,"tag":35,"props":224,"children":225},{},[226],{"type":39,"value":156},{"type":39,"value":228}," : modifier 1 module touche 3 autres. Le module \"facturation\" appelle directement le module \"stock\" qui touche au module \"auth\". Tout dépend de tout. Aucun refacto local n'est possible. Chaque feature devient une chirurgie sur l'ensemble du corps.",{"type":30,"tag":31,"props":230,"children":231},{},[232,236],{"type":30,"tag":35,"props":233,"children":234},{},[235],{"type":39,"value":173},{"type":39,"value":237}," : les premières features sont écrites vite, dans le même répertoire, avec des appels directs entre modules. Au bout de 6 mois, la matrice de dépendances ressemble à un plat de spaghettis. Au bout de 12 mois, l'équipe n'ose plus toucher au module central par peur de casser ce qu'elle ne voit pas.",{"type":30,"tag":31,"props":239,"children":240},{},[241,246,248,254],{"type":30,"tag":35,"props":242,"children":243},{},[244],{"type":39,"value":245},"Pratique craft : Bounded Contexts",{"type":39,"value":247}," issus du ",{"type":30,"tag":88,"props":249,"children":251},{"href":250},"/fr/architecture-craft/decouvrir-domain-driven-design-ddd-avantages-exemples-java",[252],{"type":39,"value":253},"Domain-Driven Design d'Eric Evans",{"type":39,"value":255}," (2003). Chaque module a un sens métier précis et délimité. Les communications entre modules passent par des contrats explicites (events, APIs, requêtes), jamais par des appels internes croisés. C'est l'application directe de ce que le DDD décrit comme la condition de scalabilité humaine d'une codebase.",{"type":30,"tag":31,"props":257,"children":258},{},[259,261,268,270,276,277,283,284,290,291,297,298,304,305,311,312,318,320,325,327,332],{"type":39,"value":260},"Sur le crmcoaching, j'ai défini 8 bounded contexts dès le démarrage : ",{"type":30,"tag":262,"props":263,"children":265},"code",{"className":264},[],[266],{"type":39,"value":267},"booking",{"type":39,"value":269},", ",{"type":30,"tag":262,"props":271,"children":273},{"className":272},[],[274],{"type":39,"value":275},"lead",{"type":39,"value":269},{"type":30,"tag":262,"props":278,"children":280},{"className":279},[],[281],{"type":39,"value":282},"calendar",{"type":39,"value":269},{"type":30,"tag":262,"props":285,"children":287},{"className":286},[],[288],{"type":39,"value":289},"payment",{"type":39,"value":269},{"type":30,"tag":262,"props":292,"children":294},{"className":293},[],[295],{"type":39,"value":296},"notification",{"type":39,"value":269},{"type":30,"tag":262,"props":299,"children":301},{"className":300},[],[302],{"type":39,"value":303},"audit",{"type":39,"value":269},{"type":30,"tag":262,"props":306,"children":308},{"className":307},[],[309],{"type":39,"value":310},"auth",{"type":39,"value":269},{"type":30,"tag":262,"props":313,"children":315},{"className":314},[],[316],{"type":39,"value":317},"tenant",{"type":39,"value":319},". Chacun a sa frontière, son langage ubiquitaire, son équipe de fait (même si je suis seul à coder, je ne mélange jamais les responsabilités). Quand je modifie ",{"type":30,"tag":262,"props":321,"children":323},{"className":322},[],[324],{"type":39,"value":267},{"type":39,"value":326},", je sais que ",{"type":30,"tag":262,"props":328,"children":330},{"className":329},[],[331],{"type":39,"value":289},{"type":39,"value":333}," ne sera pas affecté tant que je ne change pas le contrat d'événement entre les deux. La même logique structure l'architecture hexagonale appliquée en Java.",{"type":30,"tag":31,"props":335,"children":336},{},[337],{"type":39,"value":338},"Cette discipline porte ses fruits à partir du 6ème mois. Avant, elle ressemble à de la sur-organisation. Après, elle ressemble à un investissement qui paie. Sur les missions où j'introduis les bounded contexts en refacto progressif, je vois le temps de modification des features baisser de 40% en moyenne sur 9 mois.",{"type":30,"tag":55,"props":340,"children":341},{},[],{"type":30,"tag":59,"props":343,"children":345},{"id":344},"raison-3-tests-qui-testent-des-mocks-et-la-pratique-ac-level-coverage",[346],{"type":39,"value":347},"Raison #3 : tests qui testent des mocks (et la pratique AC-level coverage)",{"type":30,"tag":31,"props":349,"children":350},{},[351,355],{"type":30,"tag":35,"props":352,"children":353},{},[354],{"type":39,"value":156},{"type":39,"value":356}," : 87% de couverture technique affichée par le rapport SonarQube. Et pourtant, des bugs en prod toutes les semaines. Le filet de tests est dense mais inutile, parce qu'il teste des mocks plutôt que des comportements observables.",{"type":30,"tag":31,"props":358,"children":359},{},[360,364],{"type":30,"tag":35,"props":361,"children":362},{},[363],{"type":39,"value":173},{"type":39,"value":365}," : Claude (et avant lui les juniors) génère des tests qui vérifient que la fonction A appelle la fonction B. Si vous changez l'implémentation pour appeler la fonction C avec le même résultat métier, le test casse, sans qu'aucun bug n'ait été introduit. C'est le pire des deux mondes : couplage fort à l'implémentation, zéro garantie de comportement, faux sentiment de sécurité.",{"type":30,"tag":31,"props":367,"children":368},{},[369,374,376,382],{"type":30,"tag":35,"props":370,"children":371},{},[372],{"type":39,"value":373},"Pratique craft : Acceptance Criteria + couverture AC-level.",{"type":39,"value":375}," Dan North a posé les bases dans ses articles BDD fondateurs de 2006. Format Given/When/Then. Chaque comportement métier exprimé en langage naturel, puis instrumenté en test. L'implémentation peut changer 5 fois, le test reste valable tant que le comportement est respecté. C'est exactement la philosophie défendue dans ",{"type":30,"tag":88,"props":377,"children":379},{"href":378},"/fr/pratiques-agiles/adopter-behaviour-driven-development-bdd-guide-agile",[380],{"type":39,"value":381},"l'adoption du Behaviour-Driven Development",{"type":39,"value":205},{"type":30,"tag":31,"props":384,"children":385},{},[386],{"type":39,"value":387},"Sur le crmcoaching, j'ai 47 acceptance criteria explicites, chacun couvert par un test behavior-level. Mon ratio \"tests utiles / tests totaux\" est à 78%. La couverture brute est plus basse que sur un repo IA-heavy non audité (62% vs 87%), mais la couverture utile triple. Sur les missions où j'instaure cette transition, le change failure rate baisse de 50% en 4 mois. La Definition of Done bien établie est l'autre pilier de cette discipline, et elle se complète bien avec les pièges classiques des tests d'intégration sur du legacy.",{"type":30,"tag":55,"props":389,"children":390},{},[],{"type":30,"tag":392,"props":393,"children":398},"cta",{"cta":394,"href":395,"title":396,"type":397},"Coder comme un senior →","https://app.kamanga.fr/forms/mentoring","Vous voulez prendre les réflexes craft qui font tenir une codebase 10 ans ?","call",[399],{"type":30,"tag":31,"props":400,"children":401},{},[402],{"type":39,"value":403},"Tracer un ADR, nommer une frontière métier, écrire un test qui survit au refacto : ça ne se lit pas, ça se travaille au contact d'un cas réel. En mentoring 1:1, je relis votre code avec vous et on installe ces réflexes sur vos propres modules, pas sur des exemples génériques. Vous repartez en sachant reconnaître les 5 mécanismes de pourrissement avant qu'ils s'installent, et en ayant les gestes pour les couper.",{"type":30,"tag":55,"props":405,"children":406},{},[],{"type":30,"tag":59,"props":408,"children":410},{"id":409},"raison-4-pas-de-discipline-de-refacto-et-la-pratique-strangler-fig",[411],{"type":39,"value":412},"Raison #4 : pas de discipline de refacto (et la pratique Strangler Fig)",{"type":30,"tag":31,"props":414,"children":415},{},[416,420],{"type":30,"tag":35,"props":417,"children":418},{},[419],{"type":39,"value":156},{"type":39,"value":421}," : la dette technique grossit en silence. \"Plus tard\" devient \"jamais\". Au bout de 18 mois, le module legacy fait peur à toute l'équipe. Personne ne veut le toucher. Le coût composé de la dette atteint 1,5x par an (chiffre que je vois revenir sur la majorité de mes audits).",{"type":30,"tag":31,"props":423,"children":424},{},[425,429],{"type":30,"tag":35,"props":426,"children":427},{},[428],{"type":39,"value":173},{"type":39,"value":430}," : sans discipline explicite de refacto, le code se dégrade par accumulation de petits compromis. Chaque feature pressée ajoute son raccourci. Chaque deadline impose son TODO non traité. À 18 mois, la dette accumulée demanderait 3 mois de stop production pour être remboursée, ce qui est inacceptable, donc on continue, et elle continue de grossir.",{"type":30,"tag":31,"props":432,"children":433},{},[434,439],{"type":30,"tag":35,"props":435,"children":436},{},[437],{"type":39,"value":438},"Pratique craft : Strangler Fig Application (Martin Fowler, 2004).",{"type":39,"value":440}," Au lieu de réécrire d'un coup, on encapsule le legacy derrière une interface, et on remplace progressivement module par module. Chaque refacto est documenté en ADR (raison #1 + raison #4 se renforcent), chaque module remplacé libère un peu d'air à l'équipe.",{"type":30,"tag":31,"props":442,"children":443},{},[444,446,452],{"type":39,"value":445},"Sur les missions où j'installe cette discipline, je couple le Strangler Fig avec ",{"type":30,"tag":88,"props":447,"children":449},{"href":448},"/fr/dette-technique/programme-refactoring-approuve-business",[450],{"type":39,"value":451},"un programme de refacto approuvé business",{"type":39,"value":453},". 20% du temps équipe sur 6 mois consacré au remplacement progressif. Pas plus. Pas de \"big bang refacto\". Le résultat : à 12 mois, 40% du legacy est neutralisé, sans avoir mis en pause la livraison de features. C'est aussi ce que défend la Boy Scout Rule appliquée au quotidien : on laisse le code un peu plus propre que comment on l'a trouvé, à chaque PR. Ce travail s'appuie sur l'évaluation préalable du risque legacy pour prioriser correctement.",{"type":30,"tag":55,"props":455,"children":456},{},[],{"type":30,"tag":59,"props":458,"children":460},{"id":459},"raison-5-tout-est-dans-une-seule-tête-et-la-pratique-docs-as-code",[461],{"type":39,"value":462},"Raison #5 : tout est dans une seule tête (et la pratique Docs as code)",{"type":30,"tag":31,"props":464,"children":465},{},[466,470],{"type":30,"tag":35,"props":467,"children":468},{},[469],{"type":39,"value":156},{"type":39,"value":471}," : un développeur part, 30% du savoir métier part avec lui. Trois mois plus tard, l'équipe redécouvre des décisions qu'elle pensait actées. Six mois plus tard, des bugs réapparaissent parce que personne ne se souvient des contraintes initiales.",{"type":30,"tag":31,"props":473,"children":474},{},[475,479],{"type":30,"tag":35,"props":476,"children":477},{},[478],{"type":39,"value":173},{"type":39,"value":480}," : pendant les 12 premiers mois, l'équipe est stable. Les développeurs portent le contexte dans leur tête. Personne ne sent le besoin de tracer. À 12-18 mois, le premier départ révèle le trou. À 24 mois, les rotations cumulées ont fait disparaître la moitié du savoir non écrit.",{"type":30,"tag":31,"props":482,"children":483},{},[484,489],{"type":30,"tag":35,"props":485,"children":486},{},[487],{"type":39,"value":488},"Pratique craft : Docs as code, artifacts vivants versionnés.",{"type":39,"value":490}," Pas une documentation Confluence séparée du repo (qui pourrit en 6 mois). Une documentation dans le repo, à côté du code, mise à jour dans les mêmes PR que le code. ADRs (raison #1), README de module (raison #2), Acceptance Criteria (raison #3), playbooks d'incident, journal de décisions, etc.",{"type":30,"tag":31,"props":492,"children":493},{},[494],{"type":39,"value":495},"Sur le crmcoaching, j'ai 280 fichiers de documentation versionnés dans le repo. Pas des pages mortes, des artifacts vivants : 52 ADRs, 47 ACs, 22 playbooks d'incident, 8 README de bounded context, 18 schemas d'architecture, etc. Le ratio docs / code est à 18% en LOC. C'est ce qui permet à un nouveau dev d'être productif en 3 semaines au lieu de 7, et c'est ce qui fait survivre le contexte aux personnes.",{"type":30,"tag":31,"props":497,"children":498},{},[499,501,507],{"type":39,"value":500},"Cette discipline est aussi ce qui permet à une équipe de tenir l'usage massif de l'IA : Claude lit les ADRs et les contrats de bounded context comme contexte, et propose des solutions cohérentes avec l'architecture, au lieu d'inventer des patterns inadaptés. C'est le sujet de fond traité dans ",{"type":30,"tag":88,"props":502,"children":504},{"href":503},"/fr/intelligence-artificielle/ia-documentation-technique-cas-usage",[505],{"type":39,"value":506},"l'usage de l'IA pour la documentation technique",{"type":39,"value":508},", où l'IA devient un amplificateur d'écriture craft plutôt qu'un raccourci.",{"type":30,"tag":55,"props":510,"children":511},{},[],{"type":30,"tag":59,"props":513,"children":515},{"id":514},"synthèse-le-code-qui-tient-à-10-ans",[516],{"type":39,"value":517},"Synthèse : le code qui tient à 10 ans",{"type":30,"tag":31,"props":519,"children":520},{},[521],{"type":39,"value":522},"Voici la phrase signature que j'utilise en mission, en conférence, en stand-up :",{"type":30,"tag":31,"props":524,"children":525},{},[526],{"type":30,"tag":42,"props":527,"children":528},{},[529],{"type":39,"value":530},"\"Le code qui tient à 10 ans n'est pas le code qui marche aujourd'hui. C'est le code dont les décisions sont tracées, les frontières sont nommées, les comportements sont testés, la dette est remboursée et le savoir est partagé.\"",{"type":30,"tag":31,"props":532,"children":533},{},[534],{"type":39,"value":535},"Ces 5 conditions ne sont pas optionnelles. Ce sont les 5 piliers du craft durable. Une codebase peut survivre à l'absence d'un pilier pendant 6 à 12 mois. Au-delà, elle entre en pourrissement accéléré. Avec les 5 piliers en place, elle peut tenir 10 à 15 ans, traverser 3 ou 4 rotations d'équipe, et accueillir de nouvelles features sans réécriture majeure.",{"type":30,"tag":537,"props":538,"children":539},"table",{},[540,559],{"type":30,"tag":541,"props":542,"children":543},"thead",{},[544],{"type":30,"tag":545,"props":546,"children":547},"tr",{},[548,554],{"type":30,"tag":549,"props":550,"children":551},"th",{},[552],{"type":39,"value":553},"Raison de la mort à 18 mois",{"type":30,"tag":549,"props":555,"children":556},{},[557],{"type":39,"value":558},"Pratique craft de survie 10 ans",{"type":30,"tag":560,"props":561,"children":562},"tbody",{},[563,577,590,603,616],{"type":30,"tag":545,"props":564,"children":565},{},[566,572],{"type":30,"tag":567,"props":568,"children":569},"td",{},[570],{"type":39,"value":571},"#1 Aucun POURQUOI tracé",{"type":30,"tag":567,"props":573,"children":574},{},[575],{"type":39,"value":576},"ADRs versionnées dans le repo",{"type":30,"tag":545,"props":578,"children":579},{},[580,585],{"type":30,"tag":567,"props":581,"children":582},{},[583],{"type":39,"value":584},"#2 Pas de frontières métier",{"type":30,"tag":567,"props":586,"children":587},{},[588],{"type":39,"value":589},"Bounded Contexts (DDD)",{"type":30,"tag":545,"props":591,"children":592},{},[593,598],{"type":30,"tag":567,"props":594,"children":595},{},[596],{"type":39,"value":597},"#3 Tests qui testent des mocks",{"type":30,"tag":567,"props":599,"children":600},{},[601],{"type":39,"value":602},"Acceptance Criteria + tests behavior-level",{"type":30,"tag":545,"props":604,"children":605},{},[606,611],{"type":30,"tag":567,"props":607,"children":608},{},[609],{"type":39,"value":610},"#4 Pas de discipline de refacto",{"type":30,"tag":567,"props":612,"children":613},{},[614],{"type":39,"value":615},"Strangler Fig + 20% temps équipe",{"type":30,"tag":545,"props":617,"children":618},{},[619,624],{"type":30,"tag":567,"props":620,"children":621},{},[622],{"type":39,"value":623},"#5 Tout est dans une tête",{"type":30,"tag":567,"props":625,"children":626},{},[627],{"type":39,"value":628},"Docs as code, artifacts vivants versionnés",{"type":30,"tag":31,"props":630,"children":631},{},[632],{"type":39,"value":633},"Cette grille tient sur un poster A4. Je la donne à chaque équipe en fin de mission. Elle se lit en 30 secondes. Elle structure 10 ans de discipline, et elle prolonge naturellement les pratiques décrites dans comment écrire du code évolutif en développement logiciel.",{"type":30,"tag":55,"props":635,"children":636},{},[],{"type":30,"tag":59,"props":638,"children":640},{"id":639},"ce-que-ça-change-concrètement",[641],{"type":39,"value":642},"Ce que ça change concrètement",{"type":30,"tag":31,"props":644,"children":645},{},[646],{"type":39,"value":647},"Sur les 4 dernières missions où j'ai installé les 5 piliers (audit + plan en 90 jours + accompagnement 6 mois), voici les chiffres avant/après.",{"type":30,"tag":537,"props":649,"children":650},{},[651,672],{"type":30,"tag":541,"props":652,"children":653},{},[654],{"type":30,"tag":545,"props":655,"children":656},{},[657,662,667],{"type":30,"tag":549,"props":658,"children":659},{},[660],{"type":39,"value":661},"Métrique",{"type":30,"tag":549,"props":663,"children":664},{},[665],{"type":39,"value":666},"Avant audit",{"type":30,"tag":549,"props":668,"children":669},{},[670],{"type":39,"value":671},"Après 12 mois",{"type":30,"tag":560,"props":673,"children":674},{},[675,693,711,729,747,765],{"type":30,"tag":545,"props":676,"children":677},{},[678,683,688],{"type":30,"tag":567,"props":679,"children":680},{},[681],{"type":39,"value":682},"Coût moyen d'une feature simple",{"type":30,"tag":567,"props":684,"children":685},{},[686],{"type":39,"value":687},"4,2 jours",{"type":30,"tag":567,"props":689,"children":690},{},[691],{"type":39,"value":692},"1,6 jour",{"type":30,"tag":545,"props":694,"children":695},{},[696,701,706],{"type":30,"tag":567,"props":697,"children":698},{},[699],{"type":39,"value":700},"Onboarding nouveau dev (1ère PR mergée)",{"type":30,"tag":567,"props":702,"children":703},{},[704],{"type":39,"value":705},"7 semaines",{"type":30,"tag":567,"props":707,"children":708},{},[709],{"type":39,"value":710},"3,5 semaines",{"type":30,"tag":545,"props":712,"children":713},{},[714,719,724],{"type":30,"tag":567,"props":715,"children":716},{},[717],{"type":39,"value":718},"Bugs régression par release",{"type":30,"tag":567,"props":720,"children":721},{},[722],{"type":39,"value":723},"5-7",{"type":30,"tag":567,"props":725,"children":726},{},[727],{"type":39,"value":728},"0-1",{"type":30,"tag":545,"props":730,"children":731},{},[732,737,742],{"type":30,"tag":567,"props":733,"children":734},{},[735],{"type":39,"value":736},"Discussions \"et si on réécrivait tout ?\"",{"type":30,"tag":567,"props":738,"children":739},{},[740],{"type":39,"value":741},"1 par trimestre",{"type":30,"tag":567,"props":743,"children":744},{},[745],{"type":39,"value":746},"0",{"type":30,"tag":545,"props":748,"children":749},{},[750,755,760],{"type":30,"tag":567,"props":751,"children":752},{},[753],{"type":39,"value":754},"Ratio docs / code",{"type":30,"tag":567,"props":756,"children":757},{},[758],{"type":39,"value":759},"4%",{"type":30,"tag":567,"props":761,"children":762},{},[763],{"type":39,"value":764},"16%",{"type":30,"tag":545,"props":766,"children":767},{},[768,773,778],{"type":30,"tag":567,"props":769,"children":770},{},[771],{"type":39,"value":772},"ADRs créées dans l'année",{"type":30,"tag":567,"props":774,"children":775},{},[776],{"type":39,"value":777},"3",{"type":30,"tag":567,"props":779,"children":780},{},[781],{"type":39,"value":782},"47",{"type":30,"tag":31,"props":784,"children":785},{},[786,788,794],{"type":39,"value":787},"Le gain économique est mesurable. Une équipe de 5 développeurs qui passe de 4,2 à 1,6 jours par feature livre 2,6 fois plus de valeur pour le même coût salarial. C'est aussi le sujet que je détaille dans ",{"type":30,"tag":88,"props":789,"children":791},{"href":790},"/fr/dette-technique/ingenierie-logicielle-avantage-concurrentiel",[792],{"type":39,"value":793},"l'ingénierie logicielle comme avantage concurrentiel",{"type":39,"value":795},". Le craft n'est pas une dépense engineering, c'est un levier business avec ROI mesurable.",{"type":30,"tag":55,"props":797,"children":798},{},[],{"type":30,"tag":59,"props":800,"children":802},{"id":801},"conclusion",[803],{"type":39,"value":804},"Conclusion",{"type":30,"tag":31,"props":806,"children":807},{},[808],{"type":39,"value":809},"Ce que je veux que vous reteniez de cet article, c'est que la mort d'une application à 18 mois n'est jamais accidentelle. C'est le résultat prévisible de 5 absences de discipline que j'ai vues se rejouer 7 fois en 25 ans. Et symétriquement, la durabilité d'une application à 10 ans n'est jamais miraculeuse. C'est le résultat prévisible de 5 disciplines installées dès les 3 premiers mois.",{"type":30,"tag":31,"props":811,"children":812},{},[813],{"type":39,"value":814},"Le bon moment pour installer ces 5 disciplines, c'était au démarrage. Le deuxième meilleur moment, c'est maintenant. Chaque mois où vous tardez, vous payez en intérêts composés. Chaque ADR que vous écrivez aujourd'hui économise 5 heures de fouille archéologique dans 18 mois. Chaque bounded context que vous définissez aujourd'hui économise 3 jours de coordination dans 12 mois. Chaque test behavior-level aujourd'hui économise un incident en prod dans 6 mois.",{"type":30,"tag":31,"props":816,"children":817},{},[818],{"type":39,"value":819},"Si en lisant ces lignes vous reconnaissez votre situation, vous avez deux choix. Vous pouvez continuer à laisser les 5 raisons s'installer un peu plus chaque sprint. Ou vous pouvez commencer lundi matin, par 1 ADR sur la décision la plus structurante des 3 derniers mois, et bâtir la suite. La discipline craft ne vient pas d'un coup. Elle vient pratique par pratique, ADR par ADR, test par test. Et au bout de 12 mois, vous regardez en arrière et vous ne reconnaissez plus votre codebase, dans le bon sens.",{"type":30,"tag":31,"props":821,"children":822},{},[823,825,830],{"type":39,"value":824},"Pour la suite des patterns de durabilité que je documente chaque semaine en mission, retrouvez-moi sur ",{"type":30,"tag":88,"props":826,"children":828},{"href":125,"rel":827},[127],[829],{"type":39,"value":130},{"type":39,"value":205},{"type":30,"tag":392,"props":832,"children":837},{"cta":833,"href":834,"title":835,"type":836},"Les 100 pratiques que l'IA n'enseigne pas →","https://kamanga.fr/referentiel-craft","Ces 5 piliers craft font partie d'un référentiel de 100 pratiques","product",[838],{"type":30,"tag":31,"props":839,"children":840},{},[841],{"type":39,"value":842},"Les 5 disciplines décrites ici (ADR, bounded contexts, tests behavior-level, Strangler Fig, docs as code) ne sont qu'une partie de ce que j'applique pour qu'une codebase tienne 10 ans. Le Craft Bundle réunit les 100 pratiques craft que j'utilise au quotidien pour coder propre et durable. Celles que l'IA ne vous apprendra jamais, parce qu'elle ne les a jamais vues survivre à 3 rotations d'équipe en prod.",{"type":30,"tag":55,"props":844,"children":845},{},[],{"type":30,"tag":59,"props":847,"children":849},{"id":848},"faq-sur-le-code-durable-et-les-5-piliers-craft",[850],{"type":39,"value":851},"FAQ sur le code durable et les 5 piliers craft",{"type":30,"tag":853,"props":854,"children":855},"details",{},[856,862],{"type":30,"tag":857,"props":858,"children":859},"summary",{},[860],{"type":39,"value":861},"1. Faut-il installer les 5 piliers en même temps ou séquentiellement ?",{"type":30,"tag":31,"props":863,"children":864},{},[865],{"type":39,"value":866},"Séquentiellement, et dans un ordre précis. Mon plan en 90 jours commence par les ADRs (raison #1), parce que c'est la pratique qui se met en place en 1 semaine et qui débloque les 4 autres (la décision d'installer les autres piliers devient elle-même un ADR). Puis viennent les tests behavior-level (raison #3), parce qu'ils protègent les refactos à venir. Puis les Bounded Contexts (raison #2). Puis le Strangler Fig (raison #4). Puis la docs as code globale (raison #5). En 90 jours, les fondations sont là.",{"type":30,"tag":853,"props":868,"children":869},{},[870,875],{"type":30,"tag":857,"props":871,"children":872},{},[873],{"type":39,"value":874},"2. Combien coûte cette discipline en charge supplémentaire pour l'équipe ?",{"type":30,"tag":31,"props":876,"children":877},{},[878],{"type":39,"value":879},"Pendant les 3 premiers mois : 15 à 20% du temps équipe. Pendant les 3 mois suivants : 10 à 12%. Au-delà de 6 mois : 5 à 8%, intégré au flux normal de développement. Et à partir du 12ème mois, c'est un gain net : le temps économisé sur les modifications et l'onboarding dépasse le temps investi dans la discipline. Le ROI s'observe entre M6 et M9.",{"type":30,"tag":853,"props":881,"children":882},{},[883,888],{"type":30,"tag":857,"props":884,"children":885},{},[886],{"type":39,"value":887},"3. Le DDD n'est-il pas trop lourd pour une équipe de 3-5 personnes ?",{"type":30,"tag":31,"props":889,"children":890},{},[891],{"type":39,"value":892},"Le DDD complet, avec ses tactical patterns (aggregates, value objects, repositories, etc.), peut être surdimensionné pour une petite équipe. Mais les Bounded Contexts au sens stratégique sont applicables à n'importe quelle taille d'équipe. Sur le crmcoaching, je suis seul à coder et j'ai 8 bounded contexts. Ça prend 1 heure à définir au démarrage et ça change la maintenabilité sur 10 ans. La règle : commencez petit (3-4 bounded contexts), laissez-les évoluer avec votre compréhension du métier.",{"type":30,"tag":853,"props":894,"children":895},{},[896,901],{"type":30,"tag":857,"props":897,"children":898},{},[899],{"type":39,"value":900},"4. Comment vendre cette discipline à un COMEX qui veut \"livrer plus vite\" ?",{"type":30,"tag":31,"props":902,"children":903},{},[904],{"type":39,"value":905},"Avec le tableau avant/après et le ROI calculé. 2,6 fois plus de features livrées à coût équivalent, c'est l'argument qui passe. Le COMEX n'achète pas du craft, il achète de la productivité durable. Quand vous présentez les 5 piliers comme un programme de productivité long terme (et non comme une exigence morale du dev), l'adoption est radicalement plus facile.",{"type":30,"tag":853,"props":907,"children":908},{},[909,914],{"type":30,"tag":857,"props":910,"children":911},{},[912],{"type":39,"value":913},"5. Les 5 piliers fonctionnent-ils avec du code IA-généré massivement ?",{"type":30,"tag":31,"props":915,"children":916},{},[917,919,925],{"type":39,"value":918},"Encore mieux. Une codebase IA-heavy non disciplinée meurt à 12-15 mois au lieu de 18 (la production de code accélère, la dette s'accumule plus vite). Une codebase IA-heavy avec les 5 piliers tient plus longtemps que les codebases purement humaines des années 2010, parce que Claude lit les ADRs comme contexte et produit du code aligné avec l'architecture en place. Le couplage discipline craft + IA est la combinaison gagnante de 2026, et c'est exactement ce que documente la série sur les ",{"type":30,"tag":88,"props":920,"children":922},{"href":921},"/fr/intelligence-artificielle/recap-5-pieges-claude-semaine-1",[923],{"type":39,"value":924},"pièges Claude et leurs contre-patterns craft",{"type":39,"value":205},{"type":30,"tag":853,"props":927,"children":928},{},[929,934],{"type":30,"tag":857,"props":930,"children":931},{},[932],{"type":39,"value":933},"6. Que faire si mon équipe résiste à installer les ADR (raison #1) ?",{"type":30,"tag":31,"props":935,"children":936},{},[937],{"type":39,"value":938},"Commencez seul. Écrivez 5 ADRs sur les 5 décisions les plus importantes des 3 derniers mois. Mettez-les dans le repo. Référencez-les dans vos prochaines PR. À 2 mois, un autre dev de l'équipe écrira son premier ADR sans qu'on lui demande. À 4 mois, c'est dans la culture. La résistance n'est jamais idéologique, elle est inertielle. Le bon levier, c'est l'exemplarité, pas la prescription. C'est exactement la mécanique qui transforme la qualité de revue de code en réflexe partagé.",{"type":30,"tag":55,"props":940,"children":941},{},[],{"type":30,"tag":392,"props":943,"children":948},{"cta":944,"href":945,"title":946,"type":947},"Évaluer la maturité de mon équipe →","/mes-ressources","Ressource gratuite : Engineering Maturity Assessment","resource",[949],{"type":30,"tag":31,"props":950,"children":951},{},[952],{"type":39,"value":953},"L'EMA est l'outil que je propose au début de chaque mission. Il mesure la maturité de votre équipe sur les 5 piliers du craft durable (et 3 autres axes engineering : observabilité, sécurité, delivery). Quelques minutes pour identifier laquelle des 5 raisons accélère le plus la mort de votre application, et où concentrer vos efforts en priorité dans les 90 prochains jours.",{"title":8,"searchDepth":955,"depth":955,"links":956},2,[957,958,959,960,961,962,963,964,965,966],{"id":61,"depth":955,"text":64},{"id":145,"depth":955,"text":148},{"id":216,"depth":955,"text":219},{"id":344,"depth":955,"text":347},{"id":409,"depth":955,"text":412},{"id":459,"depth":955,"text":462},{"id":514,"depth":955,"text":517},{"id":639,"depth":955,"text":642},{"id":801,"depth":955,"text":804},{"id":848,"depth":955,"text":851},"markdown","content:fr:dette-technique:5-raisons-app-meurt-18-mois.md","content","fr/dette-technique/5-raisons-app-meurt-18-mois.md","fr/dette-technique/5-raisons-app-meurt-18-mois","md",{"_path":921,"_dir":974,"_draft":7,"_partial":7,"_locale":8,"title":975,"description":976,"id":977,"date":978,"listed":13,"nocomments":7,"hidden":13,"categories":979,"tags":980,"cover":985,"readingTime":986,"body":991,"_type":967,"_id":1753,"_source":969,"_file":1754,"_stem":1755,"_extension":972},"intelligence-artificielle","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",[974],[981,982,16,983,984],"claude-code","recap","ia","best-practices","covers/articles/recap-5-pieges-claude-semaine-1.jpg",{"text":987,"minutes":988,"time":989,"words":990},"13 min read",12.755,765300,2551,{"type":27,"children":992,"toc":1740},[993,1001,1006,1009,1015,1020,1032,1045,1070,1073,1079,1092,1105,1108,1114,1127,1140,1143,1149,1154,1175,1178,1187,1190,1196,1201,1214,1217,1223,1228,1249,1252,1258,1268,1288,1291,1297,1302,1322,1327,1330,1336,1341,1565,1570,1573,1577,1582,1587,1592,1604,1613,1616,1622,1643,1656,1669,1682,1695,1729,1732],{"type":30,"tag":31,"props":994,"children":995},{},[996],{"type":30,"tag":35,"props":997,"children":998},{},[999],{"type":39,"value":1000},"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":30,"tag":31,"props":1002,"children":1003},{},[1004],{"type":39,"value":1005},"À 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":30,"tag":55,"props":1007,"children":1008},{},[],{"type":30,"tag":59,"props":1010,"children":1012},{"id":1011},"pourquoi-cette-série",[1013],{"type":39,"value":1014},"Pourquoi cette série",{"type":30,"tag":31,"props":1016,"children":1017},{},[1018],{"type":39,"value":1019},"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":30,"tag":31,"props":1021,"children":1022},{},[1023,1025,1031],{"type":39,"value":1024},"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":30,"tag":88,"props":1026,"children":1028},{"href":1027},"/fr/intelligence-artificielle/ia-code-review-retour-experience",[1029],{"type":39,"value":1030},"retour d'expérience sur la code review IA",{"type":39,"value":205},{"type":30,"tag":97,"props":1033,"children":1034},{},[1035],{"type":30,"tag":31,"props":1036,"children":1037},{},[1038,1043],{"type":30,"tag":35,"props":1039,"children":1040},{},[1041],{"type":39,"value":1042},"Ce que j'ai voulu transmettre",{"type":39,"value":1044}," : 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":30,"tag":31,"props":1046,"children":1047},{},[1048,1050,1055,1057,1062,1064,1068],{"type":39,"value":1049},"Robert C. Martin a écrit dans ",{"type":30,"tag":42,"props":1051,"children":1052},{},[1053],{"type":39,"value":1054},"Clean Code",{"type":39,"value":1056}," (2008) que ",{"type":30,"tag":42,"props":1058,"children":1059},{},[1060],{"type":39,"value":1061},"\"the only valid measurement of code quality is WTFs per minute.\"",{"type":39,"value":1063}," 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":30,"tag":88,"props":1065,"children":1066},{"href":112},[1067],{"type":39,"value":115},{"type":39,"value":1069},". Cette série visait à diminuer les WTF par minute dans les revues de PR Claude. Voici la synthèse, jour par jour.",{"type":30,"tag":55,"props":1071,"children":1072},{},[],{"type":30,"tag":59,"props":1074,"children":1076},{"id":1075},"lundi-le-bug-invisible",[1077],{"type":39,"value":1078},"Lundi - le bug invisible",{"type":30,"tag":31,"props":1080,"children":1081},{},[1082,1084,1090],{"type":39,"value":1083},"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":30,"tag":88,"props":1085,"children":1087},{"href":1086},"/fr/intelligence-artificielle/bug-claude-vendredi-dernier",[1088],{"type":39,"value":1089},"le bug que Claude vous a fait coder vendredi dernier",{"type":39,"value":1091},", 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":30,"tag":31,"props":1093,"children":1094},{},[1095,1097,1103],{"type":39,"value":1096},"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":30,"tag":88,"props":1098,"children":1100},{"href":1099},"/fr/dette-technique/revue-de-code-java-guide-exemples",[1101],{"type":39,"value":1102},"revue de code structurée",{"type":39,"value":1104}," 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":30,"tag":55,"props":1106,"children":1107},{},[],{"type":30,"tag":59,"props":1109,"children":1111},{"id":1110},"mardi-les-5-anti-patterns-silencieux",[1112],{"type":39,"value":1113},"Mardi - les 5 anti-patterns silencieux",{"type":30,"tag":31,"props":1115,"children":1116},{},[1117,1119,1125],{"type":39,"value":1118},"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":30,"tag":262,"props":1120,"children":1122},{"className":1121},[],[1123],{"type":39,"value":1124},"expect(...).toHaveBeenCalled()",{"type":39,"value":1126}," 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":30,"tag":31,"props":1128,"children":1129},{},[1130,1132,1138],{"type":39,"value":1131},"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":30,"tag":88,"props":1133,"children":1135},{"href":1134},"/fr/intelligence-artificielle/5-patterns-dangereux-claude",[1136],{"type":39,"value":1137},"5 anti-patterns que Claude reproduit en silence",{"type":39,"value":1139},". 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":30,"tag":55,"props":1141,"children":1142},{},[],{"type":30,"tag":59,"props":1144,"children":1146},{"id":1145},"mercredi-tests-verts-prod-rouge",[1147],{"type":39,"value":1148},"Mercredi - tests verts, prod rouge",{"type":30,"tag":31,"props":1150,"children":1151},{},[1152],{"type":39,"value":1153},"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":30,"tag":31,"props":1155,"children":1156},{},[1157,1159,1165,1167,1173],{"type":39,"value":1158},"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":30,"tag":88,"props":1160,"children":1162},{"href":1161},"/fr/intelligence-artificielle/code-claude-tests-passent-plante-prod",[1163],{"type":39,"value":1164},"le code Claude dont les tests passent mais qui plante en prod",{"type":39,"value":1166},". Cette discipline s'inscrit dans une Definition of Done qui pose les bons critères de qualité, et complète la ",{"type":30,"tag":88,"props":1168,"children":1170},{"href":1169},"/fr/intelligence-artificielle/tester-code-genere-ia-checklist",[1171],{"type":39,"value":1172},"checklist pour tester du code généré par IA",{"type":39,"value":1174}," que j'avais publiée en 2025.",{"type":30,"tag":55,"props":1176,"children":1177},{},[],{"type":30,"tag":392,"props":1179,"children":1181},{"cta":394,"href":395,"title":1180,"type":397},"Vous voulez acquérir le réflexe qui repère ces pièges Claude avant le merge ?",[1182],{"type":30,"tag":31,"props":1183,"children":1184},{},[1185],{"type":39,"value":1186},"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":30,"tag":55,"props":1188,"children":1189},{},[],{"type":30,"tag":59,"props":1191,"children":1193},{"id":1192},"jeudi-le-faux-ami",[1194],{"type":39,"value":1195},"Jeudi - le faux ami",{"type":30,"tag":31,"props":1197,"children":1198},{},[1199],{"type":39,"value":1200},"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":30,"tag":31,"props":1202,"children":1203},{},[1204,1206,1212],{"type":39,"value":1205},"Le contre-pattern, c'est la règle YAGNI étendue à l'ère IA, déclinée en 4 points dans l'article sur ",{"type":30,"tag":88,"props":1207,"children":1209},{"href":1208},"/fr/intelligence-artificielle/faux-ami-code-claude-coute-cher",[1210],{"type":39,"value":1211},"le code Claude qui marche mais qui coûte cher",{"type":39,"value":1213},". 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":30,"tag":55,"props":1215,"children":1216},{},[],{"type":30,"tag":59,"props":1218,"children":1220},{"id":1219},"vendredi-lillusion-de-productivité",[1221],{"type":39,"value":1222},"Vendredi - l'illusion de productivité",{"type":30,"tag":31,"props":1224,"children":1225},{},[1226],{"type":39,"value":1227},"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":30,"tag":31,"props":1229,"children":1230},{},[1231,1233,1239,1241,1247],{"type":39,"value":1232},"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":30,"tag":88,"props":1234,"children":1236},{"href":1235},"/fr/intelligence-artificielle/illusion-productivite-10x-pr",[1237],{"type":39,"value":1238},"l'illusion des 10x plus de PR",{"type":39,"value":1240},", avec le tableau comparatif \"sans Claude / avec Claude non piloté / avec Claude piloté\". Cette grille à 5 indicateurs est aussi le socle d'une ",{"type":30,"tag":88,"props":1242,"children":1244},{"href":1243},"/fr/management/metriques-management-developpeurs-motivation",[1245],{"type":39,"value":1246},"bonne pratique des métriques de management des développeurs",{"type":39,"value":1248},", 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":30,"tag":55,"props":1250,"children":1251},{},[],{"type":30,"tag":59,"props":1253,"children":1255},{"id":1254},"samedi-la-question-éthique-de-fond",[1256],{"type":39,"value":1257},"Samedi - la question éthique de fond",{"type":30,"tag":31,"props":1259,"children":1260},{},[1261,1263],{"type":39,"value":1262},"Au-delà des 5 pièges techniques, la semaine a posé une question qu'on évite trop souvent en stand-up : ",{"type":30,"tag":42,"props":1264,"children":1265},{},[1266],{"type":39,"value":1267},"à qui appartient le bug en prod, vous ou Claude ?",{"type":30,"tag":31,"props":1269,"children":1270},{},[1271,1273,1278,1280,1286],{"type":39,"value":1272},"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":30,"tag":88,"props":1274,"children":1275},{"href":200},[1276],{"type":39,"value":1277},"ADR de gouvernance IA",{"type":39,"value":1279}," dans l'article sur ",{"type":30,"tag":88,"props":1281,"children":1283},{"href":1282},"/fr/intelligence-artificielle/a-qui-appartient-le-bug-ia",[1284],{"type":39,"value":1285},"à qui appartient le bug en prod",{"type":39,"value":1287},". 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":30,"tag":55,"props":1289,"children":1290},{},[],{"type":30,"tag":59,"props":1292,"children":1294},{"id":1293},"ce-quon-regarde-la-semaine-suivante-la-dette-ia-induite",[1295],{"type":39,"value":1296},"Ce qu'on regarde la semaine suivante : la dette IA-induite",{"type":30,"tag":31,"props":1298,"children":1299},{},[1300],{"type":39,"value":1301},"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":30,"tag":31,"props":1303,"children":1304},{},[1305,1307,1313,1315,1320],{"type":39,"value":1306},"Deux articles supplémentaires complètent la boucle. Le premier, sur ",{"type":30,"tag":88,"props":1308,"children":1310},{"href":1309},"/fr/dette-technique/dependabot-craft-gestion-dependances",[1311],{"type":39,"value":1312},"Dependabot comme coéquipier silencieux contre la dette de dépendances",{"type":39,"value":1314},", 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":30,"tag":88,"props":1316,"children":1317},{"href":5},[1318],{"type":39,"value":1319},"les 5 raisons pour lesquelles votre app meurt à 18 mois",{"type":39,"value":1321},", é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":30,"tag":31,"props":1323,"children":1324},{},[1325],{"type":39,"value":1326},"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":30,"tag":55,"props":1328,"children":1329},{},[],{"type":30,"tag":59,"props":1331,"children":1333},{"id":1332},"la-grille-consolidée-à-imprimer",[1334],{"type":39,"value":1335},"La grille consolidée à imprimer",{"type":30,"tag":31,"props":1337,"children":1338},{},[1339],{"type":39,"value":1340},"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":30,"tag":537,"props":1342,"children":1343},{},[1344,1365],{"type":30,"tag":541,"props":1345,"children":1346},{},[1347],{"type":30,"tag":545,"props":1348,"children":1349},{},[1350,1355,1360],{"type":30,"tag":549,"props":1351,"children":1352},{},[1353],{"type":39,"value":1354},"Piège",{"type":30,"tag":549,"props":1356,"children":1357},{},[1358],{"type":39,"value":1359},"Signal d'alerte",{"type":30,"tag":549,"props":1361,"children":1362},{},[1363],{"type":39,"value":1364},"Contre-pattern craft",{"type":30,"tag":560,"props":1366,"children":1367},{},[1368,1386,1404,1428,1451,1475,1493,1511,1529,1547],{"type":30,"tag":545,"props":1369,"children":1370},{},[1371,1376,1381],{"type":30,"tag":567,"props":1372,"children":1373},{},[1374],{"type":39,"value":1375},"Race condition",{"type":30,"tag":567,"props":1377,"children":1378},{},[1379],{"type":39,"value":1380},"Lecture + écriture sur état partagé sans transaction",{"type":30,"tag":567,"props":1382,"children":1383},{},[1384],{"type":39,"value":1385},"Transaction atomique + test de concurrence",{"type":30,"tag":545,"props":1387,"children":1388},{},[1389,1394,1399],{"type":30,"tag":567,"props":1390,"children":1391},{},[1392],{"type":39,"value":1393},"God Function",{"type":30,"tag":567,"props":1395,"children":1396},{},[1397],{"type":39,"value":1398},"Fonction de plus de 40 lignes",{"type":30,"tag":567,"props":1400,"children":1401},{},[1402],{"type":39,"value":1403},"Découpe SRP en sous-fonctions nommées",{"type":30,"tag":545,"props":1405,"children":1406},{},[1407,1412,1423],{"type":30,"tag":567,"props":1408,"children":1409},{},[1410],{"type":39,"value":1411},"Couplage ORM",{"type":30,"tag":567,"props":1413,"children":1414},{},[1415,1417],{"type":39,"value":1416},"Import Prisma ou TypeORM dans le dossier ",{"type":30,"tag":262,"props":1418,"children":1420},{"className":1419},[],[1421],{"type":39,"value":1422},"domain/",{"type":30,"tag":567,"props":1424,"children":1425},{},[1426],{"type":39,"value":1427},"Repository interface + adapter",{"type":30,"tag":545,"props":1429,"children":1430},{},[1431,1436,1446],{"type":30,"tag":567,"props":1432,"children":1433},{},[1434],{"type":39,"value":1435},"Tests vides",{"type":30,"tag":567,"props":1437,"children":1438},{},[1439,1444],{"type":30,"tag":262,"props":1440,"children":1442},{"className":1441},[],[1443],{"type":39,"value":1124},{"type":39,"value":1445}," sans assertion métier",{"type":30,"tag":567,"props":1447,"children":1448},{},[1449],{"type":39,"value":1450},"Given/When/Then sur comportement observable",{"type":30,"tag":545,"props":1452,"children":1453},{},[1454,1459,1470],{"type":30,"tag":567,"props":1455,"children":1456},{},[1457],{"type":39,"value":1458},"Catch-all silencieux",{"type":30,"tag":567,"props":1460,"children":1461},{},[1462,1468],{"type":30,"tag":262,"props":1463,"children":1465},{"className":1464},[],[1466],{"type":39,"value":1467},"catch (err) { console.error(err) }",{"type":39,"value":1469}," sans politique",{"type":30,"tag":567,"props":1471,"children":1472},{},[1473],{"type":39,"value":1474},"Re-throw, ou métrique d'observabilité",{"type":30,"tag":545,"props":1476,"children":1477},{},[1478,1483,1488],{"type":30,"tag":567,"props":1479,"children":1480},{},[1481],{"type":39,"value":1482},"Copier-coller",{"type":30,"tag":567,"props":1484,"children":1485},{},[1486],{"type":39,"value":1487},"Fonction sémantiquement proche d'une existante",{"type":30,"tag":567,"props":1489,"children":1490},{},[1491],{"type":39,"value":1492},"Prompter Claude pour mutualiser",{"type":30,"tag":545,"props":1494,"children":1495},{},[1496,1501,1506],{"type":30,"tag":567,"props":1497,"children":1498},{},[1499],{"type":39,"value":1500},"Abstraction accidentelle",{"type":30,"tag":567,"props":1502,"children":1503},{},[1504],{"type":39,"value":1505},"Interface devant une seule implémentation",{"type":30,"tag":567,"props":1507,"children":1508},{},[1509],{"type":39,"value":1510},"Règle des 3 cas réels (Fowler)",{"type":30,"tag":545,"props":1512,"children":1513},{},[1514,1519,1524],{"type":30,"tag":567,"props":1515,"children":1516},{},[1517],{"type":39,"value":1518},"Tests modes d'échec",{"type":30,"tag":567,"props":1520,"children":1521},{},[1522],{"type":39,"value":1523},"Pas de test 429, timeout ou concurrence",{"type":30,"tag":567,"props":1525,"children":1526},{},[1527],{"type":39,"value":1528},"4 tests anti-fragiles obligatoires",{"type":30,"tag":545,"props":1530,"children":1531},{},[1532,1537,1542],{"type":30,"tag":567,"props":1533,"children":1534},{},[1535],{"type":39,"value":1536},"Métriques d'activité",{"type":30,"tag":567,"props":1538,"children":1539},{},[1540],{"type":39,"value":1541},"LOC, PR mergées, story points seuls",{"type":30,"tag":567,"props":1543,"children":1544},{},[1545],{"type":39,"value":1546},"DORA + ratio ADR pour 100 commits",{"type":30,"tag":545,"props":1548,"children":1549},{},[1550,1555,1560],{"type":30,"tag":567,"props":1551,"children":1552},{},[1553],{"type":39,"value":1554},"Responsabilité diluée",{"type":30,"tag":567,"props":1556,"children":1557},{},[1558],{"type":39,"value":1559},"\"C'est Claude qui l'a écrit\" en post-mortem",{"type":30,"tag":567,"props":1561,"children":1562},{},[1563],{"type":39,"value":1564},"ADR de gouvernance IA + 4 engagements",{"type":30,"tag":31,"props":1566,"children":1567},{},[1568],{"type":39,"value":1569},"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":30,"tag":55,"props":1571,"children":1572},{},[],{"type":30,"tag":59,"props":1574,"children":1575},{"id":801},[1576],{"type":39,"value":804},{"type":30,"tag":31,"props":1578,"children":1579},{},[1580],{"type":39,"value":1581},"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":30,"tag":31,"props":1583,"children":1584},{},[1585],{"type":39,"value":1586},"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":30,"tag":31,"props":1588,"children":1589},{},[1590],{"type":39,"value":1591},"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":30,"tag":31,"props":1593,"children":1594},{},[1595,1597,1602],{"type":39,"value":1596},"Pour la suite des contenus craft + IA en format court, vous pouvez me retrouver sur ",{"type":30,"tag":88,"props":1598,"children":1600},{"href":125,"rel":1599},[127],[1601],{"type":39,"value":130},{"type":39,"value":1603},", où je publie chaque semaine les patterns que je vois revenir en mission et les contre-patterns que j'applique.",{"type":30,"tag":392,"props":1605,"children":1607},{"cta":833,"href":834,"title":1606,"type":836},"Cette grille à 10 lignes n'est qu'un extrait : il existe 100 pratiques craft",[1608],{"type":30,"tag":31,"props":1609,"children":1610},{},[1611],{"type":39,"value":1612},"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":30,"tag":55,"props":1614,"children":1615},{},[],{"type":30,"tag":59,"props":1617,"children":1619},{"id":1618},"faq-sur-la-série-craft-et-ia",[1620],{"type":39,"value":1621},"FAQ sur la série craft et IA",{"type":30,"tag":853,"props":1623,"children":1624},{},[1625,1630],{"type":30,"tag":857,"props":1626,"children":1627},{},[1628],{"type":39,"value":1629},"1. La série fonctionne-t-elle pour des stacks autres que TypeScript ou Node ?",{"type":30,"tag":31,"props":1631,"children":1632},{},[1633,1635,1641],{"type":39,"value":1634},"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":30,"tag":262,"props":1636,"children":1638},{"className":1637},[],[1639],{"type":39,"value":1640},"p-retry",{"type":39,"value":1642}," 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":30,"tag":853,"props":1644,"children":1645},{},[1646,1651],{"type":30,"tag":857,"props":1647,"children":1648},{},[1649],{"type":39,"value":1650},"2. Combien de temps pour installer cette discipline dans une équipe de 10 développeurs ?",{"type":30,"tag":31,"props":1652,"children":1653},{},[1654],{"type":39,"value":1655},"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":30,"tag":853,"props":1657,"children":1658},{},[1659,1664],{"type":30,"tag":857,"props":1660,"children":1661},{},[1662],{"type":39,"value":1663},"3. Faut-il refuser Claude tant que la grille n'est pas en place ?",{"type":30,"tag":31,"props":1665,"children":1666},{},[1667],{"type":39,"value":1668},"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":30,"tag":853,"props":1670,"children":1671},{},[1672,1677],{"type":30,"tag":857,"props":1673,"children":1674},{},[1675],{"type":39,"value":1676},"4. Comment partager cette série avec mon équipe sans paraître donneur de leçons ?",{"type":30,"tag":31,"props":1678,"children":1679},{},[1680],{"type":39,"value":1681},"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":30,"tag":853,"props":1683,"children":1684},{},[1685,1690],{"type":30,"tag":857,"props":1686,"children":1687},{},[1688],{"type":39,"value":1689},"5. Les pièges vont-ils évoluer avec les prochaines versions de Claude ?",{"type":30,"tag":31,"props":1691,"children":1692},{},[1693],{"type":39,"value":1694},"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":30,"tag":853,"props":1696,"children":1697},{},[1698,1703],{"type":30,"tag":857,"props":1699,"children":1700},{},[1701],{"type":39,"value":1702},"6. Où trouver des ressources complémentaires pour aller plus loin ?",{"type":30,"tag":31,"props":1704,"children":1705},{},[1706,1708,1712,1714,1719,1721,1727],{"type":39,"value":1707},"Trois sources que je recommande systématiquement en mission : ",{"type":30,"tag":42,"props":1709,"children":1710},{},[1711],{"type":39,"value":1054},{"type":39,"value":1713}," de Robert C. Martin (les fondamentaux du craft), ",{"type":30,"tag":42,"props":1715,"children":1716},{},[1717],{"type":39,"value":1718},"Release It!",{"type":39,"value":1720}," 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":30,"tag":88,"props":1722,"children":1724},{"href":125,"rel":1723},[127],[1725],{"type":39,"value":1726},"Instagram @kamangacode",{"type":39,"value":1728}," avec un pattern craft par semaine.",{"type":30,"tag":55,"props":1730,"children":1731},{},[],{"type":30,"tag":392,"props":1733,"children":1734},{"cta":944,"href":945,"title":946,"type":947},[1735],{"type":30,"tag":31,"props":1736,"children":1737},{},[1738],{"type":39,"value":1739},"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":955,"depth":955,"links":1741},[1742,1743,1744,1745,1746,1747,1748,1749,1750,1751,1752],{"id":1011,"depth":955,"text":1014},{"id":1075,"depth":955,"text":1078},{"id":1110,"depth":955,"text":1113},{"id":1145,"depth":955,"text":1148},{"id":1192,"depth":955,"text":1195},{"id":1219,"depth":955,"text":1222},{"id":1254,"depth":955,"text":1257},{"id":1293,"depth":955,"text":1296},{"id":1332,"depth":955,"text":1335},{"id":801,"depth":955,"text":804},{"id":1618,"depth":955,"text":1621},"content:fr:intelligence-artificielle:recap-5-pieges-claude-semaine-1.md","fr/intelligence-artificielle/recap-5-pieges-claude-semaine-1.md","fr/intelligence-artificielle/recap-5-pieges-claude-semaine-1",{"_path":1134,"_dir":974,"_draft":7,"_partial":7,"_locale":8,"title":1757,"description":1758,"id":1759,"date":1760,"listed":13,"nocomments":7,"hidden":13,"categories":1761,"tags":1762,"cover":1765,"readingTime":1766,"body":1770,"_type":967,"_id":7706,"_source":969,"_file":7707,"_stem":7708,"_extension":972},"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",[974],[981,1763,16,1764,983],"anti-patterns","code-review","covers/articles/5-patterns-dangereux-claude.jpg",{"text":22,"minutes":1767,"time":1768,"words":1769},14.52,871200,2904,{"type":27,"children":1771,"toc":7694},[1772,1780,1785,1788,1794,1808,1813,1826,1851,1854,1860,1865,1870,3960,4008,4020,4023,4029,4042,4055,4593,4645,5144,5149,5152,5158,5179,5654,5659,5671,6270,6281,6286,6289,6295,6300,6586,6599,6620,7056,7075,7078,7084,7121,7133,7153,7166,7169,7175,7180,7340,7345,7348,7357,7360,7364,7369,7485,7495,7498,7502,7507,7512,7517,7528,7531,7540,7543,7549,7562,7582,7625,7638,7664,7677,7680,7688],{"type":30,"tag":31,"props":1773,"children":1774},{},[1775],{"type":30,"tag":35,"props":1776,"children":1777},{},[1778],{"type":39,"value":1779},"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":30,"tag":31,"props":1781,"children":1782},{},[1783],{"type":39,"value":1784},"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":30,"tag":55,"props":1786,"children":1787},{},[],{"type":30,"tag":59,"props":1789,"children":1791},{"id":1790},"pourquoi-claude-reproduit-certains-patterns-en-silence",[1792],{"type":39,"value":1793},"Pourquoi Claude reproduit certains patterns en silence",{"type":30,"tag":31,"props":1795,"children":1796},{},[1797,1799,1806],{"type":39,"value":1798},"Le constat de base est documenté. Le ",{"type":30,"tag":88,"props":1800,"children":1803},{"href":1801,"rel":1802},"https://www.gitclear.com/ai_assistant_code_quality_2024_research",[127],[1804],{"type":39,"value":1805},"GitClear AI Copilot Code Quality Report 2024",{"type":39,"value":1807}," 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":30,"tag":31,"props":1809,"children":1810},{},[1811],{"type":39,"value":1812},"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":30,"tag":97,"props":1814,"children":1815},{},[1816],{"type":30,"tag":31,"props":1817,"children":1818},{},[1819,1824],{"type":30,"tag":35,"props":1820,"children":1821},{},[1822],{"type":39,"value":1823},"Ce que j'ai observé sur crmcoaching",{"type":39,"value":1825}," : 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":30,"tag":31,"props":1827,"children":1828},{},[1829,1831,1835,1837,1842,1844,1849],{"type":39,"value":1830},"Robert C. Martin l'avait écrit dans ",{"type":30,"tag":42,"props":1832,"children":1833},{},[1834],{"type":39,"value":1054},{"type":39,"value":1836}," en 2008 : ",{"type":30,"tag":42,"props":1838,"children":1839},{},[1840],{"type":39,"value":1841},"\"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":39,"value":1843}," Cette règle, exposée en français dans ",{"type":30,"tag":88,"props":1845,"children":1846},{"href":112},[1847],{"type":39,"value":1848},"les principes Clean Code et software craftsmanship",{"type":39,"value":1850},", Claude ne l'applique pas par défaut. C'est à vous de la lui imposer par le prompt et la review.",{"type":30,"tag":55,"props":1852,"children":1853},{},[],{"type":30,"tag":59,"props":1855,"children":1857},{"id":1856},"pattern-1-la-god-function",[1858],{"type":39,"value":1859},"Pattern #1 : la God Function",{"type":30,"tag":31,"props":1861,"children":1862},{},[1863],{"type":39,"value":1864},"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":30,"tag":31,"props":1866,"children":1867},{},[1868],{"type":39,"value":1869},"Voici un exemple réel que j'ai vu apparaître dans crmcoaching sur la conversion d'un lead en client :",{"type":30,"tag":1871,"props":1872,"children":1876},"pre",{"className":1873,"code":1874,"language":1875,"meta":8,"style":8},"language-typescript shiki shiki-themes catppuccin-frappe github-dark","// 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","typescript",[1877],{"type":30,"tag":262,"props":1878,"children":1879},{"__ignoreMap":8},[1880,1892,1900,1909,1931,1958,1972,2008,2038,2068,2098,2112,2120,2206,2215,2275,2388,2458,2520,2586,2646,2699,2716,2758,2767,2775,2784,2842,2859,2888,2918,2948,2978,2991,3013,3034,3056,3065,3081,3127,3159,3245,3261,3269,3278,3316,3436,3459,3526,3542,3601,3609,3618,3656,3678,3700,3730,3751,3785,3801,3809,3818,3903,3910,3942,3951],{"type":30,"tag":1881,"props":1882,"children":1885},"span",{"class":1883,"line":1884},"line",1,[1886],{"type":30,"tag":1881,"props":1887,"children":1889},{"style":1888},"--shiki-default:#737994;--shiki-default-font-style:italic;--shiki-dark:#6A737D;--shiki-dark-font-style:inherit",[1890],{"type":39,"value":1891},"// apps/api/src/application/use-cases/convert-lead-to-client.use-case.ts\n",{"type":30,"tag":1881,"props":1893,"children":1894},{"class":1883,"line":955},[1895],{"type":30,"tag":1881,"props":1896,"children":1897},{"style":1888},[1898],{"type":39,"value":1899},"// Généré par Claude sans prompt de découpe (tel quel)\n",{"type":30,"tag":1881,"props":1901,"children":1903},{"class":1883,"line":1902},3,[1904],{"type":30,"tag":1881,"props":1905,"children":1906},{"emptyLinePlaceholder":13},[1907],{"type":39,"value":1908},"\n",{"type":30,"tag":1881,"props":1910,"children":1912},{"class":1883,"line":1911},4,[1913,1919,1925],{"type":30,"tag":1881,"props":1914,"children":1916},{"style":1915},"--shiki-default:#8CAAEE;--shiki-default-font-style:italic;--shiki-dark:#E1E4E8;--shiki-dark-font-style:inherit",[1917],{"type":39,"value":1918},"@",{"type":30,"tag":1881,"props":1920,"children":1922},{"style":1921},"--shiki-default:#8CAAEE;--shiki-default-font-style:italic;--shiki-dark:#B392F0;--shiki-dark-font-style:inherit",[1923],{"type":39,"value":1924},"Injectable",{"type":30,"tag":1881,"props":1926,"children":1928},{"style":1927},"--shiki-default:#EF9F76;--shiki-dark:#E1E4E8",[1929],{"type":39,"value":1930},"()\n",{"type":30,"tag":1881,"props":1932,"children":1934},{"class":1883,"line":1933},5,[1935,1941,1946,1952],{"type":30,"tag":1881,"props":1936,"children":1938},{"style":1937},"--shiki-default:#CA9EE6;--shiki-dark:#F97583",[1939],{"type":39,"value":1940},"export",{"type":30,"tag":1881,"props":1942,"children":1943},{"style":1937},[1944],{"type":39,"value":1945}," class",{"type":30,"tag":1881,"props":1947,"children":1949},{"style":1948},"--shiki-default:#E5C890;--shiki-default-font-style:italic;--shiki-dark:#B392F0;--shiki-dark-font-style:inherit",[1950],{"type":39,"value":1951}," ConvertLeadToClientUseCase",{"type":30,"tag":1881,"props":1953,"children":1955},{"style":1954},"--shiki-default:#949CBB;--shiki-dark:#E1E4E8",[1956],{"type":39,"value":1957}," {\n",{"type":30,"tag":1881,"props":1959,"children":1961},{"class":1883,"line":1960},6,[1962,1967],{"type":30,"tag":1881,"props":1963,"children":1964},{"style":1937},[1965],{"type":39,"value":1966},"  constructor",{"type":30,"tag":1881,"props":1968,"children":1969},{"style":1954},[1970],{"type":39,"value":1971},"(\n",{"type":30,"tag":1881,"props":1973,"children":1975},{"class":1883,"line":1974},7,[1976,1981,1986,1992,1998,2003],{"type":30,"tag":1881,"props":1977,"children":1978},{"style":1937},[1979],{"type":39,"value":1980},"    private",{"type":30,"tag":1881,"props":1982,"children":1983},{"style":1937},[1984],{"type":39,"value":1985}," readonly",{"type":30,"tag":1881,"props":1987,"children":1989},{"style":1988},"--shiki-default:#EA999C;--shiki-default-font-style:italic;--shiki-dark:#FFAB70;--shiki-dark-font-style:inherit",[1990],{"type":39,"value":1991}," prisma",{"type":30,"tag":1881,"props":1993,"children":1995},{"style":1994},"--shiki-default:#81C8BE;--shiki-dark:#F97583",[1996],{"type":39,"value":1997},":",{"type":30,"tag":1881,"props":1999,"children":2000},{"style":1948},[2001],{"type":39,"value":2002}," PrismaClient",{"type":30,"tag":1881,"props":2004,"children":2005},{"style":1954},[2006],{"type":39,"value":2007},",\n",{"type":30,"tag":1881,"props":2009,"children":2011},{"class":1883,"line":2010},8,[2012,2016,2020,2025,2029,2034],{"type":30,"tag":1881,"props":2013,"children":2014},{"style":1937},[2015],{"type":39,"value":1980},{"type":30,"tag":1881,"props":2017,"children":2018},{"style":1937},[2019],{"type":39,"value":1985},{"type":30,"tag":1881,"props":2021,"children":2022},{"style":1988},[2023],{"type":39,"value":2024}," brevoService",{"type":30,"tag":1881,"props":2026,"children":2027},{"style":1994},[2028],{"type":39,"value":1997},{"type":30,"tag":1881,"props":2030,"children":2031},{"style":1948},[2032],{"type":39,"value":2033}," BrevoService",{"type":30,"tag":1881,"props":2035,"children":2036},{"style":1954},[2037],{"type":39,"value":2007},{"type":30,"tag":1881,"props":2039,"children":2041},{"class":1883,"line":2040},9,[2042,2046,2050,2055,2059,2064],{"type":30,"tag":1881,"props":2043,"children":2044},{"style":1937},[2045],{"type":39,"value":1980},{"type":30,"tag":1881,"props":2047,"children":2048},{"style":1937},[2049],{"type":39,"value":1985},{"type":30,"tag":1881,"props":2051,"children":2052},{"style":1988},[2053],{"type":39,"value":2054}," auditService",{"type":30,"tag":1881,"props":2056,"children":2057},{"style":1994},[2058],{"type":39,"value":1997},{"type":30,"tag":1881,"props":2060,"children":2061},{"style":1948},[2062],{"type":39,"value":2063}," AuditService",{"type":30,"tag":1881,"props":2065,"children":2066},{"style":1954},[2067],{"type":39,"value":2007},{"type":30,"tag":1881,"props":2069,"children":2071},{"class":1883,"line":2070},10,[2072,2076,2080,2085,2089,2094],{"type":30,"tag":1881,"props":2073,"children":2074},{"style":1937},[2075],{"type":39,"value":1980},{"type":30,"tag":1881,"props":2077,"children":2078},{"style":1937},[2079],{"type":39,"value":1985},{"type":30,"tag":1881,"props":2081,"children":2082},{"style":1988},[2083],{"type":39,"value":2084}," eventEmitter",{"type":30,"tag":1881,"props":2086,"children":2087},{"style":1994},[2088],{"type":39,"value":1997},{"type":30,"tag":1881,"props":2090,"children":2091},{"style":1948},[2092],{"type":39,"value":2093}," EventEmitter2",{"type":30,"tag":1881,"props":2095,"children":2096},{"style":1954},[2097],{"type":39,"value":2007},{"type":30,"tag":1881,"props":2099,"children":2101},{"class":1883,"line":2100},11,[2102,2107],{"type":30,"tag":1881,"props":2103,"children":2104},{"style":1954},[2105],{"type":39,"value":2106},"  )",{"type":30,"tag":1881,"props":2108,"children":2109},{"style":1954},[2110],{"type":39,"value":2111}," {}\n",{"type":30,"tag":1881,"props":2113,"children":2115},{"class":1883,"line":2114},12,[2116],{"type":30,"tag":1881,"props":2117,"children":2118},{"emptyLinePlaceholder":13},[2119],{"type":39,"value":1908},{"type":30,"tag":1881,"props":2121,"children":2123},{"class":1883,"line":2122},13,[2124,2129,2134,2139,2144,2148,2154,2159,2164,2168,2172,2177,2181,2186,2192,2197,2202],{"type":30,"tag":1881,"props":2125,"children":2126},{"style":1937},[2127],{"type":39,"value":2128},"  async",{"type":30,"tag":1881,"props":2130,"children":2131},{"style":1921},[2132],{"type":39,"value":2133}," execute",{"type":30,"tag":1881,"props":2135,"children":2136},{"style":1954},[2137],{"type":39,"value":2138},"(",{"type":30,"tag":1881,"props":2140,"children":2141},{"style":1988},[2142],{"type":39,"value":2143},"leadId",{"type":30,"tag":1881,"props":2145,"children":2146},{"style":1994},[2147],{"type":39,"value":1997},{"type":30,"tag":1881,"props":2149,"children":2151},{"style":2150},"--shiki-default:#CA9EE6;--shiki-dark:#79B8FF",[2152],{"type":39,"value":2153}," string",{"type":30,"tag":1881,"props":2155,"children":2156},{"style":1954},[2157],{"type":39,"value":2158},",",{"type":30,"tag":1881,"props":2160,"children":2161},{"style":1988},[2162],{"type":39,"value":2163}," coachId",{"type":30,"tag":1881,"props":2165,"children":2166},{"style":1994},[2167],{"type":39,"value":1997},{"type":30,"tag":1881,"props":2169,"children":2170},{"style":2150},[2171],{"type":39,"value":2153},{"type":30,"tag":1881,"props":2173,"children":2174},{"style":1954},[2175],{"type":39,"value":2176},")",{"type":30,"tag":1881,"props":2178,"children":2179},{"style":1994},[2180],{"type":39,"value":1997},{"type":30,"tag":1881,"props":2182,"children":2183},{"style":1948},[2184],{"type":39,"value":2185}," Promise",{"type":30,"tag":1881,"props":2187,"children":2189},{"style":2188},"--shiki-default:#99D1DB;--shiki-dark:#E1E4E8",[2190],{"type":39,"value":2191},"\u003C",{"type":30,"tag":1881,"props":2193,"children":2194},{"style":1948},[2195],{"type":39,"value":2196},"ClientDto",{"type":30,"tag":1881,"props":2198,"children":2199},{"style":2188},[2200],{"type":39,"value":2201},">",{"type":30,"tag":1881,"props":2203,"children":2204},{"style":1954},[2205],{"type":39,"value":1957},{"type":30,"tag":1881,"props":2207,"children":2209},{"class":1883,"line":2208},14,[2210],{"type":30,"tag":1881,"props":2211,"children":2212},{"style":1888},[2213],{"type":39,"value":2214},"    // 1. Validation (15 lignes)\n",{"type":30,"tag":1881,"props":2216,"children":2218},{"class":1883,"line":2217},15,[2219,2224,2230,2235,2240,2245,2251,2256,2260,2266,2270],{"type":30,"tag":1881,"props":2220,"children":2221},{"style":1937},[2222],{"type":39,"value":2223},"    if",{"type":30,"tag":1881,"props":2225,"children":2227},{"style":2226},"--shiki-default:#C6D0F5;--shiki-dark:#E1E4E8",[2228],{"type":39,"value":2229}," (",{"type":30,"tag":1881,"props":2231,"children":2232},{"style":1994},[2233],{"type":39,"value":2234},"!",{"type":30,"tag":1881,"props":2236,"children":2237},{"style":2226},[2238],{"type":39,"value":2239},"leadId) ",{"type":30,"tag":1881,"props":2241,"children":2242},{"style":1937},[2243],{"type":39,"value":2244},"throw",{"type":30,"tag":1881,"props":2246,"children":2248},{"style":2247},"--shiki-default:#CA9EE6;--shiki-default-font-weight:bold;--shiki-dark:#F97583;--shiki-dark-font-weight:inherit",[2249],{"type":39,"value":2250}," new",{"type":30,"tag":1881,"props":2252,"children":2253},{"style":1921},[2254],{"type":39,"value":2255}," BadRequestException",{"type":30,"tag":1881,"props":2257,"children":2258},{"style":2226},[2259],{"type":39,"value":2138},{"type":30,"tag":1881,"props":2261,"children":2263},{"style":2262},"--shiki-default:#A6D189;--shiki-dark:#9ECBFF",[2264],{"type":39,"value":2265},"'leadId requis'",{"type":30,"tag":1881,"props":2267,"children":2268},{"style":2226},[2269],{"type":39,"value":2176},{"type":30,"tag":1881,"props":2271,"children":2272},{"style":1954},[2273],{"type":39,"value":2274},";\n",{"type":30,"tag":1881,"props":2276,"children":2278},{"class":1883,"line":2277},16,[2279,2284,2290,2295,2300,2306,2311,2316,2320,2324,2328,2333,2337,2342,2347,2351,2356,2361,2365,2370,2375,2380,2384],{"type":30,"tag":1881,"props":2280,"children":2281},{"style":1937},[2282],{"type":39,"value":2283},"    const",{"type":30,"tag":1881,"props":2285,"children":2287},{"style":2286},"--shiki-default:#C6D0F5;--shiki-dark:#79B8FF",[2288],{"type":39,"value":2289}," lead",{"type":30,"tag":1881,"props":2291,"children":2292},{"style":1994},[2293],{"type":39,"value":2294}," =",{"type":30,"tag":1881,"props":2296,"children":2297},{"style":1937},[2298],{"type":39,"value":2299}," await",{"type":30,"tag":1881,"props":2301,"children":2303},{"style":2302},"--shiki-default:#E78284;--shiki-dark:#79B8FF",[2304],{"type":39,"value":2305}," this",{"type":30,"tag":1881,"props":2307,"children":2309},{"style":2308},"--shiki-default:#81C8BE;--shiki-dark:#E1E4E8",[2310],{"type":39,"value":205},{"type":30,"tag":1881,"props":2312,"children":2313},{"style":2226},[2314],{"type":39,"value":2315},"prisma",{"type":30,"tag":1881,"props":2317,"children":2318},{"style":2308},[2319],{"type":39,"value":205},{"type":30,"tag":1881,"props":2321,"children":2322},{"style":2226},[2323],{"type":39,"value":275},{"type":30,"tag":1881,"props":2325,"children":2326},{"style":2308},[2327],{"type":39,"value":205},{"type":30,"tag":1881,"props":2329,"children":2330},{"style":1921},[2331],{"type":39,"value":2332},"findUnique",{"type":30,"tag":1881,"props":2334,"children":2335},{"style":2226},[2336],{"type":39,"value":2138},{"type":30,"tag":1881,"props":2338,"children":2339},{"style":1954},[2340],{"type":39,"value":2341},"{",{"type":30,"tag":1881,"props":2343,"children":2344},{"style":2226},[2345],{"type":39,"value":2346}," where",{"type":30,"tag":1881,"props":2348,"children":2349},{"style":2308},[2350],{"type":39,"value":1997},{"type":30,"tag":1881,"props":2352,"children":2353},{"style":1954},[2354],{"type":39,"value":2355}," {",{"type":30,"tag":1881,"props":2357,"children":2358},{"style":2226},[2359],{"type":39,"value":2360}," id",{"type":30,"tag":1881,"props":2362,"children":2363},{"style":2308},[2364],{"type":39,"value":1997},{"type":30,"tag":1881,"props":2366,"children":2367},{"style":2226},[2368],{"type":39,"value":2369}," leadId ",{"type":30,"tag":1881,"props":2371,"children":2372},{"style":1954},[2373],{"type":39,"value":2374},"}",{"type":30,"tag":1881,"props":2376,"children":2377},{"style":1954},[2378],{"type":39,"value":2379}," }",{"type":30,"tag":1881,"props":2381,"children":2382},{"style":2226},[2383],{"type":39,"value":2176},{"type":30,"tag":1881,"props":2385,"children":2386},{"style":1954},[2387],{"type":39,"value":2274},{"type":30,"tag":1881,"props":2389,"children":2391},{"class":1883,"line":2390},17,[2392,2396,2400,2404,2409,2413,2417,2422,2426,2431,2437,2441,2445,2450,2454],{"type":30,"tag":1881,"props":2393,"children":2394},{"style":1937},[2395],{"type":39,"value":2223},{"type":30,"tag":1881,"props":2397,"children":2398},{"style":2226},[2399],{"type":39,"value":2229},{"type":30,"tag":1881,"props":2401,"children":2402},{"style":1994},[2403],{"type":39,"value":2234},{"type":30,"tag":1881,"props":2405,"children":2406},{"style":2226},[2407],{"type":39,"value":2408},"lead) ",{"type":30,"tag":1881,"props":2410,"children":2411},{"style":1937},[2412],{"type":39,"value":2244},{"type":30,"tag":1881,"props":2414,"children":2415},{"style":2247},[2416],{"type":39,"value":2250},{"type":30,"tag":1881,"props":2418,"children":2419},{"style":1921},[2420],{"type":39,"value":2421}," NotFoundException",{"type":30,"tag":1881,"props":2423,"children":2424},{"style":2226},[2425],{"type":39,"value":2138},{"type":30,"tag":1881,"props":2427,"children":2428},{"style":2262},[2429],{"type":39,"value":2430},"`Lead ",{"type":30,"tag":1881,"props":2432,"children":2434},{"style":2433},"--shiki-default:#949CBB;--shiki-dark:#9ECBFF",[2435],{"type":39,"value":2436},"${",{"type":30,"tag":1881,"props":2438,"children":2439},{"style":2226},[2440],{"type":39,"value":2143},{"type":30,"tag":1881,"props":2442,"children":2443},{"style":2433},[2444],{"type":39,"value":2374},{"type":30,"tag":1881,"props":2446,"children":2447},{"style":2262},[2448],{"type":39,"value":2449}," introuvable`",{"type":30,"tag":1881,"props":2451,"children":2452},{"style":2226},[2453],{"type":39,"value":2176},{"type":30,"tag":1881,"props":2455,"children":2456},{"style":1954},[2457],{"type":39,"value":2274},{"type":30,"tag":1881,"props":2459,"children":2461},{"class":1883,"line":2460},18,[2462,2466,2471,2475,2480,2485,2490,2494,2498,2503,2507,2512,2516],{"type":30,"tag":1881,"props":2463,"children":2464},{"style":1937},[2465],{"type":39,"value":2223},{"type":30,"tag":1881,"props":2467,"children":2468},{"style":2226},[2469],{"type":39,"value":2470}," (lead",{"type":30,"tag":1881,"props":2472,"children":2473},{"style":2308},[2474],{"type":39,"value":205},{"type":30,"tag":1881,"props":2476,"children":2477},{"style":2226},[2478],{"type":39,"value":2479},"coachId ",{"type":30,"tag":1881,"props":2481,"children":2482},{"style":1994},[2483],{"type":39,"value":2484},"!==",{"type":30,"tag":1881,"props":2486,"children":2487},{"style":2226},[2488],{"type":39,"value":2489}," coachId) ",{"type":30,"tag":1881,"props":2491,"children":2492},{"style":1937},[2493],{"type":39,"value":2244},{"type":30,"tag":1881,"props":2495,"children":2496},{"style":2247},[2497],{"type":39,"value":2250},{"type":30,"tag":1881,"props":2499,"children":2500},{"style":1921},[2501],{"type":39,"value":2502}," ForbiddenException",{"type":30,"tag":1881,"props":2504,"children":2505},{"style":2226},[2506],{"type":39,"value":2138},{"type":30,"tag":1881,"props":2508,"children":2509},{"style":2262},[2510],{"type":39,"value":2511},"'Lead hors scope'",{"type":30,"tag":1881,"props":2513,"children":2514},{"style":2226},[2515],{"type":39,"value":2176},{"type":30,"tag":1881,"props":2517,"children":2518},{"style":1954},[2519],{"type":39,"value":2274},{"type":30,"tag":1881,"props":2521,"children":2523},{"class":1883,"line":2522},19,[2524,2528,2532,2536,2541,2546,2551,2556,2560,2564,2569,2573,2578,2582],{"type":30,"tag":1881,"props":2525,"children":2526},{"style":1937},[2527],{"type":39,"value":2223},{"type":30,"tag":1881,"props":2529,"children":2530},{"style":2226},[2531],{"type":39,"value":2470},{"type":30,"tag":1881,"props":2533,"children":2534},{"style":2308},[2535],{"type":39,"value":205},{"type":30,"tag":1881,"props":2537,"children":2538},{"style":2226},[2539],{"type":39,"value":2540},"status ",{"type":30,"tag":1881,"props":2542,"children":2543},{"style":1994},[2544],{"type":39,"value":2545},"===",{"type":30,"tag":1881,"props":2547,"children":2548},{"style":2262},[2549],{"type":39,"value":2550}," 'CONVERTED'",{"type":30,"tag":1881,"props":2552,"children":2553},{"style":2226},[2554],{"type":39,"value":2555},") ",{"type":30,"tag":1881,"props":2557,"children":2558},{"style":1937},[2559],{"type":39,"value":2244},{"type":30,"tag":1881,"props":2561,"children":2562},{"style":2247},[2563],{"type":39,"value":2250},{"type":30,"tag":1881,"props":2565,"children":2566},{"style":1921},[2567],{"type":39,"value":2568}," ConflictException",{"type":30,"tag":1881,"props":2570,"children":2571},{"style":2226},[2572],{"type":39,"value":2138},{"type":30,"tag":1881,"props":2574,"children":2575},{"style":2262},[2576],{"type":39,"value":2577},"'Lead déjà converti'",{"type":30,"tag":1881,"props":2579,"children":2580},{"style":2226},[2581],{"type":39,"value":2176},{"type":30,"tag":1881,"props":2583,"children":2584},{"style":1954},[2585],{"type":39,"value":2274},{"type":30,"tag":1881,"props":2587,"children":2589},{"class":1883,"line":2588},20,[2590,2594,2599,2603,2607,2611,2615,2619,2623,2628,2632,2637,2641],{"type":30,"tag":1881,"props":2591,"children":2592},{"style":1937},[2593],{"type":39,"value":2283},{"type":30,"tag":1881,"props":2595,"children":2596},{"style":2286},[2597],{"type":39,"value":2598}," existingClient",{"type":30,"tag":1881,"props":2600,"children":2601},{"style":1994},[2602],{"type":39,"value":2294},{"type":30,"tag":1881,"props":2604,"children":2605},{"style":1937},[2606],{"type":39,"value":2299},{"type":30,"tag":1881,"props":2608,"children":2609},{"style":2302},[2610],{"type":39,"value":2305},{"type":30,"tag":1881,"props":2612,"children":2613},{"style":2308},[2614],{"type":39,"value":205},{"type":30,"tag":1881,"props":2616,"children":2617},{"style":2226},[2618],{"type":39,"value":2315},{"type":30,"tag":1881,"props":2620,"children":2621},{"style":2308},[2622],{"type":39,"value":205},{"type":30,"tag":1881,"props":2624,"children":2625},{"style":2226},[2626],{"type":39,"value":2627},"client",{"type":30,"tag":1881,"props":2629,"children":2630},{"style":2308},[2631],{"type":39,"value":205},{"type":30,"tag":1881,"props":2633,"children":2634},{"style":1921},[2635],{"type":39,"value":2636},"findFirst",{"type":30,"tag":1881,"props":2638,"children":2639},{"style":2226},[2640],{"type":39,"value":2138},{"type":30,"tag":1881,"props":2642,"children":2643},{"style":1954},[2644],{"type":39,"value":2645},"{\n",{"type":30,"tag":1881,"props":2647,"children":2649},{"class":1883,"line":2648},21,[2650,2655,2659,2663,2668,2672,2676,2680,2685,2689,2694],{"type":30,"tag":1881,"props":2651,"children":2652},{"style":2226},[2653],{"type":39,"value":2654},"      where",{"type":30,"tag":1881,"props":2656,"children":2657},{"style":2308},[2658],{"type":39,"value":1997},{"type":30,"tag":1881,"props":2660,"children":2661},{"style":1954},[2662],{"type":39,"value":2355},{"type":30,"tag":1881,"props":2664,"children":2665},{"style":2226},[2666],{"type":39,"value":2667}," email",{"type":30,"tag":1881,"props":2669,"children":2670},{"style":2308},[2671],{"type":39,"value":1997},{"type":30,"tag":1881,"props":2673,"children":2674},{"style":2226},[2675],{"type":39,"value":2289},{"type":30,"tag":1881,"props":2677,"children":2678},{"style":2308},[2679],{"type":39,"value":205},{"type":30,"tag":1881,"props":2681,"children":2682},{"style":2226},[2683],{"type":39,"value":2684},"email",{"type":30,"tag":1881,"props":2686,"children":2687},{"style":1954},[2688],{"type":39,"value":2158},{"type":30,"tag":1881,"props":2690,"children":2691},{"style":2226},[2692],{"type":39,"value":2693}," coachId ",{"type":30,"tag":1881,"props":2695,"children":2696},{"style":1954},[2697],{"type":39,"value":2698},"},\n",{"type":30,"tag":1881,"props":2700,"children":2702},{"class":1883,"line":2701},22,[2703,2708,2712],{"type":30,"tag":1881,"props":2704,"children":2705},{"style":1954},[2706],{"type":39,"value":2707},"    }",{"type":30,"tag":1881,"props":2709,"children":2710},{"style":2226},[2711],{"type":39,"value":2176},{"type":30,"tag":1881,"props":2713,"children":2714},{"style":1954},[2715],{"type":39,"value":2274},{"type":30,"tag":1881,"props":2717,"children":2719},{"class":1883,"line":2718},23,[2720,2724,2729,2733,2737,2741,2745,2750,2754],{"type":30,"tag":1881,"props":2721,"children":2722},{"style":1937},[2723],{"type":39,"value":2223},{"type":30,"tag":1881,"props":2725,"children":2726},{"style":2226},[2727],{"type":39,"value":2728}," (existingClient) ",{"type":30,"tag":1881,"props":2730,"children":2731},{"style":1937},[2732],{"type":39,"value":2244},{"type":30,"tag":1881,"props":2734,"children":2735},{"style":2247},[2736],{"type":39,"value":2250},{"type":30,"tag":1881,"props":2738,"children":2739},{"style":1921},[2740],{"type":39,"value":2568},{"type":30,"tag":1881,"props":2742,"children":2743},{"style":2226},[2744],{"type":39,"value":2138},{"type":30,"tag":1881,"props":2746,"children":2747},{"style":2262},[2748],{"type":39,"value":2749},"'Client existant avec cet email'",{"type":30,"tag":1881,"props":2751,"children":2752},{"style":2226},[2753],{"type":39,"value":2176},{"type":30,"tag":1881,"props":2755,"children":2756},{"style":1954},[2757],{"type":39,"value":2274},{"type":30,"tag":1881,"props":2759,"children":2761},{"class":1883,"line":2760},24,[2762],{"type":30,"tag":1881,"props":2763,"children":2764},{"style":1888},[2765],{"type":39,"value":2766},"    // ... 8 autres lignes de validation métier\n",{"type":30,"tag":1881,"props":2768,"children":2770},{"class":1883,"line":2769},25,[2771],{"type":30,"tag":1881,"props":2772,"children":2773},{"emptyLinePlaceholder":13},[2774],{"type":39,"value":1908},{"type":30,"tag":1881,"props":2776,"children":2778},{"class":1883,"line":2777},26,[2779],{"type":30,"tag":1881,"props":2780,"children":2781},{"style":1888},[2782],{"type":39,"value":2783},"    // 2. Création du client (15 lignes)\n",{"type":30,"tag":1881,"props":2785,"children":2787},{"class":1883,"line":2786},27,[2788,2792,2797,2801,2805,2809,2813,2817,2821,2825,2829,2834,2838],{"type":30,"tag":1881,"props":2789,"children":2790},{"style":1937},[2791],{"type":39,"value":2283},{"type":30,"tag":1881,"props":2793,"children":2794},{"style":2286},[2795],{"type":39,"value":2796}," client",{"type":30,"tag":1881,"props":2798,"children":2799},{"style":1994},[2800],{"type":39,"value":2294},{"type":30,"tag":1881,"props":2802,"children":2803},{"style":1937},[2804],{"type":39,"value":2299},{"type":30,"tag":1881,"props":2806,"children":2807},{"style":2302},[2808],{"type":39,"value":2305},{"type":30,"tag":1881,"props":2810,"children":2811},{"style":2308},[2812],{"type":39,"value":205},{"type":30,"tag":1881,"props":2814,"children":2815},{"style":2226},[2816],{"type":39,"value":2315},{"type":30,"tag":1881,"props":2818,"children":2819},{"style":2308},[2820],{"type":39,"value":205},{"type":30,"tag":1881,"props":2822,"children":2823},{"style":2226},[2824],{"type":39,"value":2627},{"type":30,"tag":1881,"props":2826,"children":2827},{"style":2308},[2828],{"type":39,"value":205},{"type":30,"tag":1881,"props":2830,"children":2831},{"style":1921},[2832],{"type":39,"value":2833},"create",{"type":30,"tag":1881,"props":2835,"children":2836},{"style":2226},[2837],{"type":39,"value":2138},{"type":30,"tag":1881,"props":2839,"children":2840},{"style":1954},[2841],{"type":39,"value":2645},{"type":30,"tag":1881,"props":2843,"children":2845},{"class":1883,"line":2844},28,[2846,2851,2855],{"type":30,"tag":1881,"props":2847,"children":2848},{"style":2226},[2849],{"type":39,"value":2850},"      data",{"type":30,"tag":1881,"props":2852,"children":2853},{"style":2308},[2854],{"type":39,"value":1997},{"type":30,"tag":1881,"props":2856,"children":2857},{"style":1954},[2858],{"type":39,"value":1957},{"type":30,"tag":1881,"props":2860,"children":2862},{"class":1883,"line":2861},29,[2863,2868,2872,2876,2880,2884],{"type":30,"tag":1881,"props":2864,"children":2865},{"style":2226},[2866],{"type":39,"value":2867},"        email",{"type":30,"tag":1881,"props":2869,"children":2870},{"style":2308},[2871],{"type":39,"value":1997},{"type":30,"tag":1881,"props":2873,"children":2874},{"style":2226},[2875],{"type":39,"value":2289},{"type":30,"tag":1881,"props":2877,"children":2878},{"style":2308},[2879],{"type":39,"value":205},{"type":30,"tag":1881,"props":2881,"children":2882},{"style":2226},[2883],{"type":39,"value":2684},{"type":30,"tag":1881,"props":2885,"children":2886},{"style":1954},[2887],{"type":39,"value":2007},{"type":30,"tag":1881,"props":2889,"children":2891},{"class":1883,"line":2890},30,[2892,2897,2901,2905,2909,2914],{"type":30,"tag":1881,"props":2893,"children":2894},{"style":2226},[2895],{"type":39,"value":2896},"        firstName",{"type":30,"tag":1881,"props":2898,"children":2899},{"style":2308},[2900],{"type":39,"value":1997},{"type":30,"tag":1881,"props":2902,"children":2903},{"style":2226},[2904],{"type":39,"value":2289},{"type":30,"tag":1881,"props":2906,"children":2907},{"style":2308},[2908],{"type":39,"value":205},{"type":30,"tag":1881,"props":2910,"children":2911},{"style":2226},[2912],{"type":39,"value":2913},"firstName",{"type":30,"tag":1881,"props":2915,"children":2916},{"style":1954},[2917],{"type":39,"value":2007},{"type":30,"tag":1881,"props":2919,"children":2921},{"class":1883,"line":2920},31,[2922,2927,2931,2935,2939,2944],{"type":30,"tag":1881,"props":2923,"children":2924},{"style":2226},[2925],{"type":39,"value":2926},"        lastName",{"type":30,"tag":1881,"props":2928,"children":2929},{"style":2308},[2930],{"type":39,"value":1997},{"type":30,"tag":1881,"props":2932,"children":2933},{"style":2226},[2934],{"type":39,"value":2289},{"type":30,"tag":1881,"props":2936,"children":2937},{"style":2308},[2938],{"type":39,"value":205},{"type":30,"tag":1881,"props":2940,"children":2941},{"style":2226},[2942],{"type":39,"value":2943},"lastName",{"type":30,"tag":1881,"props":2945,"children":2946},{"style":1954},[2947],{"type":39,"value":2007},{"type":30,"tag":1881,"props":2949,"children":2951},{"class":1883,"line":2950},32,[2952,2957,2961,2965,2969,2974],{"type":30,"tag":1881,"props":2953,"children":2954},{"style":2226},[2955],{"type":39,"value":2956},"        phone",{"type":30,"tag":1881,"props":2958,"children":2959},{"style":2308},[2960],{"type":39,"value":1997},{"type":30,"tag":1881,"props":2962,"children":2963},{"style":2226},[2964],{"type":39,"value":2289},{"type":30,"tag":1881,"props":2966,"children":2967},{"style":2308},[2968],{"type":39,"value":205},{"type":30,"tag":1881,"props":2970,"children":2971},{"style":2226},[2972],{"type":39,"value":2973},"phone",{"type":30,"tag":1881,"props":2975,"children":2976},{"style":1954},[2977],{"type":39,"value":2007},{"type":30,"tag":1881,"props":2979,"children":2981},{"class":1883,"line":2980},33,[2982,2987],{"type":30,"tag":1881,"props":2983,"children":2984},{"style":2226},[2985],{"type":39,"value":2986},"        coachId",{"type":30,"tag":1881,"props":2988,"children":2989},{"style":1954},[2990],{"type":39,"value":2007},{"type":30,"tag":1881,"props":2992,"children":2994},{"class":1883,"line":2993},34,[2995,3000,3004,3009],{"type":30,"tag":1881,"props":2996,"children":2997},{"style":2226},[2998],{"type":39,"value":2999},"        status",{"type":30,"tag":1881,"props":3001,"children":3002},{"style":2308},[3003],{"type":39,"value":1997},{"type":30,"tag":1881,"props":3005,"children":3006},{"style":2262},[3007],{"type":39,"value":3008}," 'ACTIVE'",{"type":30,"tag":1881,"props":3010,"children":3011},{"style":1954},[3012],{"type":39,"value":2007},{"type":30,"tag":1881,"props":3014,"children":3016},{"class":1883,"line":3015},35,[3017,3022,3026,3030],{"type":30,"tag":1881,"props":3018,"children":3019},{"style":2226},[3020],{"type":39,"value":3021},"        createdBy",{"type":30,"tag":1881,"props":3023,"children":3024},{"style":2308},[3025],{"type":39,"value":1997},{"type":30,"tag":1881,"props":3027,"children":3028},{"style":2226},[3029],{"type":39,"value":2163},{"type":30,"tag":1881,"props":3031,"children":3032},{"style":1954},[3033],{"type":39,"value":2007},{"type":30,"tag":1881,"props":3035,"children":3037},{"class":1883,"line":3036},36,[3038,3043,3047,3052],{"type":30,"tag":1881,"props":3039,"children":3040},{"style":2226},[3041],{"type":39,"value":3042},"        convertedFromLeadId",{"type":30,"tag":1881,"props":3044,"children":3045},{"style":2308},[3046],{"type":39,"value":1997},{"type":30,"tag":1881,"props":3048,"children":3049},{"style":2226},[3050],{"type":39,"value":3051}," leadId",{"type":30,"tag":1881,"props":3053,"children":3054},{"style":1954},[3055],{"type":39,"value":2007},{"type":30,"tag":1881,"props":3057,"children":3059},{"class":1883,"line":3058},37,[3060],{"type":30,"tag":1881,"props":3061,"children":3062},{"style":1954},[3063],{"type":39,"value":3064},"      },\n",{"type":30,"tag":1881,"props":3066,"children":3068},{"class":1883,"line":3067},38,[3069,3073,3077],{"type":30,"tag":1881,"props":3070,"children":3071},{"style":1954},[3072],{"type":39,"value":2707},{"type":30,"tag":1881,"props":3074,"children":3075},{"style":2226},[3076],{"type":39,"value":2176},{"type":30,"tag":1881,"props":3078,"children":3079},{"style":1954},[3080],{"type":39,"value":2274},{"type":30,"tag":1881,"props":3082,"children":3084},{"class":1883,"line":3083},39,[3085,3090,3094,3098,3102,3106,3110,3114,3119,3123],{"type":30,"tag":1881,"props":3086,"children":3087},{"style":1937},[3088],{"type":39,"value":3089},"    await",{"type":30,"tag":1881,"props":3091,"children":3092},{"style":2302},[3093],{"type":39,"value":2305},{"type":30,"tag":1881,"props":3095,"children":3096},{"style":2308},[3097],{"type":39,"value":205},{"type":30,"tag":1881,"props":3099,"children":3100},{"style":2226},[3101],{"type":39,"value":2315},{"type":30,"tag":1881,"props":3103,"children":3104},{"style":2308},[3105],{"type":39,"value":205},{"type":30,"tag":1881,"props":3107,"children":3108},{"style":2226},[3109],{"type":39,"value":275},{"type":30,"tag":1881,"props":3111,"children":3112},{"style":2308},[3113],{"type":39,"value":205},{"type":30,"tag":1881,"props":3115,"children":3116},{"style":1921},[3117],{"type":39,"value":3118},"update",{"type":30,"tag":1881,"props":3120,"children":3121},{"style":2226},[3122],{"type":39,"value":2138},{"type":30,"tag":1881,"props":3124,"children":3125},{"style":1954},[3126],{"type":39,"value":2645},{"type":30,"tag":1881,"props":3128,"children":3130},{"class":1883,"line":3129},40,[3131,3135,3139,3143,3147,3151,3155],{"type":30,"tag":1881,"props":3132,"children":3133},{"style":2226},[3134],{"type":39,"value":2654},{"type":30,"tag":1881,"props":3136,"children":3137},{"style":2308},[3138],{"type":39,"value":1997},{"type":30,"tag":1881,"props":3140,"children":3141},{"style":1954},[3142],{"type":39,"value":2355},{"type":30,"tag":1881,"props":3144,"children":3145},{"style":2226},[3146],{"type":39,"value":2360},{"type":30,"tag":1881,"props":3148,"children":3149},{"style":2308},[3150],{"type":39,"value":1997},{"type":30,"tag":1881,"props":3152,"children":3153},{"style":2226},[3154],{"type":39,"value":2369},{"type":30,"tag":1881,"props":3156,"children":3157},{"style":1954},[3158],{"type":39,"value":2698},{"type":30,"tag":1881,"props":3160,"children":3162},{"class":1883,"line":3161},41,[3163,3167,3171,3175,3180,3184,3188,3192,3197,3201,3205,3210,3215,3219,3224,3228,3232,3236,3241],{"type":30,"tag":1881,"props":3164,"children":3165},{"style":2226},[3166],{"type":39,"value":2850},{"type":30,"tag":1881,"props":3168,"children":3169},{"style":2308},[3170],{"type":39,"value":1997},{"type":30,"tag":1881,"props":3172,"children":3173},{"style":1954},[3174],{"type":39,"value":2355},{"type":30,"tag":1881,"props":3176,"children":3177},{"style":2226},[3178],{"type":39,"value":3179}," status",{"type":30,"tag":1881,"props":3181,"children":3182},{"style":2308},[3183],{"type":39,"value":1997},{"type":30,"tag":1881,"props":3185,"children":3186},{"style":2262},[3187],{"type":39,"value":2550},{"type":30,"tag":1881,"props":3189,"children":3190},{"style":1954},[3191],{"type":39,"value":2158},{"type":30,"tag":1881,"props":3193,"children":3194},{"style":2226},[3195],{"type":39,"value":3196}," convertedAt",{"type":30,"tag":1881,"props":3198,"children":3199},{"style":2308},[3200],{"type":39,"value":1997},{"type":30,"tag":1881,"props":3202,"children":3203},{"style":2247},[3204],{"type":39,"value":2250},{"type":30,"tag":1881,"props":3206,"children":3207},{"style":1921},[3208],{"type":39,"value":3209}," Date",{"type":30,"tag":1881,"props":3211,"children":3212},{"style":2226},[3213],{"type":39,"value":3214},"()",{"type":30,"tag":1881,"props":3216,"children":3217},{"style":1954},[3218],{"type":39,"value":2158},{"type":30,"tag":1881,"props":3220,"children":3221},{"style":2226},[3222],{"type":39,"value":3223}," convertedToClientId",{"type":30,"tag":1881,"props":3225,"children":3226},{"style":2308},[3227],{"type":39,"value":1997},{"type":30,"tag":1881,"props":3229,"children":3230},{"style":2226},[3231],{"type":39,"value":2796},{"type":30,"tag":1881,"props":3233,"children":3234},{"style":2308},[3235],{"type":39,"value":205},{"type":30,"tag":1881,"props":3237,"children":3238},{"style":2226},[3239],{"type":39,"value":3240},"id ",{"type":30,"tag":1881,"props":3242,"children":3243},{"style":1954},[3244],{"type":39,"value":2698},{"type":30,"tag":1881,"props":3246,"children":3248},{"class":1883,"line":3247},42,[3249,3253,3257],{"type":30,"tag":1881,"props":3250,"children":3251},{"style":1954},[3252],{"type":39,"value":2707},{"type":30,"tag":1881,"props":3254,"children":3255},{"style":2226},[3256],{"type":39,"value":2176},{"type":30,"tag":1881,"props":3258,"children":3259},{"style":1954},[3260],{"type":39,"value":2274},{"type":30,"tag":1881,"props":3262,"children":3264},{"class":1883,"line":3263},43,[3265],{"type":30,"tag":1881,"props":3266,"children":3267},{"emptyLinePlaceholder":13},[3268],{"type":39,"value":1908},{"type":30,"tag":1881,"props":3270,"children":3272},{"class":1883,"line":3271},44,[3273],{"type":30,"tag":1881,"props":3274,"children":3275},{"style":1888},[3276],{"type":39,"value":3277},"    // 3. Notification Brevo (12 lignes)\n",{"type":30,"tag":1881,"props":3279,"children":3281},{"class":1883,"line":3280},45,[3282,3286,3290,3294,3299,3303,3308,3312],{"type":30,"tag":1881,"props":3283,"children":3284},{"style":1937},[3285],{"type":39,"value":3089},{"type":30,"tag":1881,"props":3287,"children":3288},{"style":2302},[3289],{"type":39,"value":2305},{"type":30,"tag":1881,"props":3291,"children":3292},{"style":2308},[3293],{"type":39,"value":205},{"type":30,"tag":1881,"props":3295,"children":3296},{"style":2226},[3297],{"type":39,"value":3298},"brevoService",{"type":30,"tag":1881,"props":3300,"children":3301},{"style":2308},[3302],{"type":39,"value":205},{"type":30,"tag":1881,"props":3304,"children":3305},{"style":1921},[3306],{"type":39,"value":3307},"sendTransactionalEmail",{"type":30,"tag":1881,"props":3309,"children":3310},{"style":2226},[3311],{"type":39,"value":2138},{"type":30,"tag":1881,"props":3313,"children":3314},{"style":1954},[3315],{"type":39,"value":2645},{"type":30,"tag":1881,"props":3317,"children":3319},{"class":1883,"line":3318},46,[3320,3325,3329,3334,3338,3342,3346,3350,3354,3358,3362,3367,3371,3376,3380,3384,3389,3393,3397,3402,3406,3410,3414,3418,3423,3427,3432],{"type":30,"tag":1881,"props":3321,"children":3322},{"style":2226},[3323],{"type":39,"value":3324},"      to",{"type":30,"tag":1881,"props":3326,"children":3327},{"style":2308},[3328],{"type":39,"value":1997},{"type":30,"tag":1881,"props":3330,"children":3331},{"style":2226},[3332],{"type":39,"value":3333}," [",{"type":30,"tag":1881,"props":3335,"children":3336},{"style":1954},[3337],{"type":39,"value":2341},{"type":30,"tag":1881,"props":3339,"children":3340},{"style":2226},[3341],{"type":39,"value":2667},{"type":30,"tag":1881,"props":3343,"children":3344},{"style":2308},[3345],{"type":39,"value":1997},{"type":30,"tag":1881,"props":3347,"children":3348},{"style":2226},[3349],{"type":39,"value":2796},{"type":30,"tag":1881,"props":3351,"children":3352},{"style":2308},[3353],{"type":39,"value":205},{"type":30,"tag":1881,"props":3355,"children":3356},{"style":2226},[3357],{"type":39,"value":2684},{"type":30,"tag":1881,"props":3359,"children":3360},{"style":1954},[3361],{"type":39,"value":2158},{"type":30,"tag":1881,"props":3363,"children":3364},{"style":2226},[3365],{"type":39,"value":3366}," name",{"type":30,"tag":1881,"props":3368,"children":3369},{"style":2308},[3370],{"type":39,"value":1997},{"type":30,"tag":1881,"props":3372,"children":3373},{"style":2262},[3374],{"type":39,"value":3375}," `",{"type":30,"tag":1881,"props":3377,"children":3378},{"style":2433},[3379],{"type":39,"value":2436},{"type":30,"tag":1881,"props":3381,"children":3382},{"style":2226},[3383],{"type":39,"value":2627},{"type":30,"tag":1881,"props":3385,"children":3387},{"style":3386},"--shiki-default:#81C8BE;--shiki-dark:#9ECBFF",[3388],{"type":39,"value":205},{"type":30,"tag":1881,"props":3390,"children":3391},{"style":2226},[3392],{"type":39,"value":2913},{"type":30,"tag":1881,"props":3394,"children":3395},{"style":2433},[3396],{"type":39,"value":2374},{"type":30,"tag":1881,"props":3398,"children":3399},{"style":2433},[3400],{"type":39,"value":3401}," ${",{"type":30,"tag":1881,"props":3403,"children":3404},{"style":2226},[3405],{"type":39,"value":2627},{"type":30,"tag":1881,"props":3407,"children":3408},{"style":3386},[3409],{"type":39,"value":205},{"type":30,"tag":1881,"props":3411,"children":3412},{"style":2226},[3413],{"type":39,"value":2943},{"type":30,"tag":1881,"props":3415,"children":3416},{"style":2433},[3417],{"type":39,"value":2374},{"type":30,"tag":1881,"props":3419,"children":3420},{"style":2262},[3421],{"type":39,"value":3422},"`",{"type":30,"tag":1881,"props":3424,"children":3425},{"style":1954},[3426],{"type":39,"value":2379},{"type":30,"tag":1881,"props":3428,"children":3429},{"style":2226},[3430],{"type":39,"value":3431},"]",{"type":30,"tag":1881,"props":3433,"children":3434},{"style":1954},[3435],{"type":39,"value":2007},{"type":30,"tag":1881,"props":3437,"children":3439},{"class":1883,"line":3438},47,[3440,3445,3449,3455],{"type":30,"tag":1881,"props":3441,"children":3442},{"style":2226},[3443],{"type":39,"value":3444},"      templateId",{"type":30,"tag":1881,"props":3446,"children":3447},{"style":2308},[3448],{"type":39,"value":1997},{"type":30,"tag":1881,"props":3450,"children":3452},{"style":3451},"--shiki-default:#EF9F76;--shiki-dark:#79B8FF",[3453],{"type":39,"value":3454}," 42",{"type":30,"tag":1881,"props":3456,"children":3457},{"style":1954},[3458],{"type":39,"value":2007},{"type":30,"tag":1881,"props":3460,"children":3462},{"class":1883,"line":3461},48,[3463,3468,3472,3476,3481,3485,3489,3493,3497,3501,3506,3510,3514,3518,3522],{"type":30,"tag":1881,"props":3464,"children":3465},{"style":2226},[3466],{"type":39,"value":3467},"      params",{"type":30,"tag":1881,"props":3469,"children":3470},{"style":2308},[3471],{"type":39,"value":1997},{"type":30,"tag":1881,"props":3473,"children":3474},{"style":1954},[3475],{"type":39,"value":2355},{"type":30,"tag":1881,"props":3477,"children":3478},{"style":2226},[3479],{"type":39,"value":3480}," firstName",{"type":30,"tag":1881,"props":3482,"children":3483},{"style":2308},[3484],{"type":39,"value":1997},{"type":30,"tag":1881,"props":3486,"children":3487},{"style":2226},[3488],{"type":39,"value":2796},{"type":30,"tag":1881,"props":3490,"children":3491},{"style":2308},[3492],{"type":39,"value":205},{"type":30,"tag":1881,"props":3494,"children":3495},{"style":2226},[3496],{"type":39,"value":2913},{"type":30,"tag":1881,"props":3498,"children":3499},{"style":1954},[3500],{"type":39,"value":2158},{"type":30,"tag":1881,"props":3502,"children":3503},{"style":2226},[3504],{"type":39,"value":3505}," coachName",{"type":30,"tag":1881,"props":3507,"children":3508},{"style":2308},[3509],{"type":39,"value":1997},{"type":30,"tag":1881,"props":3511,"children":3512},{"style":2226},[3513],{"type":39,"value":2289},{"type":30,"tag":1881,"props":3515,"children":3516},{"style":2308},[3517],{"type":39,"value":205},{"type":30,"tag":1881,"props":3519,"children":3520},{"style":2226},[3521],{"type":39,"value":2479},{"type":30,"tag":1881,"props":3523,"children":3524},{"style":1954},[3525],{"type":39,"value":2698},{"type":30,"tag":1881,"props":3527,"children":3529},{"class":1883,"line":3528},49,[3530,3534,3538],{"type":30,"tag":1881,"props":3531,"children":3532},{"style":1954},[3533],{"type":39,"value":2707},{"type":30,"tag":1881,"props":3535,"children":3536},{"style":2226},[3537],{"type":39,"value":2176},{"type":30,"tag":1881,"props":3539,"children":3540},{"style":1954},[3541],{"type":39,"value":2274},{"type":30,"tag":1881,"props":3543,"children":3545},{"class":1883,"line":3544},50,[3546,3550,3554,3558,3562,3566,3571,3576,3580,3584,3588,3593,3597],{"type":30,"tag":1881,"props":3547,"children":3548},{"style":1937},[3549],{"type":39,"value":3089},{"type":30,"tag":1881,"props":3551,"children":3552},{"style":2302},[3553],{"type":39,"value":2305},{"type":30,"tag":1881,"props":3555,"children":3556},{"style":2308},[3557],{"type":39,"value":205},{"type":30,"tag":1881,"props":3559,"children":3560},{"style":2226},[3561],{"type":39,"value":3298},{"type":30,"tag":1881,"props":3563,"children":3564},{"style":2308},[3565],{"type":39,"value":205},{"type":30,"tag":1881,"props":3567,"children":3568},{"style":1921},[3569],{"type":39,"value":3570},"addContactToList",{"type":30,"tag":1881,"props":3572,"children":3573},{"style":2226},[3574],{"type":39,"value":3575},"(client",{"type":30,"tag":1881,"props":3577,"children":3578},{"style":2308},[3579],{"type":39,"value":205},{"type":30,"tag":1881,"props":3581,"children":3582},{"style":2226},[3583],{"type":39,"value":2684},{"type":30,"tag":1881,"props":3585,"children":3586},{"style":1954},[3587],{"type":39,"value":2158},{"type":30,"tag":1881,"props":3589,"children":3590},{"style":2262},[3591],{"type":39,"value":3592}," 'clients-actifs'",{"type":30,"tag":1881,"props":3594,"children":3595},{"style":2226},[3596],{"type":39,"value":2176},{"type":30,"tag":1881,"props":3598,"children":3599},{"style":1954},[3600],{"type":39,"value":2274},{"type":30,"tag":1881,"props":3602,"children":3604},{"class":1883,"line":3603},51,[3605],{"type":30,"tag":1881,"props":3606,"children":3607},{"emptyLinePlaceholder":13},[3608],{"type":39,"value":1908},{"type":30,"tag":1881,"props":3610,"children":3612},{"class":1883,"line":3611},52,[3613],{"type":30,"tag":1881,"props":3614,"children":3615},{"style":1888},[3616],{"type":39,"value":3617},"    // 4. Audit (6 lignes)\n",{"type":30,"tag":1881,"props":3619,"children":3621},{"class":1883,"line":3620},53,[3622,3626,3630,3634,3639,3643,3648,3652],{"type":30,"tag":1881,"props":3623,"children":3624},{"style":1937},[3625],{"type":39,"value":3089},{"type":30,"tag":1881,"props":3627,"children":3628},{"style":2302},[3629],{"type":39,"value":2305},{"type":30,"tag":1881,"props":3631,"children":3632},{"style":2308},[3633],{"type":39,"value":205},{"type":30,"tag":1881,"props":3635,"children":3636},{"style":2226},[3637],{"type":39,"value":3638},"auditService",{"type":30,"tag":1881,"props":3640,"children":3641},{"style":2308},[3642],{"type":39,"value":205},{"type":30,"tag":1881,"props":3644,"children":3645},{"style":1921},[3646],{"type":39,"value":3647},"log",{"type":30,"tag":1881,"props":3649,"children":3650},{"style":2226},[3651],{"type":39,"value":2138},{"type":30,"tag":1881,"props":3653,"children":3654},{"style":1954},[3655],{"type":39,"value":2645},{"type":30,"tag":1881,"props":3657,"children":3659},{"class":1883,"line":3658},54,[3660,3665,3669,3674],{"type":30,"tag":1881,"props":3661,"children":3662},{"style":2226},[3663],{"type":39,"value":3664},"      action",{"type":30,"tag":1881,"props":3666,"children":3667},{"style":2308},[3668],{"type":39,"value":1997},{"type":30,"tag":1881,"props":3670,"children":3671},{"style":2262},[3672],{"type":39,"value":3673}," 'LEAD_CONVERTED'",{"type":30,"tag":1881,"props":3675,"children":3676},{"style":1954},[3677],{"type":39,"value":2007},{"type":30,"tag":1881,"props":3679,"children":3681},{"class":1883,"line":3680},55,[3682,3687,3691,3696],{"type":30,"tag":1881,"props":3683,"children":3684},{"style":2226},[3685],{"type":39,"value":3686},"      entityType",{"type":30,"tag":1881,"props":3688,"children":3689},{"style":2308},[3690],{"type":39,"value":1997},{"type":30,"tag":1881,"props":3692,"children":3693},{"style":2262},[3694],{"type":39,"value":3695}," 'client'",{"type":30,"tag":1881,"props":3697,"children":3698},{"style":1954},[3699],{"type":39,"value":2007},{"type":30,"tag":1881,"props":3701,"children":3703},{"class":1883,"line":3702},56,[3704,3709,3713,3717,3721,3726],{"type":30,"tag":1881,"props":3705,"children":3706},{"style":2226},[3707],{"type":39,"value":3708},"      entityId",{"type":30,"tag":1881,"props":3710,"children":3711},{"style":2308},[3712],{"type":39,"value":1997},{"type":30,"tag":1881,"props":3714,"children":3715},{"style":2226},[3716],{"type":39,"value":2796},{"type":30,"tag":1881,"props":3718,"children":3719},{"style":2308},[3720],{"type":39,"value":205},{"type":30,"tag":1881,"props":3722,"children":3723},{"style":2226},[3724],{"type":39,"value":3725},"id",{"type":30,"tag":1881,"props":3727,"children":3728},{"style":1954},[3729],{"type":39,"value":2007},{"type":30,"tag":1881,"props":3731,"children":3733},{"class":1883,"line":3732},57,[3734,3739,3743,3747],{"type":30,"tag":1881,"props":3735,"children":3736},{"style":2226},[3737],{"type":39,"value":3738},"      userId",{"type":30,"tag":1881,"props":3740,"children":3741},{"style":2308},[3742],{"type":39,"value":1997},{"type":30,"tag":1881,"props":3744,"children":3745},{"style":2226},[3746],{"type":39,"value":2163},{"type":30,"tag":1881,"props":3748,"children":3749},{"style":1954},[3750],{"type":39,"value":2007},{"type":30,"tag":1881,"props":3752,"children":3754},{"class":1883,"line":3753},58,[3755,3760,3764,3768,3773,3777,3781],{"type":30,"tag":1881,"props":3756,"children":3757},{"style":2226},[3758],{"type":39,"value":3759},"      meta",{"type":30,"tag":1881,"props":3761,"children":3762},{"style":2308},[3763],{"type":39,"value":1997},{"type":30,"tag":1881,"props":3765,"children":3766},{"style":1954},[3767],{"type":39,"value":2355},{"type":30,"tag":1881,"props":3769,"children":3770},{"style":2226},[3771],{"type":39,"value":3772}," fromLeadId",{"type":30,"tag":1881,"props":3774,"children":3775},{"style":2308},[3776],{"type":39,"value":1997},{"type":30,"tag":1881,"props":3778,"children":3779},{"style":2226},[3780],{"type":39,"value":2369},{"type":30,"tag":1881,"props":3782,"children":3783},{"style":1954},[3784],{"type":39,"value":2698},{"type":30,"tag":1881,"props":3786,"children":3788},{"class":1883,"line":3787},59,[3789,3793,3797],{"type":30,"tag":1881,"props":3790,"children":3791},{"style":1954},[3792],{"type":39,"value":2707},{"type":30,"tag":1881,"props":3794,"children":3795},{"style":2226},[3796],{"type":39,"value":2176},{"type":30,"tag":1881,"props":3798,"children":3799},{"style":1954},[3800],{"type":39,"value":2274},{"type":30,"tag":1881,"props":3802,"children":3804},{"class":1883,"line":3803},60,[3805],{"type":30,"tag":1881,"props":3806,"children":3807},{"emptyLinePlaceholder":13},[3808],{"type":39,"value":1908},{"type":30,"tag":1881,"props":3810,"children":3812},{"class":1883,"line":3811},61,[3813],{"type":30,"tag":1881,"props":3814,"children":3815},{"style":1888},[3816],{"type":39,"value":3817},"    // 5. Événement domaine (4 lignes)\n",{"type":30,"tag":1881,"props":3819,"children":3821},{"class":1883,"line":3820},62,[3822,3827,3831,3836,3840,3845,3849,3854,3858,3862,3867,3871,3875,3879,3883,3887,3891,3895,3899],{"type":30,"tag":1881,"props":3823,"children":3824},{"style":2302},[3825],{"type":39,"value":3826},"    this",{"type":30,"tag":1881,"props":3828,"children":3829},{"style":2308},[3830],{"type":39,"value":205},{"type":30,"tag":1881,"props":3832,"children":3833},{"style":2226},[3834],{"type":39,"value":3835},"eventEmitter",{"type":30,"tag":1881,"props":3837,"children":3838},{"style":2308},[3839],{"type":39,"value":205},{"type":30,"tag":1881,"props":3841,"children":3842},{"style":1921},[3843],{"type":39,"value":3844},"emit",{"type":30,"tag":1881,"props":3846,"children":3847},{"style":2226},[3848],{"type":39,"value":2138},{"type":30,"tag":1881,"props":3850,"children":3851},{"style":2262},[3852],{"type":39,"value":3853},"'client.created'",{"type":30,"tag":1881,"props":3855,"children":3856},{"style":1954},[3857],{"type":39,"value":2158},{"type":30,"tag":1881,"props":3859,"children":3860},{"style":1954},[3861],{"type":39,"value":2355},{"type":30,"tag":1881,"props":3863,"children":3864},{"style":2226},[3865],{"type":39,"value":3866}," clientId",{"type":30,"tag":1881,"props":3868,"children":3869},{"style":2308},[3870],{"type":39,"value":1997},{"type":30,"tag":1881,"props":3872,"children":3873},{"style":2226},[3874],{"type":39,"value":2796},{"type":30,"tag":1881,"props":3876,"children":3877},{"style":2308},[3878],{"type":39,"value":205},{"type":30,"tag":1881,"props":3880,"children":3881},{"style":2226},[3882],{"type":39,"value":3725},{"type":30,"tag":1881,"props":3884,"children":3885},{"style":1954},[3886],{"type":39,"value":2158},{"type":30,"tag":1881,"props":3888,"children":3889},{"style":2226},[3890],{"type":39,"value":2693},{"type":30,"tag":1881,"props":3892,"children":3893},{"style":1954},[3894],{"type":39,"value":2374},{"type":30,"tag":1881,"props":3896,"children":3897},{"style":2226},[3898],{"type":39,"value":2176},{"type":30,"tag":1881,"props":3900,"children":3901},{"style":1954},[3902],{"type":39,"value":2274},{"type":30,"tag":1881,"props":3904,"children":3905},{"class":1883,"line":1759},[3906],{"type":30,"tag":1881,"props":3907,"children":3908},{"emptyLinePlaceholder":13},[3909],{"type":39,"value":1908},{"type":30,"tag":1881,"props":3911,"children":3913},{"class":1883,"line":3912},64,[3914,3919,3924,3928,3933,3938],{"type":30,"tag":1881,"props":3915,"children":3916},{"style":1937},[3917],{"type":39,"value":3918},"    return",{"type":30,"tag":1881,"props":3920,"children":3921},{"style":2226},[3922],{"type":39,"value":3923}," ClientDto",{"type":30,"tag":1881,"props":3925,"children":3926},{"style":2308},[3927],{"type":39,"value":205},{"type":30,"tag":1881,"props":3929,"children":3930},{"style":1921},[3931],{"type":39,"value":3932},"fromPrisma",{"type":30,"tag":1881,"props":3934,"children":3935},{"style":2226},[3936],{"type":39,"value":3937},"(client)",{"type":30,"tag":1881,"props":3939,"children":3940},{"style":1954},[3941],{"type":39,"value":2274},{"type":30,"tag":1881,"props":3943,"children":3945},{"class":1883,"line":3944},65,[3946],{"type":30,"tag":1881,"props":3947,"children":3948},{"style":1954},[3949],{"type":39,"value":3950},"  }\n",{"type":30,"tag":1881,"props":3952,"children":3954},{"class":1883,"line":3953},66,[3955],{"type":30,"tag":1881,"props":3956,"children":3957},{"style":1954},[3958],{"type":39,"value":3959},"}\n",{"type":30,"tag":31,"props":3961,"children":3962},{},[3963,3965,3971,3972,3978,3979,3985,3986,3992,3993,3999,4000,4006],{"type":39,"value":3964},"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":30,"tag":262,"props":3966,"children":3968},{"className":3967},[],[3969],{"type":39,"value":3970},"assertLeadIsConvertible",{"type":39,"value":269},{"type":30,"tag":262,"props":3973,"children":3975},{"className":3974},[],[3976],{"type":39,"value":3977},"createClientFromLead",{"type":39,"value":269},{"type":30,"tag":262,"props":3980,"children":3982},{"className":3981},[],[3983],{"type":39,"value":3984},"markLeadAsConverted",{"type":39,"value":269},{"type":30,"tag":262,"props":3987,"children":3989},{"className":3988},[],[3990],{"type":39,"value":3991},"notifyClientOnboarding",{"type":39,"value":269},{"type":30,"tag":262,"props":3994,"children":3996},{"className":3995},[],[3997],{"type":39,"value":3998},"logConversionAudit",{"type":39,"value":269},{"type":30,"tag":262,"props":4001,"children":4003},{"className":4002},[],[4004],{"type":39,"value":4005},"emitClientCreated",{"type":39,"value":4007},". Chacun est testable isolément. Chacun est lisible en 30 secondes.",{"type":30,"tag":31,"props":4009,"children":4010},{},[4011,4013,4018],{"type":39,"value":4012},"Le prompt que j'utilise : ",{"type":30,"tag":42,"props":4014,"children":4015},{},[4016],{"type":39,"value":4017},"\"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":39,"value":4019}," Claude exécute proprement. Le problème est qu'il ne le fait jamais spontanément.",{"type":30,"tag":55,"props":4021,"children":4022},{},[],{"type":30,"tag":59,"props":4024,"children":4026},{"id":4025},"pattern-2-couplage-métierorm",[4027],{"type":39,"value":4028},"Pattern #2 : couplage métier/ORM",{"type":30,"tag":31,"props":4030,"children":4031},{},[4032,4034,4040],{"type":39,"value":4033},"Celui-là est plus insidieux. Claude injecte directement le ",{"type":30,"tag":262,"props":4035,"children":4037},{"className":4036},[],[4038],{"type":39,"value":4039},"PrismaClient",{"type":39,"value":4041}," 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":30,"tag":31,"props":4043,"children":4044},{},[4045,4047,4053],{"type":39,"value":4046},"Concrètement, j'ai vu ça dans crmcoaching sur le bounded context ",{"type":30,"tag":262,"props":4048,"children":4050},{"className":4049},[],[4051],{"type":39,"value":4052},"slot-hold",{"type":39,"value":4054}," :",{"type":30,"tag":1871,"props":4056,"children":4058},{"className":1873,"code":4057,"language":1875,"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",[4059],{"type":30,"tag":262,"props":4060,"children":4061},{"__ignoreMap":8},[4062,4070,4078,4085,4100,4120,4131,4163,4174,4181,4254,4312,4396,4411,4509,4579,4586],{"type":30,"tag":1881,"props":4063,"children":4064},{"class":1883,"line":1884},[4065],{"type":30,"tag":1881,"props":4066,"children":4067},{"style":1888},[4068],{"type":39,"value":4069},"// apps/api/src/application/use-cases/check-slot-availability.use-case.ts\n",{"type":30,"tag":1881,"props":4071,"children":4072},{"class":1883,"line":955},[4073],{"type":30,"tag":1881,"props":4074,"children":4075},{"style":1888},[4076],{"type":39,"value":4077},"// Couplage direct Prisma dans le use case (anti-pattern)\n",{"type":30,"tag":1881,"props":4079,"children":4080},{"class":1883,"line":1902},[4081],{"type":30,"tag":1881,"props":4082,"children":4083},{"emptyLinePlaceholder":13},[4084],{"type":39,"value":1908},{"type":30,"tag":1881,"props":4086,"children":4087},{"class":1883,"line":1911},[4088,4092,4096],{"type":30,"tag":1881,"props":4089,"children":4090},{"style":1915},[4091],{"type":39,"value":1918},{"type":30,"tag":1881,"props":4093,"children":4094},{"style":1921},[4095],{"type":39,"value":1924},{"type":30,"tag":1881,"props":4097,"children":4098},{"style":1927},[4099],{"type":39,"value":1930},{"type":30,"tag":1881,"props":4101,"children":4102},{"class":1883,"line":1933},[4103,4107,4111,4116],{"type":30,"tag":1881,"props":4104,"children":4105},{"style":1937},[4106],{"type":39,"value":1940},{"type":30,"tag":1881,"props":4108,"children":4109},{"style":1937},[4110],{"type":39,"value":1945},{"type":30,"tag":1881,"props":4112,"children":4113},{"style":1948},[4114],{"type":39,"value":4115}," CheckSlotAvailabilityUseCase",{"type":30,"tag":1881,"props":4117,"children":4118},{"style":1954},[4119],{"type":39,"value":1957},{"type":30,"tag":1881,"props":4121,"children":4122},{"class":1883,"line":1960},[4123,4127],{"type":30,"tag":1881,"props":4124,"children":4125},{"style":1937},[4126],{"type":39,"value":1966},{"type":30,"tag":1881,"props":4128,"children":4129},{"style":1954},[4130],{"type":39,"value":1971},{"type":30,"tag":1881,"props":4132,"children":4133},{"class":1883,"line":1974},[4134,4138,4142,4146,4150,4154,4158],{"type":30,"tag":1881,"props":4135,"children":4136},{"style":1937},[4137],{"type":39,"value":1980},{"type":30,"tag":1881,"props":4139,"children":4140},{"style":1937},[4141],{"type":39,"value":1985},{"type":30,"tag":1881,"props":4143,"children":4144},{"style":1988},[4145],{"type":39,"value":1991},{"type":30,"tag":1881,"props":4147,"children":4148},{"style":1994},[4149],{"type":39,"value":1997},{"type":30,"tag":1881,"props":4151,"children":4152},{"style":1948},[4153],{"type":39,"value":2002},{"type":30,"tag":1881,"props":4155,"children":4156},{"style":1954},[4157],{"type":39,"value":2158},{"type":30,"tag":1881,"props":4159,"children":4160},{"style":1888},[4161],{"type":39,"value":4162}," // couplage direct infra\n",{"type":30,"tag":1881,"props":4164,"children":4165},{"class":1883,"line":2010},[4166,4170],{"type":30,"tag":1881,"props":4167,"children":4168},{"style":1954},[4169],{"type":39,"value":2106},{"type":30,"tag":1881,"props":4171,"children":4172},{"style":1954},[4173],{"type":39,"value":2111},{"type":30,"tag":1881,"props":4175,"children":4176},{"class":1883,"line":2040},[4177],{"type":30,"tag":1881,"props":4178,"children":4179},{"emptyLinePlaceholder":13},[4180],{"type":39,"value":1908},{"type":30,"tag":1881,"props":4182,"children":4183},{"class":1883,"line":2070},[4184,4188,4192,4196,4201,4205,4209,4213,4217,4221,4225,4229,4233,4237,4241,4246,4250],{"type":30,"tag":1881,"props":4185,"children":4186},{"style":1937},[4187],{"type":39,"value":2128},{"type":30,"tag":1881,"props":4189,"children":4190},{"style":1921},[4191],{"type":39,"value":2133},{"type":30,"tag":1881,"props":4193,"children":4194},{"style":1954},[4195],{"type":39,"value":2138},{"type":30,"tag":1881,"props":4197,"children":4198},{"style":1988},[4199],{"type":39,"value":4200},"slotId",{"type":30,"tag":1881,"props":4202,"children":4203},{"style":1994},[4204],{"type":39,"value":1997},{"type":30,"tag":1881,"props":4206,"children":4207},{"style":2150},[4208],{"type":39,"value":2153},{"type":30,"tag":1881,"props":4210,"children":4211},{"style":1954},[4212],{"type":39,"value":2158},{"type":30,"tag":1881,"props":4214,"children":4215},{"style":1988},[4216],{"type":39,"value":2163},{"type":30,"tag":1881,"props":4218,"children":4219},{"style":1994},[4220],{"type":39,"value":1997},{"type":30,"tag":1881,"props":4222,"children":4223},{"style":2150},[4224],{"type":39,"value":2153},{"type":30,"tag":1881,"props":4226,"children":4227},{"style":1954},[4228],{"type":39,"value":2176},{"type":30,"tag":1881,"props":4230,"children":4231},{"style":1994},[4232],{"type":39,"value":1997},{"type":30,"tag":1881,"props":4234,"children":4235},{"style":1948},[4236],{"type":39,"value":2185},{"type":30,"tag":1881,"props":4238,"children":4239},{"style":2188},[4240],{"type":39,"value":2191},{"type":30,"tag":1881,"props":4242,"children":4243},{"style":2150},[4244],{"type":39,"value":4245},"boolean",{"type":30,"tag":1881,"props":4247,"children":4248},{"style":2188},[4249],{"type":39,"value":2201},{"type":30,"tag":1881,"props":4251,"children":4252},{"style":1954},[4253],{"type":39,"value":1957},{"type":30,"tag":1881,"props":4255,"children":4256},{"class":1883,"line":2100},[4257,4261,4266,4270,4274,4278,4282,4286,4290,4295,4299,4304,4308],{"type":30,"tag":1881,"props":4258,"children":4259},{"style":1937},[4260],{"type":39,"value":2283},{"type":30,"tag":1881,"props":4262,"children":4263},{"style":2286},[4264],{"type":39,"value":4265}," holds",{"type":30,"tag":1881,"props":4267,"children":4268},{"style":1994},[4269],{"type":39,"value":2294},{"type":30,"tag":1881,"props":4271,"children":4272},{"style":1937},[4273],{"type":39,"value":2299},{"type":30,"tag":1881,"props":4275,"children":4276},{"style":2302},[4277],{"type":39,"value":2305},{"type":30,"tag":1881,"props":4279,"children":4280},{"style":2308},[4281],{"type":39,"value":205},{"type":30,"tag":1881,"props":4283,"children":4284},{"style":2226},[4285],{"type":39,"value":2315},{"type":30,"tag":1881,"props":4287,"children":4288},{"style":2308},[4289],{"type":39,"value":205},{"type":30,"tag":1881,"props":4291,"children":4292},{"style":2226},[4293],{"type":39,"value":4294},"slotHold",{"type":30,"tag":1881,"props":4296,"children":4297},{"style":2308},[4298],{"type":39,"value":205},{"type":30,"tag":1881,"props":4300,"children":4301},{"style":1921},[4302],{"type":39,"value":4303},"count",{"type":30,"tag":1881,"props":4305,"children":4306},{"style":2226},[4307],{"type":39,"value":2138},{"type":30,"tag":1881,"props":4309,"children":4310},{"style":1954},[4311],{"type":39,"value":2645},{"type":30,"tag":1881,"props":4313,"children":4314},{"class":1883,"line":2114},[4315,4319,4323,4327,4332,4336,4340,4344,4348,4352,4357,4361,4365,4370,4374,4378,4382,4387,4391],{"type":30,"tag":1881,"props":4316,"children":4317},{"style":2226},[4318],{"type":39,"value":2654},{"type":30,"tag":1881,"props":4320,"children":4321},{"style":2308},[4322],{"type":39,"value":1997},{"type":30,"tag":1881,"props":4324,"children":4325},{"style":1954},[4326],{"type":39,"value":2355},{"type":30,"tag":1881,"props":4328,"children":4329},{"style":2226},[4330],{"type":39,"value":4331}," slotId",{"type":30,"tag":1881,"props":4333,"children":4334},{"style":1954},[4335],{"type":39,"value":2158},{"type":30,"tag":1881,"props":4337,"children":4338},{"style":2226},[4339],{"type":39,"value":3179},{"type":30,"tag":1881,"props":4341,"children":4342},{"style":2308},[4343],{"type":39,"value":1997},{"type":30,"tag":1881,"props":4345,"children":4346},{"style":2262},[4347],{"type":39,"value":3008},{"type":30,"tag":1881,"props":4349,"children":4350},{"style":1954},[4351],{"type":39,"value":2158},{"type":30,"tag":1881,"props":4353,"children":4354},{"style":2226},[4355],{"type":39,"value":4356}," expiresAt",{"type":30,"tag":1881,"props":4358,"children":4359},{"style":2308},[4360],{"type":39,"value":1997},{"type":30,"tag":1881,"props":4362,"children":4363},{"style":1954},[4364],{"type":39,"value":2355},{"type":30,"tag":1881,"props":4366,"children":4367},{"style":2226},[4368],{"type":39,"value":4369}," gt",{"type":30,"tag":1881,"props":4371,"children":4372},{"style":2308},[4373],{"type":39,"value":1997},{"type":30,"tag":1881,"props":4375,"children":4376},{"style":2247},[4377],{"type":39,"value":2250},{"type":30,"tag":1881,"props":4379,"children":4380},{"style":1921},[4381],{"type":39,"value":3209},{"type":30,"tag":1881,"props":4383,"children":4384},{"style":2226},[4385],{"type":39,"value":4386},"() ",{"type":30,"tag":1881,"props":4388,"children":4389},{"style":1954},[4390],{"type":39,"value":2374},{"type":30,"tag":1881,"props":4392,"children":4393},{"style":1954},[4394],{"type":39,"value":4395}," },\n",{"type":30,"tag":1881,"props":4397,"children":4398},{"class":1883,"line":2122},[4399,4403,4407],{"type":30,"tag":1881,"props":4400,"children":4401},{"style":1954},[4402],{"type":39,"value":2707},{"type":30,"tag":1881,"props":4404,"children":4405},{"style":2226},[4406],{"type":39,"value":2176},{"type":30,"tag":1881,"props":4408,"children":4409},{"style":1954},[4410],{"type":39,"value":2274},{"type":30,"tag":1881,"props":4412,"children":4413},{"class":1883,"line":2208},[4414,4418,4423,4427,4431,4435,4439,4443,4447,4452,4456,4460,4464,4468,4472,4476,4480,4484,4488,4493,4497,4501,4505],{"type":30,"tag":1881,"props":4415,"children":4416},{"style":1937},[4417],{"type":39,"value":2283},{"type":30,"tag":1881,"props":4419,"children":4420},{"style":2286},[4421],{"type":39,"value":4422}," slot",{"type":30,"tag":1881,"props":4424,"children":4425},{"style":1994},[4426],{"type":39,"value":2294},{"type":30,"tag":1881,"props":4428,"children":4429},{"style":1937},[4430],{"type":39,"value":2299},{"type":30,"tag":1881,"props":4432,"children":4433},{"style":2302},[4434],{"type":39,"value":2305},{"type":30,"tag":1881,"props":4436,"children":4437},{"style":2308},[4438],{"type":39,"value":205},{"type":30,"tag":1881,"props":4440,"children":4441},{"style":2226},[4442],{"type":39,"value":2315},{"type":30,"tag":1881,"props":4444,"children":4445},{"style":2308},[4446],{"type":39,"value":205},{"type":30,"tag":1881,"props":4448,"children":4449},{"style":2226},[4450],{"type":39,"value":4451},"slot",{"type":30,"tag":1881,"props":4453,"children":4454},{"style":2308},[4455],{"type":39,"value":205},{"type":30,"tag":1881,"props":4457,"children":4458},{"style":1921},[4459],{"type":39,"value":2332},{"type":30,"tag":1881,"props":4461,"children":4462},{"style":2226},[4463],{"type":39,"value":2138},{"type":30,"tag":1881,"props":4465,"children":4466},{"style":1954},[4467],{"type":39,"value":2341},{"type":30,"tag":1881,"props":4469,"children":4470},{"style":2226},[4471],{"type":39,"value":2346},{"type":30,"tag":1881,"props":4473,"children":4474},{"style":2308},[4475],{"type":39,"value":1997},{"type":30,"tag":1881,"props":4477,"children":4478},{"style":1954},[4479],{"type":39,"value":2355},{"type":30,"tag":1881,"props":4481,"children":4482},{"style":2226},[4483],{"type":39,"value":2360},{"type":30,"tag":1881,"props":4485,"children":4486},{"style":2308},[4487],{"type":39,"value":1997},{"type":30,"tag":1881,"props":4489,"children":4490},{"style":2226},[4491],{"type":39,"value":4492}," slotId ",{"type":30,"tag":1881,"props":4494,"children":4495},{"style":1954},[4496],{"type":39,"value":2374},{"type":30,"tag":1881,"props":4498,"children":4499},{"style":1954},[4500],{"type":39,"value":2379},{"type":30,"tag":1881,"props":4502,"children":4503},{"style":2226},[4504],{"type":39,"value":2176},{"type":30,"tag":1881,"props":4506,"children":4507},{"style":1954},[4508],{"type":39,"value":2274},{"type":30,"tag":1881,"props":4510,"children":4511},{"class":1883,"line":2217},[4512,4516,4521,4526,4531,4536,4540,4544,4548,4552,4556,4561,4566,4570,4575],{"type":30,"tag":1881,"props":4513,"children":4514},{"style":1937},[4515],{"type":39,"value":3918},{"type":30,"tag":1881,"props":4517,"children":4518},{"style":2226},[4519],{"type":39,"value":4520}," slot ",{"type":30,"tag":1881,"props":4522,"children":4523},{"style":1994},[4524],{"type":39,"value":4525},"!=",{"type":30,"tag":1881,"props":4527,"children":4528},{"style":2150},[4529],{"type":39,"value":4530}," null",{"type":30,"tag":1881,"props":4532,"children":4533},{"style":1994},[4534],{"type":39,"value":4535}," &&",{"type":30,"tag":1881,"props":4537,"children":4538},{"style":2226},[4539],{"type":39,"value":4422},{"type":30,"tag":1881,"props":4541,"children":4542},{"style":2308},[4543],{"type":39,"value":205},{"type":30,"tag":1881,"props":4545,"children":4546},{"style":2226},[4547],{"type":39,"value":2479},{"type":30,"tag":1881,"props":4549,"children":4550},{"style":1994},[4551],{"type":39,"value":2545},{"type":30,"tag":1881,"props":4553,"children":4554},{"style":2226},[4555],{"type":39,"value":2693},{"type":30,"tag":1881,"props":4557,"children":4558},{"style":1994},[4559],{"type":39,"value":4560},"&&",{"type":30,"tag":1881,"props":4562,"children":4563},{"style":2226},[4564],{"type":39,"value":4565}," holds ",{"type":30,"tag":1881,"props":4567,"children":4568},{"style":1994},[4569],{"type":39,"value":2545},{"type":30,"tag":1881,"props":4571,"children":4572},{"style":3451},[4573],{"type":39,"value":4574}," 0",{"type":30,"tag":1881,"props":4576,"children":4577},{"style":1954},[4578],{"type":39,"value":2274},{"type":30,"tag":1881,"props":4580,"children":4581},{"class":1883,"line":2277},[4582],{"type":30,"tag":1881,"props":4583,"children":4584},{"style":1954},[4585],{"type":39,"value":3950},{"type":30,"tag":1881,"props":4587,"children":4588},{"class":1883,"line":2390},[4589],{"type":30,"tag":1881,"props":4590,"children":4591},{"style":1954},[4592],{"type":39,"value":3959},{"type":30,"tag":31,"props":4594,"children":4595},{},[4596,4598,4604,4606,4612,4614,4620,4622,4628,4629,4635,4637,4643],{"type":39,"value":4597},"Le contre-pattern, c'est l'",{"type":30,"tag":88,"props":4599,"children":4601},{"href":4600},"/fr/architecture-craft/architecture-hexagonale-java-exemples-bonnes-pratiques",[4602],{"type":39,"value":4603},"architecture hexagonale d'Alistair Cockburn",{"type":39,"value":4605}," (2005). La règle métier ne connaît pas Prisma. Elle prend un port ",{"type":30,"tag":262,"props":4607,"children":4609},{"className":4608},[],[4610],{"type":39,"value":4611},"ISlotHoldRepository",{"type":39,"value":4613}," qui expose ",{"type":30,"tag":262,"props":4615,"children":4617},{"className":4616},[],[4618],{"type":39,"value":4619},"countActiveHolds(slotId)",{"type":39,"value":4621}," et un port ",{"type":30,"tag":262,"props":4623,"children":4625},{"className":4624},[],[4626],{"type":39,"value":4627},"ISlotRepository",{"type":39,"value":4613},{"type":30,"tag":262,"props":4630,"children":4632},{"className":4631},[],[4633],{"type":39,"value":4634},"findById(slotId)",{"type":39,"value":4636},". L'implémentation Prisma vit dans ",{"type":30,"tag":262,"props":4638,"children":4640},{"className":4639},[],[4641],{"type":39,"value":4642},"infrastructure/",{"type":39,"value":4644},". Les tests unitaires utilisent un fake repository en mémoire.",{"type":30,"tag":1871,"props":4646,"children":4648},{"className":1873,"code":4647,"language":1875,"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",[4649],{"type":30,"tag":262,"props":4650,"children":4651},{"__ignoreMap":8},[4652,4660,4681,4734,4741,4748,4755,4770,4789,4800,4829,4857,4868,4875,4946,4996,5056,5106,5130,5137],{"type":30,"tag":1881,"props":4653,"children":4654},{"class":1883,"line":1884},[4655],{"type":30,"tag":1881,"props":4656,"children":4657},{"style":1888},[4658],{"type":39,"value":4659},"// apps/api/src/domain/ports/slot-hold.repository.port.ts\n",{"type":30,"tag":1881,"props":4661,"children":4662},{"class":1883,"line":955},[4663,4667,4672,4677],{"type":30,"tag":1881,"props":4664,"children":4665},{"style":1937},[4666],{"type":39,"value":1940},{"type":30,"tag":1881,"props":4668,"children":4669},{"style":1937},[4670],{"type":39,"value":4671}," interface",{"type":30,"tag":1881,"props":4673,"children":4674},{"style":1948},[4675],{"type":39,"value":4676}," ISlotHoldRepository",{"type":30,"tag":1881,"props":4678,"children":4679},{"style":1954},[4680],{"type":39,"value":1957},{"type":30,"tag":1881,"props":4682,"children":4683},{"class":1883,"line":1902},[4684,4689,4693,4697,4701,4705,4709,4713,4717,4721,4726,4730],{"type":30,"tag":1881,"props":4685,"children":4686},{"style":1921},[4687],{"type":39,"value":4688},"  countActiveHolds",{"type":30,"tag":1881,"props":4690,"children":4691},{"style":1954},[4692],{"type":39,"value":2138},{"type":30,"tag":1881,"props":4694,"children":4695},{"style":1988},[4696],{"type":39,"value":4200},{"type":30,"tag":1881,"props":4698,"children":4699},{"style":1994},[4700],{"type":39,"value":1997},{"type":30,"tag":1881,"props":4702,"children":4703},{"style":2150},[4704],{"type":39,"value":2153},{"type":30,"tag":1881,"props":4706,"children":4707},{"style":1954},[4708],{"type":39,"value":2176},{"type":30,"tag":1881,"props":4710,"children":4711},{"style":1994},[4712],{"type":39,"value":1997},{"type":30,"tag":1881,"props":4714,"children":4715},{"style":1948},[4716],{"type":39,"value":2185},{"type":30,"tag":1881,"props":4718,"children":4719},{"style":2188},[4720],{"type":39,"value":2191},{"type":30,"tag":1881,"props":4722,"children":4723},{"style":2150},[4724],{"type":39,"value":4725},"number",{"type":30,"tag":1881,"props":4727,"children":4728},{"style":2188},[4729],{"type":39,"value":2201},{"type":30,"tag":1881,"props":4731,"children":4732},{"style":1954},[4733],{"type":39,"value":2274},{"type":30,"tag":1881,"props":4735,"children":4736},{"class":1883,"line":1911},[4737],{"type":30,"tag":1881,"props":4738,"children":4739},{"style":1954},[4740],{"type":39,"value":3959},{"type":30,"tag":1881,"props":4742,"children":4743},{"class":1883,"line":1933},[4744],{"type":30,"tag":1881,"props":4745,"children":4746},{"emptyLinePlaceholder":13},[4747],{"type":39,"value":1908},{"type":30,"tag":1881,"props":4749,"children":4750},{"class":1883,"line":1960},[4751],{"type":30,"tag":1881,"props":4752,"children":4753},{"style":1888},[4754],{"type":39,"value":4069},{"type":30,"tag":1881,"props":4756,"children":4757},{"class":1883,"line":1974},[4758,4762,4766],{"type":30,"tag":1881,"props":4759,"children":4760},{"style":1915},[4761],{"type":39,"value":1918},{"type":30,"tag":1881,"props":4763,"children":4764},{"style":1921},[4765],{"type":39,"value":1924},{"type":30,"tag":1881,"props":4767,"children":4768},{"style":1927},[4769],{"type":39,"value":1930},{"type":30,"tag":1881,"props":4771,"children":4772},{"class":1883,"line":2010},[4773,4777,4781,4785],{"type":30,"tag":1881,"props":4774,"children":4775},{"style":1937},[4776],{"type":39,"value":1940},{"type":30,"tag":1881,"props":4778,"children":4779},{"style":1937},[4780],{"type":39,"value":1945},{"type":30,"tag":1881,"props":4782,"children":4783},{"style":1948},[4784],{"type":39,"value":4115},{"type":30,"tag":1881,"props":4786,"children":4787},{"style":1954},[4788],{"type":39,"value":1957},{"type":30,"tag":1881,"props":4790,"children":4791},{"class":1883,"line":2040},[4792,4796],{"type":30,"tag":1881,"props":4793,"children":4794},{"style":1937},[4795],{"type":39,"value":1966},{"type":30,"tag":1881,"props":4797,"children":4798},{"style":1954},[4799],{"type":39,"value":1971},{"type":30,"tag":1881,"props":4801,"children":4802},{"class":1883,"line":2070},[4803,4807,4811,4816,4820,4825],{"type":30,"tag":1881,"props":4804,"children":4805},{"style":1937},[4806],{"type":39,"value":1980},{"type":30,"tag":1881,"props":4808,"children":4809},{"style":1937},[4810],{"type":39,"value":1985},{"type":30,"tag":1881,"props":4812,"children":4813},{"style":1988},[4814],{"type":39,"value":4815}," slotRepo",{"type":30,"tag":1881,"props":4817,"children":4818},{"style":1994},[4819],{"type":39,"value":1997},{"type":30,"tag":1881,"props":4821,"children":4822},{"style":1948},[4823],{"type":39,"value":4824}," ISlotRepository",{"type":30,"tag":1881,"props":4826,"children":4827},{"style":1954},[4828],{"type":39,"value":2007},{"type":30,"tag":1881,"props":4830,"children":4831},{"class":1883,"line":2100},[4832,4836,4840,4845,4849,4853],{"type":30,"tag":1881,"props":4833,"children":4834},{"style":1937},[4835],{"type":39,"value":1980},{"type":30,"tag":1881,"props":4837,"children":4838},{"style":1937},[4839],{"type":39,"value":1985},{"type":30,"tag":1881,"props":4841,"children":4842},{"style":1988},[4843],{"type":39,"value":4844}," slotHoldRepo",{"type":30,"tag":1881,"props":4846,"children":4847},{"style":1994},[4848],{"type":39,"value":1997},{"type":30,"tag":1881,"props":4850,"children":4851},{"style":1948},[4852],{"type":39,"value":4676},{"type":30,"tag":1881,"props":4854,"children":4855},{"style":1954},[4856],{"type":39,"value":2007},{"type":30,"tag":1881,"props":4858,"children":4859},{"class":1883,"line":2114},[4860,4864],{"type":30,"tag":1881,"props":4861,"children":4862},{"style":1954},[4863],{"type":39,"value":2106},{"type":30,"tag":1881,"props":4865,"children":4866},{"style":1954},[4867],{"type":39,"value":2111},{"type":30,"tag":1881,"props":4869,"children":4870},{"class":1883,"line":2122},[4871],{"type":30,"tag":1881,"props":4872,"children":4873},{"emptyLinePlaceholder":13},[4874],{"type":39,"value":1908},{"type":30,"tag":1881,"props":4876,"children":4877},{"class":1883,"line":2208},[4878,4882,4886,4890,4894,4898,4902,4906,4910,4914,4918,4922,4926,4930,4934,4938,4942],{"type":30,"tag":1881,"props":4879,"children":4880},{"style":1937},[4881],{"type":39,"value":2128},{"type":30,"tag":1881,"props":4883,"children":4884},{"style":1921},[4885],{"type":39,"value":2133},{"type":30,"tag":1881,"props":4887,"children":4888},{"style":1954},[4889],{"type":39,"value":2138},{"type":30,"tag":1881,"props":4891,"children":4892},{"style":1988},[4893],{"type":39,"value":4200},{"type":30,"tag":1881,"props":4895,"children":4896},{"style":1994},[4897],{"type":39,"value":1997},{"type":30,"tag":1881,"props":4899,"children":4900},{"style":2150},[4901],{"type":39,"value":2153},{"type":30,"tag":1881,"props":4903,"children":4904},{"style":1954},[4905],{"type":39,"value":2158},{"type":30,"tag":1881,"props":4907,"children":4908},{"style":1988},[4909],{"type":39,"value":2163},{"type":30,"tag":1881,"props":4911,"children":4912},{"style":1994},[4913],{"type":39,"value":1997},{"type":30,"tag":1881,"props":4915,"children":4916},{"style":2150},[4917],{"type":39,"value":2153},{"type":30,"tag":1881,"props":4919,"children":4920},{"style":1954},[4921],{"type":39,"value":2176},{"type":30,"tag":1881,"props":4923,"children":4924},{"style":1994},[4925],{"type":39,"value":1997},{"type":30,"tag":1881,"props":4927,"children":4928},{"style":1948},[4929],{"type":39,"value":2185},{"type":30,"tag":1881,"props":4931,"children":4932},{"style":2188},[4933],{"type":39,"value":2191},{"type":30,"tag":1881,"props":4935,"children":4936},{"style":2150},[4937],{"type":39,"value":4245},{"type":30,"tag":1881,"props":4939,"children":4940},{"style":2188},[4941],{"type":39,"value":2201},{"type":30,"tag":1881,"props":4943,"children":4944},{"style":1954},[4945],{"type":39,"value":1957},{"type":30,"tag":1881,"props":4947,"children":4948},{"class":1883,"line":2217},[4949,4953,4957,4961,4965,4969,4973,4978,4982,4987,4992],{"type":30,"tag":1881,"props":4950,"children":4951},{"style":1937},[4952],{"type":39,"value":2283},{"type":30,"tag":1881,"props":4954,"children":4955},{"style":2286},[4956],{"type":39,"value":4422},{"type":30,"tag":1881,"props":4958,"children":4959},{"style":1994},[4960],{"type":39,"value":2294},{"type":30,"tag":1881,"props":4962,"children":4963},{"style":1937},[4964],{"type":39,"value":2299},{"type":30,"tag":1881,"props":4966,"children":4967},{"style":2302},[4968],{"type":39,"value":2305},{"type":30,"tag":1881,"props":4970,"children":4971},{"style":2308},[4972],{"type":39,"value":205},{"type":30,"tag":1881,"props":4974,"children":4975},{"style":2226},[4976],{"type":39,"value":4977},"slotRepo",{"type":30,"tag":1881,"props":4979,"children":4980},{"style":2308},[4981],{"type":39,"value":205},{"type":30,"tag":1881,"props":4983,"children":4984},{"style":1921},[4985],{"type":39,"value":4986},"findById",{"type":30,"tag":1881,"props":4988,"children":4989},{"style":2226},[4990],{"type":39,"value":4991},"(slotId)",{"type":30,"tag":1881,"props":4993,"children":4994},{"style":1954},[4995],{"type":39,"value":2274},{"type":30,"tag":1881,"props":4997,"children":4998},{"class":1883,"line":2277},[4999,5003,5008,5013,5017,5022,5026,5030,5034,5038,5042,5047,5052],{"type":30,"tag":1881,"props":5000,"children":5001},{"style":1937},[5002],{"type":39,"value":2223},{"type":30,"tag":1881,"props":5004,"children":5005},{"style":2226},[5006],{"type":39,"value":5007}," (slot ",{"type":30,"tag":1881,"props":5009,"children":5010},{"style":1994},[5011],{"type":39,"value":5012},"==",{"type":30,"tag":1881,"props":5014,"children":5015},{"style":2150},[5016],{"type":39,"value":4530},{"type":30,"tag":1881,"props":5018,"children":5019},{"style":1994},[5020],{"type":39,"value":5021}," ||",{"type":30,"tag":1881,"props":5023,"children":5024},{"style":2226},[5025],{"type":39,"value":4422},{"type":30,"tag":1881,"props":5027,"children":5028},{"style":2308},[5029],{"type":39,"value":205},{"type":30,"tag":1881,"props":5031,"children":5032},{"style":2226},[5033],{"type":39,"value":2479},{"type":30,"tag":1881,"props":5035,"children":5036},{"style":1994},[5037],{"type":39,"value":2484},{"type":30,"tag":1881,"props":5039,"children":5040},{"style":2226},[5041],{"type":39,"value":2489},{"type":30,"tag":1881,"props":5043,"children":5044},{"style":1937},[5045],{"type":39,"value":5046},"return",{"type":30,"tag":1881,"props":5048,"children":5049},{"style":3451},[5050],{"type":39,"value":5051}," false",{"type":30,"tag":1881,"props":5053,"children":5054},{"style":1954},[5055],{"type":39,"value":2274},{"type":30,"tag":1881,"props":5057,"children":5058},{"class":1883,"line":2390},[5059,5063,5068,5072,5076,5080,5084,5089,5093,5098,5102],{"type":30,"tag":1881,"props":5060,"children":5061},{"style":1937},[5062],{"type":39,"value":2283},{"type":30,"tag":1881,"props":5064,"children":5065},{"style":2286},[5066],{"type":39,"value":5067}," activeHolds",{"type":30,"tag":1881,"props":5069,"children":5070},{"style":1994},[5071],{"type":39,"value":2294},{"type":30,"tag":1881,"props":5073,"children":5074},{"style":1937},[5075],{"type":39,"value":2299},{"type":30,"tag":1881,"props":5077,"children":5078},{"style":2302},[5079],{"type":39,"value":2305},{"type":30,"tag":1881,"props":5081,"children":5082},{"style":2308},[5083],{"type":39,"value":205},{"type":30,"tag":1881,"props":5085,"children":5086},{"style":2226},[5087],{"type":39,"value":5088},"slotHoldRepo",{"type":30,"tag":1881,"props":5090,"children":5091},{"style":2308},[5092],{"type":39,"value":205},{"type":30,"tag":1881,"props":5094,"children":5095},{"style":1921},[5096],{"type":39,"value":5097},"countActiveHolds",{"type":30,"tag":1881,"props":5099,"children":5100},{"style":2226},[5101],{"type":39,"value":4991},{"type":30,"tag":1881,"props":5103,"children":5104},{"style":1954},[5105],{"type":39,"value":2274},{"type":30,"tag":1881,"props":5107,"children":5108},{"class":1883,"line":2460},[5109,5113,5118,5122,5126],{"type":30,"tag":1881,"props":5110,"children":5111},{"style":1937},[5112],{"type":39,"value":3918},{"type":30,"tag":1881,"props":5114,"children":5115},{"style":2226},[5116],{"type":39,"value":5117}," activeHolds ",{"type":30,"tag":1881,"props":5119,"children":5120},{"style":1994},[5121],{"type":39,"value":2545},{"type":30,"tag":1881,"props":5123,"children":5124},{"style":3451},[5125],{"type":39,"value":4574},{"type":30,"tag":1881,"props":5127,"children":5128},{"style":1954},[5129],{"type":39,"value":2274},{"type":30,"tag":1881,"props":5131,"children":5132},{"class":1883,"line":2522},[5133],{"type":30,"tag":1881,"props":5134,"children":5135},{"style":1954},[5136],{"type":39,"value":3950},{"type":30,"tag":1881,"props":5138,"children":5139},{"class":1883,"line":2588},[5140],{"type":30,"tag":1881,"props":5141,"children":5142},{"style":1954},[5143],{"type":39,"value":3959},{"type":30,"tag":31,"props":5145,"children":5146},{},[5147],{"type":39,"value":5148},"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":30,"tag":55,"props":5150,"children":5151},{},[],{"type":30,"tag":59,"props":5153,"children":5155},{"id":5154},"pattern-3-tests-qui-ne-testent-rien",[5156],{"type":39,"value":5157},"Pattern #3 : tests qui ne testent rien",{"type":30,"tag":31,"props":5159,"children":5160},{},[5161,5163,5169,5171,5177],{"type":39,"value":5162},"Celui-là me fait grincer des dents à chaque fois. Claude génère des tests qui ont l'air sérieux, avec des ",{"type":30,"tag":262,"props":5164,"children":5166},{"className":5165},[],[5167],{"type":39,"value":5168},"describe",{"type":39,"value":5170},", des ",{"type":30,"tag":262,"props":5172,"children":5174},{"className":5173},[],[5175],{"type":39,"value":5176},"vi.fn()",{"type":39,"value":5178},", des assertions, et qui ne testent en réalité aucun comportement métier. Exemple typique sur crmcoaching :",{"type":30,"tag":1871,"props":5180,"children":5182},{"className":1873,"code":5181,"language":1875,"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",[5183],{"type":30,"tag":262,"props":5184,"children":5185},{"__ignoreMap":8},[5186,5194,5202,5209,5243,5281,5371,5419,5426,5514,5521,5556,5605,5623,5639],{"type":30,"tag":1881,"props":5187,"children":5188},{"class":1883,"line":1884},[5189],{"type":30,"tag":1881,"props":5190,"children":5191},{"style":1888},[5192],{"type":39,"value":5193},"// apps/api/src/application/use-cases/__tests__/create-mentoring-checkout-intent.test.ts\n",{"type":30,"tag":1881,"props":5195,"children":5196},{"class":1883,"line":955},[5197],{"type":30,"tag":1881,"props":5198,"children":5199},{"style":1888},[5200],{"type":39,"value":5201},"// Test généré par Claude sans prompt de comportement\n",{"type":30,"tag":1881,"props":5203,"children":5204},{"class":1883,"line":1902},[5205],{"type":30,"tag":1881,"props":5206,"children":5207},{"emptyLinePlaceholder":13},[5208],{"type":39,"value":1908},{"type":30,"tag":1881,"props":5210,"children":5211},{"class":1883,"line":1911},[5212,5216,5220,5225,5229,5234,5239],{"type":30,"tag":1881,"props":5213,"children":5214},{"style":1921},[5215],{"type":39,"value":5168},{"type":30,"tag":1881,"props":5217,"children":5218},{"style":2226},[5219],{"type":39,"value":2138},{"type":30,"tag":1881,"props":5221,"children":5222},{"style":2262},[5223],{"type":39,"value":5224},"'CreateMentoringCheckoutIntentUseCase'",{"type":30,"tag":1881,"props":5226,"children":5227},{"style":1954},[5228],{"type":39,"value":2158},{"type":30,"tag":1881,"props":5230,"children":5231},{"style":1954},[5232],{"type":39,"value":5233}," ()",{"type":30,"tag":1881,"props":5235,"children":5236},{"style":1994},[5237],{"type":39,"value":5238}," =>",{"type":30,"tag":1881,"props":5240,"children":5241},{"style":1954},[5242],{"type":39,"value":1957},{"type":30,"tag":1881,"props":5244,"children":5245},{"class":1883,"line":1933},[5246,5251,5255,5260,5264,5269,5273,5277],{"type":30,"tag":1881,"props":5247,"children":5248},{"style":1921},[5249],{"type":39,"value":5250},"  it",{"type":30,"tag":1881,"props":5252,"children":5253},{"style":2226},[5254],{"type":39,"value":2138},{"type":30,"tag":1881,"props":5256,"children":5257},{"style":2262},[5258],{"type":39,"value":5259},"'should call repository save'",{"type":30,"tag":1881,"props":5261,"children":5262},{"style":1954},[5263],{"type":39,"value":2158},{"type":30,"tag":1881,"props":5265,"children":5266},{"style":1937},[5267],{"type":39,"value":5268}," async",{"type":30,"tag":1881,"props":5270,"children":5271},{"style":1954},[5272],{"type":39,"value":5233},{"type":30,"tag":1881,"props":5274,"children":5275},{"style":1994},[5276],{"type":39,"value":5238},{"type":30,"tag":1881,"props":5278,"children":5279},{"style":1954},[5280],{"type":39,"value":1957},{"type":30,"tag":1881,"props":5282,"children":5283},{"class":1883,"line":1960},[5284,5288,5293,5297,5301,5306,5310,5315,5319,5324,5328,5332,5337,5341,5345,5349,5353,5358,5362,5366],{"type":30,"tag":1881,"props":5285,"children":5286},{"style":1937},[5287],{"type":39,"value":2283},{"type":30,"tag":1881,"props":5289,"children":5290},{"style":2286},[5291],{"type":39,"value":5292}," repo",{"type":30,"tag":1881,"props":5294,"children":5295},{"style":1994},[5296],{"type":39,"value":2294},{"type":30,"tag":1881,"props":5298,"children":5299},{"style":1954},[5300],{"type":39,"value":2355},{"type":30,"tag":1881,"props":5302,"children":5303},{"style":2226},[5304],{"type":39,"value":5305}," save",{"type":30,"tag":1881,"props":5307,"children":5308},{"style":2308},[5309],{"type":39,"value":1997},{"type":30,"tag":1881,"props":5311,"children":5312},{"style":2226},[5313],{"type":39,"value":5314}," vi",{"type":30,"tag":1881,"props":5316,"children":5317},{"style":2308},[5318],{"type":39,"value":205},{"type":30,"tag":1881,"props":5320,"children":5321},{"style":1921},[5322],{"type":39,"value":5323},"fn",{"type":30,"tag":1881,"props":5325,"children":5326},{"style":2226},[5327],{"type":39,"value":3214},{"type":30,"tag":1881,"props":5329,"children":5330},{"style":2308},[5331],{"type":39,"value":205},{"type":30,"tag":1881,"props":5333,"children":5334},{"style":1921},[5335],{"type":39,"value":5336},"mockResolvedValue",{"type":30,"tag":1881,"props":5338,"children":5339},{"style":2226},[5340],{"type":39,"value":2138},{"type":30,"tag":1881,"props":5342,"children":5343},{"style":1954},[5344],{"type":39,"value":2341},{"type":30,"tag":1881,"props":5346,"children":5347},{"style":2226},[5348],{"type":39,"value":2360},{"type":30,"tag":1881,"props":5350,"children":5351},{"style":2308},[5352],{"type":39,"value":1997},{"type":30,"tag":1881,"props":5354,"children":5355},{"style":2262},[5356],{"type":39,"value":5357}," 'intent-1'",{"type":30,"tag":1881,"props":5359,"children":5360},{"style":1954},[5361],{"type":39,"value":2379},{"type":30,"tag":1881,"props":5363,"children":5364},{"style":2226},[5365],{"type":39,"value":2555},{"type":30,"tag":1881,"props":5367,"children":5368},{"style":1954},[5369],{"type":39,"value":5370},"};\n",{"type":30,"tag":1881,"props":5372,"children":5373},{"class":1883,"line":1974},[5374,5378,5383,5387,5391,5396,5401,5406,5411,5415],{"type":30,"tag":1881,"props":5375,"children":5376},{"style":1937},[5377],{"type":39,"value":2283},{"type":30,"tag":1881,"props":5379,"children":5380},{"style":2286},[5381],{"type":39,"value":5382}," useCase",{"type":30,"tag":1881,"props":5384,"children":5385},{"style":1994},[5386],{"type":39,"value":2294},{"type":30,"tag":1881,"props":5388,"children":5389},{"style":2247},[5390],{"type":39,"value":2250},{"type":30,"tag":1881,"props":5392,"children":5393},{"style":1921},[5394],{"type":39,"value":5395}," CreateMentoringCheckoutIntentUseCase",{"type":30,"tag":1881,"props":5397,"children":5398},{"style":2226},[5399],{"type":39,"value":5400},"(repo ",{"type":30,"tag":1881,"props":5402,"children":5403},{"style":1937},[5404],{"type":39,"value":5405},"as",{"type":30,"tag":1881,"props":5407,"children":5408},{"style":2150},[5409],{"type":39,"value":5410}," any",{"type":30,"tag":1881,"props":5412,"children":5413},{"style":2226},[5414],{"type":39,"value":2176},{"type":30,"tag":1881,"props":5416,"children":5417},{"style":1954},[5418],{"type":39,"value":2274},{"type":30,"tag":1881,"props":5420,"children":5421},{"class":1883,"line":2010},[5422],{"type":30,"tag":1881,"props":5423,"children":5424},{"emptyLinePlaceholder":13},[5425],{"type":39,"value":1908},{"type":30,"tag":1881,"props":5427,"children":5428},{"class":1883,"line":2040},[5429,5433,5437,5441,5446,5450,5454,5458,5462,5467,5471,5475,5479,5484,5488,5493,5497,5502,5506,5510],{"type":30,"tag":1881,"props":5430,"children":5431},{"style":1937},[5432],{"type":39,"value":3089},{"type":30,"tag":1881,"props":5434,"children":5435},{"style":2226},[5436],{"type":39,"value":5382},{"type":30,"tag":1881,"props":5438,"children":5439},{"style":2308},[5440],{"type":39,"value":205},{"type":30,"tag":1881,"props":5442,"children":5443},{"style":1921},[5444],{"type":39,"value":5445},"execute",{"type":30,"tag":1881,"props":5447,"children":5448},{"style":2226},[5449],{"type":39,"value":2138},{"type":30,"tag":1881,"props":5451,"children":5452},{"style":1954},[5453],{"type":39,"value":2341},{"type":30,"tag":1881,"props":5455,"children":5456},{"style":2226},[5457],{"type":39,"value":2163},{"type":30,"tag":1881,"props":5459,"children":5460},{"style":2308},[5461],{"type":39,"value":1997},{"type":30,"tag":1881,"props":5463,"children":5464},{"style":2262},[5465],{"type":39,"value":5466}," 'c1'",{"type":30,"tag":1881,"props":5468,"children":5469},{"style":1954},[5470],{"type":39,"value":2158},{"type":30,"tag":1881,"props":5472,"children":5473},{"style":2226},[5474],{"type":39,"value":3866},{"type":30,"tag":1881,"props":5476,"children":5477},{"style":2308},[5478],{"type":39,"value":1997},{"type":30,"tag":1881,"props":5480,"children":5481},{"style":2262},[5482],{"type":39,"value":5483}," 'cl1'",{"type":30,"tag":1881,"props":5485,"children":5486},{"style":1954},[5487],{"type":39,"value":2158},{"type":30,"tag":1881,"props":5489,"children":5490},{"style":2226},[5491],{"type":39,"value":5492}," offreId",{"type":30,"tag":1881,"props":5494,"children":5495},{"style":2308},[5496],{"type":39,"value":1997},{"type":30,"tag":1881,"props":5498,"children":5499},{"style":2262},[5500],{"type":39,"value":5501}," 'o1'",{"type":30,"tag":1881,"props":5503,"children":5504},{"style":1954},[5505],{"type":39,"value":2379},{"type":30,"tag":1881,"props":5507,"children":5508},{"style":2226},[5509],{"type":39,"value":2176},{"type":30,"tag":1881,"props":5511,"children":5512},{"style":1954},[5513],{"type":39,"value":2274},{"type":30,"tag":1881,"props":5515,"children":5516},{"class":1883,"line":2070},[5517],{"type":30,"tag":1881,"props":5518,"children":5519},{"emptyLinePlaceholder":13},[5520],{"type":39,"value":1908},{"type":30,"tag":1881,"props":5522,"children":5523},{"class":1883,"line":2100},[5524,5529,5534,5538,5543,5547,5552],{"type":30,"tag":1881,"props":5525,"children":5526},{"style":1921},[5527],{"type":39,"value":5528},"    expect",{"type":30,"tag":1881,"props":5530,"children":5531},{"style":2226},[5532],{"type":39,"value":5533},"(repo",{"type":30,"tag":1881,"props":5535,"children":5536},{"style":2308},[5537],{"type":39,"value":205},{"type":30,"tag":1881,"props":5539,"children":5540},{"style":2226},[5541],{"type":39,"value":5542},"save)",{"type":30,"tag":1881,"props":5544,"children":5545},{"style":2308},[5546],{"type":39,"value":205},{"type":30,"tag":1881,"props":5548,"children":5549},{"style":1921},[5550],{"type":39,"value":5551},"toHaveBeenCalledWith",{"type":30,"tag":1881,"props":5553,"children":5554},{"style":2226},[5555],{"type":39,"value":1971},{"type":30,"tag":1881,"props":5557,"children":5558},{"class":1883,"line":2114},[5559,5564,5568,5573,5577,5581,5585,5589,5593,5597,5601],{"type":30,"tag":1881,"props":5560,"children":5561},{"style":2226},[5562],{"type":39,"value":5563},"      expect",{"type":30,"tag":1881,"props":5565,"children":5566},{"style":2308},[5567],{"type":39,"value":205},{"type":30,"tag":1881,"props":5569,"children":5570},{"style":1921},[5571],{"type":39,"value":5572},"objectContaining",{"type":30,"tag":1881,"props":5574,"children":5575},{"style":2226},[5576],{"type":39,"value":2138},{"type":30,"tag":1881,"props":5578,"children":5579},{"style":1954},[5580],{"type":39,"value":2341},{"type":30,"tag":1881,"props":5582,"children":5583},{"style":2226},[5584],{"type":39,"value":2163},{"type":30,"tag":1881,"props":5586,"children":5587},{"style":2308},[5588],{"type":39,"value":1997},{"type":30,"tag":1881,"props":5590,"children":5591},{"style":2262},[5592],{"type":39,"value":5466},{"type":30,"tag":1881,"props":5594,"children":5595},{"style":1954},[5596],{"type":39,"value":2379},{"type":30,"tag":1881,"props":5598,"children":5599},{"style":2226},[5600],{"type":39,"value":2176},{"type":30,"tag":1881,"props":5602,"children":5603},{"style":1954},[5604],{"type":39,"value":2007},{"type":30,"tag":1881,"props":5606,"children":5607},{"class":1883,"line":2122},[5608,5613,5618],{"type":30,"tag":1881,"props":5609,"children":5610},{"style":2226},[5611],{"type":39,"value":5612},"    )",{"type":30,"tag":1881,"props":5614,"children":5615},{"style":1954},[5616],{"type":39,"value":5617},";",{"type":30,"tag":1881,"props":5619,"children":5620},{"style":1888},[5621],{"type":39,"value":5622}," // vérifie un appel, pas un comportement\n",{"type":30,"tag":1881,"props":5624,"children":5625},{"class":1883,"line":2208},[5626,5631,5635],{"type":30,"tag":1881,"props":5627,"children":5628},{"style":1954},[5629],{"type":39,"value":5630},"  }",{"type":30,"tag":1881,"props":5632,"children":5633},{"style":2226},[5634],{"type":39,"value":2176},{"type":30,"tag":1881,"props":5636,"children":5637},{"style":1954},[5638],{"type":39,"value":2274},{"type":30,"tag":1881,"props":5640,"children":5641},{"class":1883,"line":2217},[5642,5646,5650],{"type":30,"tag":1881,"props":5643,"children":5644},{"style":1954},[5645],{"type":39,"value":2374},{"type":30,"tag":1881,"props":5647,"children":5648},{"style":2226},[5649],{"type":39,"value":2176},{"type":30,"tag":1881,"props":5651,"children":5652},{"style":1954},[5653],{"type":39,"value":2274},{"type":30,"tag":31,"props":5655,"children":5656},{},[5657],{"type":39,"value":5658},"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":30,"tag":31,"props":5660,"children":5661},{},[5662,5664,5669],{"type":39,"value":5663},"Le contre-pattern, c'est ce que Dan North appelait ",{"type":30,"tag":42,"props":5665,"children":5666},{},[5667],{"type":39,"value":5668},"\"Tests as Specifications\"",{"type":39,"value":5670}," dans ses articles BDD fondateurs de 2006. Le test décrit un comportement observable :",{"type":30,"tag":1871,"props":5672,"children":5674},{"className":1873,"code":5673,"language":1875,"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",[5675],{"type":30,"tag":262,"props":5676,"children":5677},{"__ignoreMap":8},[5678,5709,5774,5782,5871,5903,5937,5977,5984,5992,6088,6095,6103,6150,6195,6240,6255],{"type":30,"tag":1881,"props":5679,"children":5680},{"class":1883,"line":1884},[5681,5685,5689,5693,5697,5701,5705],{"type":30,"tag":1881,"props":5682,"children":5683},{"style":1921},[5684],{"type":39,"value":5168},{"type":30,"tag":1881,"props":5686,"children":5687},{"style":2226},[5688],{"type":39,"value":2138},{"type":30,"tag":1881,"props":5690,"children":5691},{"style":2262},[5692],{"type":39,"value":5224},{"type":30,"tag":1881,"props":5694,"children":5695},{"style":1954},[5696],{"type":39,"value":2158},{"type":30,"tag":1881,"props":5698,"children":5699},{"style":1954},[5700],{"type":39,"value":5233},{"type":30,"tag":1881,"props":5702,"children":5703},{"style":1994},[5704],{"type":39,"value":5238},{"type":30,"tag":1881,"props":5706,"children":5707},{"style":1954},[5708],{"type":39,"value":1957},{"type":30,"tag":1881,"props":5710,"children":5711},{"class":1883,"line":955},[5712,5716,5720,5725,5731,5736,5740,5745,5749,5754,5758,5762,5766,5770],{"type":30,"tag":1881,"props":5713,"children":5714},{"style":1921},[5715],{"type":39,"value":5250},{"type":30,"tag":1881,"props":5717,"children":5718},{"style":2226},[5719],{"type":39,"value":2138},{"type":30,"tag":1881,"props":5721,"children":5722},{"style":2262},[5723],{"type":39,"value":5724},"'étant donné une offre active, quand on crée l",{"type":30,"tag":1881,"props":5726,"children":5728},{"style":5727},"--shiki-default:#F4B8E4;--shiki-dark:#79B8FF",[5729],{"type":39,"value":5730},"\\'",{"type":30,"tag":1881,"props":5732,"children":5733},{"style":2262},[5734],{"type":39,"value":5735},"intent, alors l",{"type":30,"tag":1881,"props":5737,"children":5738},{"style":5727},[5739],{"type":39,"value":5730},{"type":30,"tag":1881,"props":5741,"children":5742},{"style":2262},[5743],{"type":39,"value":5744},"intent contient le prix de l",{"type":30,"tag":1881,"props":5746,"children":5747},{"style":5727},[5748],{"type":39,"value":5730},{"type":30,"tag":1881,"props":5750,"children":5751},{"style":2262},[5752],{"type":39,"value":5753},"offre'",{"type":30,"tag":1881,"props":5755,"children":5756},{"style":1954},[5757],{"type":39,"value":2158},{"type":30,"tag":1881,"props":5759,"children":5760},{"style":1937},[5761],{"type":39,"value":5268},{"type":30,"tag":1881,"props":5763,"children":5764},{"style":1954},[5765],{"type":39,"value":5233},{"type":30,"tag":1881,"props":5767,"children":5768},{"style":1994},[5769],{"type":39,"value":5238},{"type":30,"tag":1881,"props":5771,"children":5772},{"style":1954},[5773],{"type":39,"value":1957},{"type":30,"tag":1881,"props":5775,"children":5776},{"class":1883,"line":1902},[5777],{"type":30,"tag":1881,"props":5778,"children":5779},{"style":1888},[5780],{"type":39,"value":5781},"    // Given\n",{"type":30,"tag":1881,"props":5783,"children":5784},{"class":1883,"line":1911},[5785,5789,5794,5798,5802,5806,5810,5814,5818,5823,5827,5832,5836,5841,5845,5850,5854,5858,5862,5866],{"type":30,"tag":1881,"props":5786,"children":5787},{"style":1937},[5788],{"type":39,"value":2283},{"type":30,"tag":1881,"props":5790,"children":5791},{"style":2286},[5792],{"type":39,"value":5793}," offre",{"type":30,"tag":1881,"props":5795,"children":5796},{"style":1994},[5797],{"type":39,"value":2294},{"type":30,"tag":1881,"props":5799,"children":5800},{"style":1954},[5801],{"type":39,"value":2355},{"type":30,"tag":1881,"props":5803,"children":5804},{"style":2226},[5805],{"type":39,"value":2360},{"type":30,"tag":1881,"props":5807,"children":5808},{"style":2308},[5809],{"type":39,"value":1997},{"type":30,"tag":1881,"props":5811,"children":5812},{"style":2262},[5813],{"type":39,"value":5501},{"type":30,"tag":1881,"props":5815,"children":5816},{"style":1954},[5817],{"type":39,"value":2158},{"type":30,"tag":1881,"props":5819,"children":5820},{"style":2226},[5821],{"type":39,"value":5822}," price",{"type":30,"tag":1881,"props":5824,"children":5825},{"style":2308},[5826],{"type":39,"value":1997},{"type":30,"tag":1881,"props":5828,"children":5829},{"style":3451},[5830],{"type":39,"value":5831}," 150",{"type":30,"tag":1881,"props":5833,"children":5834},{"style":1954},[5835],{"type":39,"value":2158},{"type":30,"tag":1881,"props":5837,"children":5838},{"style":2226},[5839],{"type":39,"value":5840}," currency",{"type":30,"tag":1881,"props":5842,"children":5843},{"style":2308},[5844],{"type":39,"value":1997},{"type":30,"tag":1881,"props":5846,"children":5847},{"style":2262},[5848],{"type":39,"value":5849}," 'EUR'",{"type":30,"tag":1881,"props":5851,"children":5852},{"style":1954},[5853],{"type":39,"value":2158},{"type":30,"tag":1881,"props":5855,"children":5856},{"style":2226},[5857],{"type":39,"value":3179},{"type":30,"tag":1881,"props":5859,"children":5860},{"style":2308},[5861],{"type":39,"value":1997},{"type":30,"tag":1881,"props":5863,"children":5864},{"style":2262},[5865],{"type":39,"value":3008},{"type":30,"tag":1881,"props":5867,"children":5868},{"style":1954},[5869],{"type":39,"value":5870}," };\n",{"type":30,"tag":1881,"props":5872,"children":5873},{"class":1883,"line":1933},[5874,5878,5882,5886,5890,5895,5899],{"type":30,"tag":1881,"props":5875,"children":5876},{"style":1937},[5877],{"type":39,"value":2283},{"type":30,"tag":1881,"props":5879,"children":5880},{"style":2286},[5881],{"type":39,"value":5292},{"type":30,"tag":1881,"props":5883,"children":5884},{"style":1994},[5885],{"type":39,"value":2294},{"type":30,"tag":1881,"props":5887,"children":5888},{"style":2247},[5889],{"type":39,"value":2250},{"type":30,"tag":1881,"props":5891,"children":5892},{"style":1921},[5893],{"type":39,"value":5894}," InMemoryCheckoutIntentRepository",{"type":30,"tag":1881,"props":5896,"children":5897},{"style":2226},[5898],{"type":39,"value":3214},{"type":30,"tag":1881,"props":5900,"children":5901},{"style":1954},[5902],{"type":39,"value":2274},{"type":30,"tag":1881,"props":5904,"children":5905},{"class":1883,"line":1960},[5906,5910,5915,5919,5923,5928,5933],{"type":30,"tag":1881,"props":5907,"children":5908},{"style":1937},[5909],{"type":39,"value":2283},{"type":30,"tag":1881,"props":5911,"children":5912},{"style":2286},[5913],{"type":39,"value":5914}," offreRepo",{"type":30,"tag":1881,"props":5916,"children":5917},{"style":1994},[5918],{"type":39,"value":2294},{"type":30,"tag":1881,"props":5920,"children":5921},{"style":2247},[5922],{"type":39,"value":2250},{"type":30,"tag":1881,"props":5924,"children":5925},{"style":1921},[5926],{"type":39,"value":5927}," InMemoryOffreRepository",{"type":30,"tag":1881,"props":5929,"children":5930},{"style":2226},[5931],{"type":39,"value":5932},"([offre])",{"type":30,"tag":1881,"props":5934,"children":5935},{"style":1954},[5936],{"type":39,"value":2274},{"type":30,"tag":1881,"props":5938,"children":5939},{"class":1883,"line":1974},[5940,5944,5948,5952,5956,5960,5964,5968,5973],{"type":30,"tag":1881,"props":5941,"children":5942},{"style":1937},[5943],{"type":39,"value":2283},{"type":30,"tag":1881,"props":5945,"children":5946},{"style":2286},[5947],{"type":39,"value":5382},{"type":30,"tag":1881,"props":5949,"children":5950},{"style":1994},[5951],{"type":39,"value":2294},{"type":30,"tag":1881,"props":5953,"children":5954},{"style":2247},[5955],{"type":39,"value":2250},{"type":30,"tag":1881,"props":5957,"children":5958},{"style":1921},[5959],{"type":39,"value":5395},{"type":30,"tag":1881,"props":5961,"children":5962},{"style":2226},[5963],{"type":39,"value":5533},{"type":30,"tag":1881,"props":5965,"children":5966},{"style":1954},[5967],{"type":39,"value":2158},{"type":30,"tag":1881,"props":5969,"children":5970},{"style":2226},[5971],{"type":39,"value":5972}," offreRepo)",{"type":30,"tag":1881,"props":5974,"children":5975},{"style":1954},[5976],{"type":39,"value":2274},{"type":30,"tag":1881,"props":5978,"children":5979},{"class":1883,"line":2010},[5980],{"type":30,"tag":1881,"props":5981,"children":5982},{"emptyLinePlaceholder":13},[5983],{"type":39,"value":1908},{"type":30,"tag":1881,"props":5985,"children":5986},{"class":1883,"line":2040},[5987],{"type":30,"tag":1881,"props":5988,"children":5989},{"style":1888},[5990],{"type":39,"value":5991},"    // When\n",{"type":30,"tag":1881,"props":5993,"children":5994},{"class":1883,"line":2070},[5995,5999,6004,6008,6012,6016,6020,6024,6028,6032,6036,6040,6044,6048,6052,6056,6060,6064,6068,6072,6076,6080,6084],{"type":30,"tag":1881,"props":5996,"children":5997},{"style":1937},[5998],{"type":39,"value":2283},{"type":30,"tag":1881,"props":6000,"children":6001},{"style":2286},[6002],{"type":39,"value":6003}," result",{"type":30,"tag":1881,"props":6005,"children":6006},{"style":1994},[6007],{"type":39,"value":2294},{"type":30,"tag":1881,"props":6009,"children":6010},{"style":1937},[6011],{"type":39,"value":2299},{"type":30,"tag":1881,"props":6013,"children":6014},{"style":2226},[6015],{"type":39,"value":5382},{"type":30,"tag":1881,"props":6017,"children":6018},{"style":2308},[6019],{"type":39,"value":205},{"type":30,"tag":1881,"props":6021,"children":6022},{"style":1921},[6023],{"type":39,"value":5445},{"type":30,"tag":1881,"props":6025,"children":6026},{"style":2226},[6027],{"type":39,"value":2138},{"type":30,"tag":1881,"props":6029,"children":6030},{"style":1954},[6031],{"type":39,"value":2341},{"type":30,"tag":1881,"props":6033,"children":6034},{"style":2226},[6035],{"type":39,"value":2163},{"type":30,"tag":1881,"props":6037,"children":6038},{"style":2308},[6039],{"type":39,"value":1997},{"type":30,"tag":1881,"props":6041,"children":6042},{"style":2262},[6043],{"type":39,"value":5466},{"type":30,"tag":1881,"props":6045,"children":6046},{"style":1954},[6047],{"type":39,"value":2158},{"type":30,"tag":1881,"props":6049,"children":6050},{"style":2226},[6051],{"type":39,"value":3866},{"type":30,"tag":1881,"props":6053,"children":6054},{"style":2308},[6055],{"type":39,"value":1997},{"type":30,"tag":1881,"props":6057,"children":6058},{"style":2262},[6059],{"type":39,"value":5483},{"type":30,"tag":1881,"props":6061,"children":6062},{"style":1954},[6063],{"type":39,"value":2158},{"type":30,"tag":1881,"props":6065,"children":6066},{"style":2226},[6067],{"type":39,"value":5492},{"type":30,"tag":1881,"props":6069,"children":6070},{"style":2308},[6071],{"type":39,"value":1997},{"type":30,"tag":1881,"props":6073,"children":6074},{"style":2262},[6075],{"type":39,"value":5501},{"type":30,"tag":1881,"props":6077,"children":6078},{"style":1954},[6079],{"type":39,"value":2379},{"type":30,"tag":1881,"props":6081,"children":6082},{"style":2226},[6083],{"type":39,"value":2176},{"type":30,"tag":1881,"props":6085,"children":6086},{"style":1954},[6087],{"type":39,"value":2274},{"type":30,"tag":1881,"props":6089,"children":6090},{"class":1883,"line":2100},[6091],{"type":30,"tag":1881,"props":6092,"children":6093},{"emptyLinePlaceholder":13},[6094],{"type":39,"value":1908},{"type":30,"tag":1881,"props":6096,"children":6097},{"class":1883,"line":2114},[6098],{"type":30,"tag":1881,"props":6099,"children":6100},{"style":1888},[6101],{"type":39,"value":6102},"    // Then\n",{"type":30,"tag":1881,"props":6104,"children":6105},{"class":1883,"line":2122},[6106,6110,6115,6119,6124,6128,6133,6137,6142,6146],{"type":30,"tag":1881,"props":6107,"children":6108},{"style":1921},[6109],{"type":39,"value":5528},{"type":30,"tag":1881,"props":6111,"children":6112},{"style":2226},[6113],{"type":39,"value":6114},"(result",{"type":30,"tag":1881,"props":6116,"children":6117},{"style":2308},[6118],{"type":39,"value":205},{"type":30,"tag":1881,"props":6120,"children":6121},{"style":2226},[6122],{"type":39,"value":6123},"amount)",{"type":30,"tag":1881,"props":6125,"children":6126},{"style":2308},[6127],{"type":39,"value":205},{"type":30,"tag":1881,"props":6129,"children":6130},{"style":1921},[6131],{"type":39,"value":6132},"toBe",{"type":30,"tag":1881,"props":6134,"children":6135},{"style":2226},[6136],{"type":39,"value":2138},{"type":30,"tag":1881,"props":6138,"children":6139},{"style":3451},[6140],{"type":39,"value":6141},"150",{"type":30,"tag":1881,"props":6143,"children":6144},{"style":2226},[6145],{"type":39,"value":2176},{"type":30,"tag":1881,"props":6147,"children":6148},{"style":1954},[6149],{"type":39,"value":2274},{"type":30,"tag":1881,"props":6151,"children":6152},{"class":1883,"line":2208},[6153,6157,6161,6165,6170,6174,6178,6182,6187,6191],{"type":30,"tag":1881,"props":6154,"children":6155},{"style":1921},[6156],{"type":39,"value":5528},{"type":30,"tag":1881,"props":6158,"children":6159},{"style":2226},[6160],{"type":39,"value":6114},{"type":30,"tag":1881,"props":6162,"children":6163},{"style":2308},[6164],{"type":39,"value":205},{"type":30,"tag":1881,"props":6166,"children":6167},{"style":2226},[6168],{"type":39,"value":6169},"currency)",{"type":30,"tag":1881,"props":6171,"children":6172},{"style":2308},[6173],{"type":39,"value":205},{"type":30,"tag":1881,"props":6175,"children":6176},{"style":1921},[6177],{"type":39,"value":6132},{"type":30,"tag":1881,"props":6179,"children":6180},{"style":2226},[6181],{"type":39,"value":2138},{"type":30,"tag":1881,"props":6183,"children":6184},{"style":2262},[6185],{"type":39,"value":6186},"'EUR'",{"type":30,"tag":1881,"props":6188,"children":6189},{"style":2226},[6190],{"type":39,"value":2176},{"type":30,"tag":1881,"props":6192,"children":6193},{"style":1954},[6194],{"type":39,"value":2274},{"type":30,"tag":1881,"props":6196,"children":6197},{"class":1883,"line":2217},[6198,6202,6206,6210,6215,6219,6223,6227,6232,6236],{"type":30,"tag":1881,"props":6199,"children":6200},{"style":1921},[6201],{"type":39,"value":5528},{"type":30,"tag":1881,"props":6203,"children":6204},{"style":2226},[6205],{"type":39,"value":6114},{"type":30,"tag":1881,"props":6207,"children":6208},{"style":2308},[6209],{"type":39,"value":205},{"type":30,"tag":1881,"props":6211,"children":6212},{"style":2226},[6213],{"type":39,"value":6214},"status)",{"type":30,"tag":1881,"props":6216,"children":6217},{"style":2308},[6218],{"type":39,"value":205},{"type":30,"tag":1881,"props":6220,"children":6221},{"style":1921},[6222],{"type":39,"value":6132},{"type":30,"tag":1881,"props":6224,"children":6225},{"style":2226},[6226],{"type":39,"value":2138},{"type":30,"tag":1881,"props":6228,"children":6229},{"style":2262},[6230],{"type":39,"value":6231},"'PENDING'",{"type":30,"tag":1881,"props":6233,"children":6234},{"style":2226},[6235],{"type":39,"value":2176},{"type":30,"tag":1881,"props":6237,"children":6238},{"style":1954},[6239],{"type":39,"value":2274},{"type":30,"tag":1881,"props":6241,"children":6242},{"class":1883,"line":2277},[6243,6247,6251],{"type":30,"tag":1881,"props":6244,"children":6245},{"style":1954},[6246],{"type":39,"value":5630},{"type":30,"tag":1881,"props":6248,"children":6249},{"style":2226},[6250],{"type":39,"value":2176},{"type":30,"tag":1881,"props":6252,"children":6253},{"style":1954},[6254],{"type":39,"value":2274},{"type":30,"tag":1881,"props":6256,"children":6257},{"class":1883,"line":2390},[6258,6262,6266],{"type":30,"tag":1881,"props":6259,"children":6260},{"style":1954},[6261],{"type":39,"value":2374},{"type":30,"tag":1881,"props":6263,"children":6264},{"style":2226},[6265],{"type":39,"value":2176},{"type":30,"tag":1881,"props":6267,"children":6268},{"style":1954},[6269],{"type":39,"value":2274},{"type":30,"tag":31,"props":6271,"children":6272},{},[6273,6275,6279],{"type":39,"value":6274},"L'implémentation peut changer, le test reste valable. C'est exactement la philosophie défendue dans ",{"type":30,"tag":88,"props":6276,"children":6277},{"href":378},[6278],{"type":39,"value":381},{"type":39,"value":6280}," et dans la Definition of Done bien posée.",{"type":30,"tag":31,"props":6282,"children":6283},{},[6284],{"type":39,"value":6285},"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":30,"tag":55,"props":6287,"children":6288},{},[],{"type":30,"tag":59,"props":6290,"children":6292},{"id":6291},"pattern-4-catch-all-silencieux",[6293],{"type":39,"value":6294},"Pattern #4 : catch-all silencieux",{"type":30,"tag":31,"props":6296,"children":6297},{},[6298],{"type":39,"value":6299},"C'est le pattern le plus dangereux, parce qu'il masque les bugs au lieu de les révéler. Claude écrit volontiers :",{"type":30,"tag":1871,"props":6301,"children":6303},{"className":1873,"code":6302,"language":1875,"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",[6304],{"type":30,"tag":262,"props":6305,"children":6306},{"__ignoreMap":8},[6307,6315,6322,6364,6376,6411,6455,6475,6498,6513,6525,6564,6572,6579],{"type":30,"tag":1881,"props":6308,"children":6309},{"class":1883,"line":1884},[6310],{"type":30,"tag":1881,"props":6311,"children":6312},{"style":1888},[6313],{"type":39,"value":6314},"// apps/api/src/infrastructure/adapters/brevo-notification.adapter.ts\n",{"type":30,"tag":1881,"props":6316,"children":6317},{"class":1883,"line":955},[6318],{"type":30,"tag":1881,"props":6319,"children":6320},{"emptyLinePlaceholder":13},[6321],{"type":39,"value":1908},{"type":30,"tag":1881,"props":6323,"children":6324},{"class":1883,"line":1902},[6325,6330,6335,6340,6344,6349,6355,6360],{"type":30,"tag":1881,"props":6326,"children":6327},{"style":2226},[6328],{"type":39,"value":6329},"async ",{"type":30,"tag":1881,"props":6331,"children":6332},{"style":1921},[6333],{"type":39,"value":6334},"sendSlotConfirmation",{"type":30,"tag":1881,"props":6336,"children":6337},{"style":2226},[6338],{"type":39,"value":6339},"(clientEmail: string",{"type":30,"tag":1881,"props":6341,"children":6342},{"style":1954},[6343],{"type":39,"value":2158},{"type":30,"tag":1881,"props":6345,"children":6346},{"style":2226},[6347],{"type":39,"value":6348}," slotId: string): ",{"type":30,"tag":1881,"props":6350,"children":6352},{"style":6351},"--shiki-default:#E5C890;--shiki-default-font-style:italic;--shiki-dark:#79B8FF;--shiki-dark-font-style:inherit",[6353],{"type":39,"value":6354},"Promise",{"type":30,"tag":1881,"props":6356,"children":6357},{"style":1994},[6358],{"type":39,"value":6359},"\u003Cvoid>",{"type":30,"tag":1881,"props":6361,"children":6362},{"style":1954},[6363],{"type":39,"value":1957},{"type":30,"tag":1881,"props":6365,"children":6366},{"class":1883,"line":1911},[6367,6372],{"type":30,"tag":1881,"props":6368,"children":6369},{"style":2226},[6370],{"type":39,"value":6371},"  try ",{"type":30,"tag":1881,"props":6373,"children":6374},{"style":1954},[6375],{"type":39,"value":2645},{"type":30,"tag":1881,"props":6377,"children":6378},{"class":1883,"line":1933},[6379,6383,6387,6391,6395,6399,6403,6407],{"type":30,"tag":1881,"props":6380,"children":6381},{"style":1937},[6382],{"type":39,"value":3089},{"type":30,"tag":1881,"props":6384,"children":6385},{"style":2302},[6386],{"type":39,"value":2305},{"type":30,"tag":1881,"props":6388,"children":6389},{"style":2308},[6390],{"type":39,"value":205},{"type":30,"tag":1881,"props":6392,"children":6393},{"style":2226},[6394],{"type":39,"value":3298},{"type":30,"tag":1881,"props":6396,"children":6397},{"style":2308},[6398],{"type":39,"value":205},{"type":30,"tag":1881,"props":6400,"children":6401},{"style":1921},[6402],{"type":39,"value":3307},{"type":30,"tag":1881,"props":6404,"children":6405},{"style":2226},[6406],{"type":39,"value":2138},{"type":30,"tag":1881,"props":6408,"children":6409},{"style":1954},[6410],{"type":39,"value":2645},{"type":30,"tag":1881,"props":6412,"children":6413},{"class":1883,"line":1960},[6414,6418,6422,6426,6430,6434,6438,6443,6447,6451],{"type":30,"tag":1881,"props":6415,"children":6416},{"style":2226},[6417],{"type":39,"value":3324},{"type":30,"tag":1881,"props":6419,"children":6420},{"style":2308},[6421],{"type":39,"value":1997},{"type":30,"tag":1881,"props":6423,"children":6424},{"style":2226},[6425],{"type":39,"value":3333},{"type":30,"tag":1881,"props":6427,"children":6428},{"style":1954},[6429],{"type":39,"value":2341},{"type":30,"tag":1881,"props":6431,"children":6432},{"style":2226},[6433],{"type":39,"value":2667},{"type":30,"tag":1881,"props":6435,"children":6436},{"style":2308},[6437],{"type":39,"value":1997},{"type":30,"tag":1881,"props":6439,"children":6440},{"style":2226},[6441],{"type":39,"value":6442}," clientEmail ",{"type":30,"tag":1881,"props":6444,"children":6445},{"style":1954},[6446],{"type":39,"value":2374},{"type":30,"tag":1881,"props":6448,"children":6449},{"style":2226},[6450],{"type":39,"value":3431},{"type":30,"tag":1881,"props":6452,"children":6453},{"style":1954},[6454],{"type":39,"value":2007},{"type":30,"tag":1881,"props":6456,"children":6457},{"class":1883,"line":1974},[6458,6462,6466,6471],{"type":30,"tag":1881,"props":6459,"children":6460},{"style":2226},[6461],{"type":39,"value":3444},{"type":30,"tag":1881,"props":6463,"children":6464},{"style":2308},[6465],{"type":39,"value":1997},{"type":30,"tag":1881,"props":6467,"children":6468},{"style":3451},[6469],{"type":39,"value":6470}," 12",{"type":30,"tag":1881,"props":6472,"children":6473},{"style":1954},[6474],{"type":39,"value":2007},{"type":30,"tag":1881,"props":6476,"children":6477},{"class":1883,"line":2010},[6478,6482,6486,6490,6494],{"type":30,"tag":1881,"props":6479,"children":6480},{"style":2226},[6481],{"type":39,"value":3467},{"type":30,"tag":1881,"props":6483,"children":6484},{"style":2308},[6485],{"type":39,"value":1997},{"type":30,"tag":1881,"props":6487,"children":6488},{"style":1954},[6489],{"type":39,"value":2355},{"type":30,"tag":1881,"props":6491,"children":6492},{"style":2226},[6493],{"type":39,"value":4492},{"type":30,"tag":1881,"props":6495,"children":6496},{"style":1954},[6497],{"type":39,"value":2698},{"type":30,"tag":1881,"props":6499,"children":6500},{"class":1883,"line":2040},[6501,6505,6509],{"type":30,"tag":1881,"props":6502,"children":6503},{"style":1954},[6504],{"type":39,"value":2707},{"type":30,"tag":1881,"props":6506,"children":6507},{"style":2226},[6508],{"type":39,"value":2176},{"type":30,"tag":1881,"props":6510,"children":6511},{"style":1954},[6512],{"type":39,"value":2274},{"type":30,"tag":1881,"props":6514,"children":6515},{"class":1883,"line":2070},[6516,6520],{"type":30,"tag":1881,"props":6517,"children":6518},{"style":1954},[6519],{"type":39,"value":5630},{"type":30,"tag":1881,"props":6521,"children":6522},{"style":2226},[6523],{"type":39,"value":6524}," catch (e) {\n",{"type":30,"tag":1881,"props":6526,"children":6527},{"class":1883,"line":2100},[6528,6533,6538,6542,6547,6551,6556,6560],{"type":30,"tag":1881,"props":6529,"children":6530},{"style":2226},[6531],{"type":39,"value":6532},"    console.",{"type":30,"tag":1881,"props":6534,"children":6535},{"style":1921},[6536],{"type":39,"value":6537},"error",{"type":30,"tag":1881,"props":6539,"children":6540},{"style":1954},[6541],{"type":39,"value":2138},{"type":30,"tag":1881,"props":6543,"children":6544},{"style":2262},[6545],{"type":39,"value":6546},"'notification failed'",{"type":30,"tag":1881,"props":6548,"children":6549},{"style":1954},[6550],{"type":39,"value":2158},{"type":30,"tag":1881,"props":6552,"children":6553},{"style":1988},[6554],{"type":39,"value":6555}," e",{"type":30,"tag":1881,"props":6557,"children":6558},{"style":1954},[6559],{"type":39,"value":2176},{"type":30,"tag":1881,"props":6561,"children":6562},{"style":2226},[6563],{"type":39,"value":2274},{"type":30,"tag":1881,"props":6565,"children":6566},{"class":1883,"line":2114},[6567],{"type":30,"tag":1881,"props":6568,"children":6569},{"style":1888},[6570],{"type":39,"value":6571},"    // la suite s'exécute comme si tout allait bien\n",{"type":30,"tag":1881,"props":6573,"children":6574},{"class":1883,"line":2122},[6575],{"type":30,"tag":1881,"props":6576,"children":6577},{"style":1954},[6578],{"type":39,"value":3950},{"type":30,"tag":1881,"props":6580,"children":6581},{"class":1883,"line":2208},[6582],{"type":30,"tag":1881,"props":6583,"children":6584},{"style":2226},[6585],{"type":39,"value":3959},{"type":30,"tag":31,"props":6587,"children":6588},{},[6589,6591,6597],{"type":39,"value":6590},"Et la suite du code continue normalement. Le slot a-t-il été confirmé par email ? On ne sait pas. Le ",{"type":30,"tag":262,"props":6592,"children":6594},{"className":6593},[],[6595],{"type":39,"value":6596},"console.error",{"type":39,"value":6598}," 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":30,"tag":31,"props":6600,"children":6601},{},[6602,6604,6610,6612,6618],{"type":39,"value":6603},"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":30,"tag":262,"props":6605,"children":6607},{"className":6606},[],[6608],{"type":39,"value":6609},"catch (e)",{"type":39,"value":6611}," générique sans typer l'exception attendue : une erreur réseau Brevo ne se traite pas comme une ",{"type":30,"tag":262,"props":6613,"children":6615},{"className":6614},[],[6616],{"type":39,"value":6617},"DomainException",{"type":39,"value":6619},". Enfin, instrumenter chaque catch avec une métrique ou une alerte :",{"type":30,"tag":1871,"props":6621,"children":6623},{"className":1873,"code":6622,"language":1875,"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",[6624],{"type":30,"tag":262,"props":6625,"children":6626},{"__ignoreMap":8},[6627,6662,6673,6708,6751,6770,6793,6808,6820,6849,6861,6873,6938,6950,6995,7042,7049],{"type":30,"tag":1881,"props":6628,"children":6629},{"class":1883,"line":1884},[6630,6634,6638,6642,6646,6650,6654,6658],{"type":30,"tag":1881,"props":6631,"children":6632},{"style":2226},[6633],{"type":39,"value":6329},{"type":30,"tag":1881,"props":6635,"children":6636},{"style":1921},[6637],{"type":39,"value":6334},{"type":30,"tag":1881,"props":6639,"children":6640},{"style":2226},[6641],{"type":39,"value":6339},{"type":30,"tag":1881,"props":6643,"children":6644},{"style":1954},[6645],{"type":39,"value":2158},{"type":30,"tag":1881,"props":6647,"children":6648},{"style":2226},[6649],{"type":39,"value":6348},{"type":30,"tag":1881,"props":6651,"children":6652},{"style":6351},[6653],{"type":39,"value":6354},{"type":30,"tag":1881,"props":6655,"children":6656},{"style":1994},[6657],{"type":39,"value":6359},{"type":30,"tag":1881,"props":6659,"children":6660},{"style":1954},[6661],{"type":39,"value":1957},{"type":30,"tag":1881,"props":6663,"children":6664},{"class":1883,"line":955},[6665,6669],{"type":30,"tag":1881,"props":6666,"children":6667},{"style":2226},[6668],{"type":39,"value":6371},{"type":30,"tag":1881,"props":6670,"children":6671},{"style":1954},[6672],{"type":39,"value":2645},{"type":30,"tag":1881,"props":6674,"children":6675},{"class":1883,"line":1902},[6676,6680,6684,6688,6692,6696,6700,6704],{"type":30,"tag":1881,"props":6677,"children":6678},{"style":1937},[6679],{"type":39,"value":3089},{"type":30,"tag":1881,"props":6681,"children":6682},{"style":2302},[6683],{"type":39,"value":2305},{"type":30,"tag":1881,"props":6685,"children":6686},{"style":2308},[6687],{"type":39,"value":205},{"type":30,"tag":1881,"props":6689,"children":6690},{"style":2226},[6691],{"type":39,"value":3298},{"type":30,"tag":1881,"props":6693,"children":6694},{"style":2308},[6695],{"type":39,"value":205},{"type":30,"tag":1881,"props":6697,"children":6698},{"style":1921},[6699],{"type":39,"value":3307},{"type":30,"tag":1881,"props":6701,"children":6702},{"style":2226},[6703],{"type":39,"value":2138},{"type":30,"tag":1881,"props":6705,"children":6706},{"style":1954},[6707],{"type":39,"value":2645},{"type":30,"tag":1881,"props":6709,"children":6710},{"class":1883,"line":1911},[6711,6715,6719,6723,6727,6731,6735,6739,6743,6747],{"type":30,"tag":1881,"props":6712,"children":6713},{"style":2226},[6714],{"type":39,"value":3324},{"type":30,"tag":1881,"props":6716,"children":6717},{"style":2308},[6718],{"type":39,"value":1997},{"type":30,"tag":1881,"props":6720,"children":6721},{"style":2226},[6722],{"type":39,"value":3333},{"type":30,"tag":1881,"props":6724,"children":6725},{"style":1954},[6726],{"type":39,"value":2341},{"type":30,"tag":1881,"props":6728,"children":6729},{"style":2226},[6730],{"type":39,"value":2667},{"type":30,"tag":1881,"props":6732,"children":6733},{"style":2308},[6734],{"type":39,"value":1997},{"type":30,"tag":1881,"props":6736,"children":6737},{"style":2226},[6738],{"type":39,"value":6442},{"type":30,"tag":1881,"props":6740,"children":6741},{"style":1954},[6742],{"type":39,"value":2374},{"type":30,"tag":1881,"props":6744,"children":6745},{"style":2226},[6746],{"type":39,"value":3431},{"type":30,"tag":1881,"props":6748,"children":6749},{"style":1954},[6750],{"type":39,"value":2007},{"type":30,"tag":1881,"props":6752,"children":6753},{"class":1883,"line":1933},[6754,6758,6762,6766],{"type":30,"tag":1881,"props":6755,"children":6756},{"style":2226},[6757],{"type":39,"value":3444},{"type":30,"tag":1881,"props":6759,"children":6760},{"style":2308},[6761],{"type":39,"value":1997},{"type":30,"tag":1881,"props":6763,"children":6764},{"style":3451},[6765],{"type":39,"value":6470},{"type":30,"tag":1881,"props":6767,"children":6768},{"style":1954},[6769],{"type":39,"value":2007},{"type":30,"tag":1881,"props":6771,"children":6772},{"class":1883,"line":1960},[6773,6777,6781,6785,6789],{"type":30,"tag":1881,"props":6774,"children":6775},{"style":2226},[6776],{"type":39,"value":3467},{"type":30,"tag":1881,"props":6778,"children":6779},{"style":2308},[6780],{"type":39,"value":1997},{"type":30,"tag":1881,"props":6782,"children":6783},{"style":1954},[6784],{"type":39,"value":2355},{"type":30,"tag":1881,"props":6786,"children":6787},{"style":2226},[6788],{"type":39,"value":4492},{"type":30,"tag":1881,"props":6790,"children":6791},{"style":1954},[6792],{"type":39,"value":2698},{"type":30,"tag":1881,"props":6794,"children":6795},{"class":1883,"line":1974},[6796,6800,6804],{"type":30,"tag":1881,"props":6797,"children":6798},{"style":1954},[6799],{"type":39,"value":2707},{"type":30,"tag":1881,"props":6801,"children":6802},{"style":2226},[6803],{"type":39,"value":2176},{"type":30,"tag":1881,"props":6805,"children":6806},{"style":1954},[6807],{"type":39,"value":2274},{"type":30,"tag":1881,"props":6809,"children":6810},{"class":1883,"line":2010},[6811,6815],{"type":30,"tag":1881,"props":6812,"children":6813},{"style":1954},[6814],{"type":39,"value":5630},{"type":30,"tag":1881,"props":6816,"children":6817},{"style":2226},[6818],{"type":39,"value":6819}," catch (err) {\n",{"type":30,"tag":1881,"props":6821,"children":6822},{"class":1883,"line":2040},[6823,6828,6832,6836,6841,6845],{"type":30,"tag":1881,"props":6824,"children":6825},{"style":2226},[6826],{"type":39,"value":6827},"    this.logger.",{"type":30,"tag":1881,"props":6829,"children":6830},{"style":1921},[6831],{"type":39,"value":6537},{"type":30,"tag":1881,"props":6833,"children":6834},{"style":1954},[6835],{"type":39,"value":2138},{"type":30,"tag":1881,"props":6837,"children":6838},{"style":2262},[6839],{"type":39,"value":6840},"'brevo.slot_confirmation.failed'",{"type":30,"tag":1881,"props":6842,"children":6843},{"style":1954},[6844],{"type":39,"value":2158},{"type":30,"tag":1881,"props":6846,"children":6847},{"style":1954},[6848],{"type":39,"value":1957},{"type":30,"tag":1881,"props":6850,"children":6851},{"class":1883,"line":2070},[6852,6857],{"type":30,"tag":1881,"props":6853,"children":6854},{"style":1988},[6855],{"type":39,"value":6856},"      clientEmail",{"type":30,"tag":1881,"props":6858,"children":6859},{"style":1954},[6860],{"type":39,"value":2007},{"type":30,"tag":1881,"props":6862,"children":6863},{"class":1883,"line":2100},[6864,6869],{"type":30,"tag":1881,"props":6865,"children":6866},{"style":1988},[6867],{"type":39,"value":6868},"      slotId",{"type":30,"tag":1881,"props":6870,"children":6871},{"style":1954},[6872],{"type":39,"value":2007},{"type":30,"tag":1881,"props":6874,"children":6875},{"class":1883,"line":2114},[6876,6882,6886,6891,6896,6901,6906,6911,6915,6920,6924,6929,6934],{"type":30,"tag":1881,"props":6877,"children":6879},{"style":6878},"--shiki-default:#C6D0F5;--shiki-dark:#FFAB70",[6880],{"type":39,"value":6881},"      error",{"type":30,"tag":1881,"props":6883,"children":6884},{"style":1954},[6885],{"type":39,"value":1997},{"type":30,"tag":1881,"props":6887,"children":6888},{"style":1988},[6889],{"type":39,"value":6890}," err",{"type":30,"tag":1881,"props":6892,"children":6893},{"style":1988},[6894],{"type":39,"value":6895}," instanceof",{"type":30,"tag":1881,"props":6897,"children":6898},{"style":1988},[6899],{"type":39,"value":6900}," Error",{"type":30,"tag":1881,"props":6902,"children":6903},{"style":2226},[6904],{"type":39,"value":6905}," ? ",{"type":30,"tag":1881,"props":6907,"children":6908},{"style":1988},[6909],{"type":39,"value":6910},"err",{"type":30,"tag":1881,"props":6912,"children":6913},{"style":2226},[6914],{"type":39,"value":205},{"type":30,"tag":1881,"props":6916,"children":6917},{"style":6878},[6918],{"type":39,"value":6919},"message",{"type":30,"tag":1881,"props":6921,"children":6922},{"style":1954},[6923],{"type":39,"value":4054},{"type":30,"tag":1881,"props":6925,"children":6926},{"style":1988},[6927],{"type":39,"value":6928}," String",{"type":30,"tag":1881,"props":6930,"children":6931},{"style":2226},[6932],{"type":39,"value":6933},"(err)",{"type":30,"tag":1881,"props":6935,"children":6936},{"style":1954},[6937],{"type":39,"value":2007},{"type":30,"tag":1881,"props":6939,"children":6940},{"class":1883,"line":2122},[6941,6946],{"type":30,"tag":1881,"props":6942,"children":6943},{"style":1954},[6944],{"type":39,"value":6945},"    })",{"type":30,"tag":1881,"props":6947,"children":6948},{"style":2226},[6949],{"type":39,"value":2274},{"type":30,"tag":1881,"props":6951,"children":6952},{"class":1883,"line":2208},[6953,6958,6963,6967,6971,6977,6981,6986,6990],{"type":30,"tag":1881,"props":6954,"children":6955},{"style":2226},[6956],{"type":39,"value":6957},"    this.metricsService.increment(",{"type":30,"tag":1881,"props":6959,"children":6960},{"style":2262},[6961],{"type":39,"value":6962},"'notification_failures_total'",{"type":30,"tag":1881,"props":6964,"children":6965},{"style":1954},[6966],{"type":39,"value":2158},{"type":30,"tag":1881,"props":6968,"children":6969},{"style":1954},[6970],{"type":39,"value":2355},{"type":30,"tag":1881,"props":6972,"children":6974},{"style":6973},"--shiki-default:#C6D0F5;--shiki-dark:#B392F0",[6975],{"type":39,"value":6976}," type",{"type":30,"tag":1881,"props":6978,"children":6979},{"style":1954},[6980],{"type":39,"value":1997},{"type":30,"tag":1881,"props":6982,"children":6983},{"style":2262},[6984],{"type":39,"value":6985}," 'slot_confirmation'",{"type":30,"tag":1881,"props":6987,"children":6988},{"style":1954},[6989],{"type":39,"value":2379},{"type":30,"tag":1881,"props":6991,"children":6992},{"style":2226},[6993],{"type":39,"value":6994},");\n",{"type":30,"tag":1881,"props":6996,"children":6997},{"class":1883,"line":2217},[6998,7003,7008,7012,7017,7021,7025,7029,7034,7038],{"type":30,"tag":1881,"props":6999,"children":7000},{"style":2226},[7001],{"type":39,"value":7002},"    throw new ",{"type":30,"tag":1881,"props":7004,"children":7005},{"style":1921},[7006],{"type":39,"value":7007},"NotificationDeliveryException",{"type":30,"tag":1881,"props":7009,"children":7010},{"style":1954},[7011],{"type":39,"value":2138},{"type":30,"tag":1881,"props":7013,"children":7014},{"style":2262},[7015],{"type":39,"value":7016},"`Confirmation slot ",{"type":30,"tag":1881,"props":7018,"children":7019},{"style":2433},[7020],{"type":39,"value":2436},{"type":30,"tag":1881,"props":7022,"children":7023},{"style":2226},[7024],{"type":39,"value":4200},{"type":30,"tag":1881,"props":7026,"children":7027},{"style":2433},[7028],{"type":39,"value":2374},{"type":30,"tag":1881,"props":7030,"children":7031},{"style":2262},[7032],{"type":39,"value":7033}," non envoyée`",{"type":30,"tag":1881,"props":7035,"children":7036},{"style":1954},[7037],{"type":39,"value":2176},{"type":30,"tag":1881,"props":7039,"children":7040},{"style":2226},[7041],{"type":39,"value":2274},{"type":30,"tag":1881,"props":7043,"children":7044},{"class":1883,"line":2277},[7045],{"type":30,"tag":1881,"props":7046,"children":7047},{"style":1954},[7048],{"type":39,"value":3950},{"type":30,"tag":1881,"props":7050,"children":7051},{"class":1883,"line":2390},[7052],{"type":30,"tag":1881,"props":7053,"children":7054},{"style":2226},[7055],{"type":39,"value":3959},{"type":30,"tag":31,"props":7057,"children":7058},{},[7059,7061,7065,7067,7073],{"type":39,"value":7060},"Michael Nygard a documenté ce sujet en profondeur dans ",{"type":30,"tag":42,"props":7062,"children":7063},{},[7064],{"type":39,"value":1718},{"type":39,"value":7066}," (2007). Les ",{"type":30,"tag":88,"props":7068,"children":7070},{"href":7069},"/fr/architecture-craft/patterns-resilience-circuit-breaker-retry",[7071],{"type":39,"value":7072},"patterns de résilience type circuit breaker et retry",{"type":39,"value":7074}," 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":30,"tag":55,"props":7076,"children":7077},{},[],{"type":30,"tag":59,"props":7079,"children":7081},{"id":7080},"pattern-5-dépendances-non-auditées",[7082],{"type":39,"value":7083},"Pattern #5 : dépendances non auditées",{"type":30,"tag":31,"props":7085,"children":7086},{},[7087,7089,7095,7097,7103,7105,7111,7113,7119],{"type":39,"value":7088},"Le dernier pattern est le plus invisible. Claude propose une dépendance pour résoudre un problème : \"Ajoute ",{"type":30,"tag":262,"props":7090,"children":7092},{"className":7091},[],[7093],{"type":39,"value":7094},"stripe",{"type":39,"value":7096}," pour les checkouts\", \"Utilise ",{"type":30,"tag":262,"props":7098,"children":7100},{"className":7099},[],[7101],{"type":39,"value":7102},"jose",{"type":39,"value":7104}," pour signer ce token\", \"Importe ",{"type":30,"tag":262,"props":7106,"children":7108},{"className":7107},[],[7109],{"type":39,"value":7110},"date-fns",{"type":39,"value":7112}," pour ce calcul de durée\". Le développeur lance ",{"type":30,"tag":262,"props":7114,"children":7116},{"className":7115},[],[7117],{"type":39,"value":7118},"pnpm add \u003Cpkg>",{"type":39,"value":7120},", ça compile, ça passe les tests, ça merge. Et l'artefact entre dans le repo, sans audit, sans justification.",{"type":30,"tag":31,"props":7122,"children":7123},{},[7124,7126,7132],{"type":39,"value":7125},"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":30,"tag":88,"props":7127,"children":7129},{"href":7128},"/fr/intelligence-artificielle/llm-securite-code-vulnerabilites",[7130],{"type":39,"value":7131},"les vulnérabilités de sécurité dans le code LLM-généré",{"type":39,"value":205},{"type":30,"tag":31,"props":7134,"children":7135},{},[7136,7138,7144,7146,7151],{"type":39,"value":7137},"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":30,"tag":262,"props":7139,"children":7141},{"className":7140},[],[7142],{"type":39,"value":7143},"time-to-patch",{"type":39,"value":7145}," sur les CVE critiques (en dessous de 7 jours = sain). Enfin, automatiser la veille via ",{"type":30,"tag":88,"props":7147,"children":7148},{"href":1309},[7149],{"type":39,"value":7150},"Dependabot configuré craft",{"type":39,"value":7152}," avec auto-merge sur les patches et review humaine sur les majors.",{"type":30,"tag":31,"props":7154,"children":7155},{},[7156,7158,7164],{"type":39,"value":7157},"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":30,"tag":262,"props":7159,"children":7161},{"className":7160},[],[7162],{"type":39,"value":7163},"pnpm audit",{"type":39,"value":7165},". 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":30,"tag":55,"props":7167,"children":7168},{},[],{"type":30,"tag":59,"props":7170,"children":7172},{"id":7171},"les-5-garde-fous-craft-à-installer-dès-lundi",[7173],{"type":39,"value":7174},"Les 5 garde-fous craft à installer dès lundi",{"type":30,"tag":31,"props":7176,"children":7177},{},[7178],{"type":39,"value":7179},"Voici la grille condensée. Mettez-la en checklist GitHub PR template.",{"type":30,"tag":537,"props":7181,"children":7182},{},[7183,7203],{"type":30,"tag":541,"props":7184,"children":7185},{},[7186],{"type":30,"tag":545,"props":7187,"children":7188},{},[7189,7194,7199],{"type":30,"tag":549,"props":7190,"children":7191},{},[7192],{"type":39,"value":7193},"Pattern",{"type":30,"tag":549,"props":7195,"children":7196},{},[7197],{"type":39,"value":7198},"Signal en review",{"type":30,"tag":549,"props":7200,"children":7201},{},[7202],{"type":39,"value":1364},{"type":30,"tag":560,"props":7204,"children":7205},{},[7206,7222,7262,7285,7307],{"type":30,"tag":545,"props":7207,"children":7208},{},[7209,7213,7218],{"type":30,"tag":567,"props":7210,"children":7211},{},[7212],{"type":39,"value":1393},{"type":30,"tag":567,"props":7214,"children":7215},{},[7216],{"type":39,"value":7217},"Fonction > 40 lignes ou > 3 niveaux d'indentation",{"type":30,"tag":567,"props":7219,"children":7220},{},[7221],{"type":39,"value":1403},{"type":30,"tag":545,"props":7223,"children":7224},{},[7225,7229,7252],{"type":30,"tag":567,"props":7226,"children":7227},{},[7228],{"type":39,"value":1411},{"type":30,"tag":567,"props":7230,"children":7231},{},[7232,7237,7239,7245,7247],{"type":30,"tag":262,"props":7233,"children":7235},{"className":7234},[],[7236],{"type":39,"value":4039},{"type":39,"value":7238}," injecté dans ",{"type":30,"tag":262,"props":7240,"children":7242},{"className":7241},[],[7243],{"type":39,"value":7244},"application/",{"type":39,"value":7246}," ou ",{"type":30,"tag":262,"props":7248,"children":7250},{"className":7249},[],[7251],{"type":39,"value":1422},{"type":30,"tag":567,"props":7253,"children":7254},{},[7255,7257],{"type":39,"value":7256},"Interface Repository (port), adapter Prisma en ",{"type":30,"tag":262,"props":7258,"children":7260},{"className":7259},[],[7261],{"type":39,"value":4642},{"type":30,"tag":545,"props":7263,"children":7264},{},[7265,7269,7280],{"type":30,"tag":567,"props":7266,"children":7267},{},[7268],{"type":39,"value":1435},{"type":30,"tag":567,"props":7270,"children":7271},{},[7272,7278],{"type":30,"tag":262,"props":7273,"children":7275},{"className":7274},[],[7276],{"type":39,"value":7277},"expect(repo.save).toHaveBeenCalled()",{"type":39,"value":7279}," sans assertion comportementale",{"type":30,"tag":567,"props":7281,"children":7282},{},[7283],{"type":39,"value":7284},"Format Given/When/Then sur comportement observable",{"type":30,"tag":545,"props":7286,"children":7287},{},[7288,7292,7302],{"type":30,"tag":567,"props":7289,"children":7290},{},[7291],{"type":39,"value":1458},{"type":30,"tag":567,"props":7293,"children":7294},{},[7295,7301],{"type":30,"tag":262,"props":7296,"children":7298},{"className":7297},[],[7299],{"type":39,"value":7300},"catch (e) { console.error(e) }",{"type":39,"value":1469},{"type":30,"tag":567,"props":7303,"children":7304},{},[7305],{"type":39,"value":7306},"Re-throw typé, métrique, ou rollback",{"type":30,"tag":545,"props":7308,"children":7309},{},[7310,7315,7328],{"type":30,"tag":567,"props":7311,"children":7312},{},[7313],{"type":39,"value":7314},"Dépendance non auditée",{"type":30,"tag":567,"props":7316,"children":7317},{},[7318,7320,7326],{"type":39,"value":7319},"Entrée ",{"type":30,"tag":262,"props":7321,"children":7323},{"className":7322},[],[7324],{"type":39,"value":7325},"package.json",{"type":39,"value":7327}," sans commentaire de justification",{"type":30,"tag":567,"props":7329,"children":7330},{},[7331,7333,7338],{"type":39,"value":7332},"Audit 30 sec (",{"type":30,"tag":262,"props":7334,"children":7336},{"className":7335},[],[7337],{"type":39,"value":7163},{"type":39,"value":7339},") + Dependabot configuré craft",{"type":30,"tag":31,"props":7341,"children":7342},{},[7343],{"type":39,"value":7344},"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":30,"tag":55,"props":7346,"children":7347},{},[],{"type":30,"tag":392,"props":7349,"children":7351},{"cta":394,"href":395,"title":7350,"type":397},"Vous voulez voir ces patterns dans une PR Claude avant qu'ils ne deviennent de la dette ?",[7352],{"type":30,"tag":31,"props":7353,"children":7354},{},[7355],{"type":39,"value":7356},"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":30,"tag":55,"props":7358,"children":7359},{},[],{"type":30,"tag":59,"props":7361,"children":7362},{"id":639},[7363],{"type":39,"value":642},{"type":30,"tag":31,"props":7365,"children":7366},{},[7367],{"type":39,"value":7368},"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":30,"tag":537,"props":7370,"children":7371},{},[7372,7392],{"type":30,"tag":541,"props":7373,"children":7374},{},[7375],{"type":30,"tag":545,"props":7376,"children":7377},{},[7378,7382,7387],{"type":30,"tag":549,"props":7379,"children":7380},{},[7381],{"type":39,"value":661},{"type":30,"tag":549,"props":7383,"children":7384},{},[7385],{"type":39,"value":7386},"Avant grille",{"type":30,"tag":549,"props":7388,"children":7389},{},[7390],{"type":39,"value":7391},"Après 6 mois",{"type":30,"tag":560,"props":7393,"children":7394},{},[7395,7413,7431,7449,7467],{"type":30,"tag":545,"props":7396,"children":7397},{},[7398,7403,7408],{"type":30,"tag":567,"props":7399,"children":7400},{},[7401],{"type":39,"value":7402},"Fonctions > 40 lignes dans le repo",{"type":30,"tag":567,"props":7404,"children":7405},{},[7406],{"type":39,"value":7407},"22% des fonctions",{"type":30,"tag":567,"props":7409,"children":7410},{},[7411],{"type":39,"value":7412},"4% des fonctions",{"type":30,"tag":545,"props":7414,"children":7415},{},[7416,7421,7426],{"type":30,"tag":567,"props":7417,"children":7418},{},[7419],{"type":39,"value":7420},"Couverture de tests behavior-level",{"type":30,"tag":567,"props":7422,"children":7423},{},[7424],{"type":39,"value":7425},"15%",{"type":30,"tag":567,"props":7427,"children":7428},{},[7429],{"type":39,"value":7430},"70%",{"type":30,"tag":545,"props":7432,"children":7433},{},[7434,7439,7444],{"type":30,"tag":567,"props":7435,"children":7436},{},[7437],{"type":39,"value":7438},"Incidents prod liés à exception swallowed",{"type":30,"tag":567,"props":7440,"children":7441},{},[7442],{"type":39,"value":7443},"4 par trimestre",{"type":30,"tag":567,"props":7445,"children":7446},{},[7447],{"type":39,"value":7448},"0 par trimestre",{"type":30,"tag":545,"props":7450,"children":7451},{},[7452,7457,7462],{"type":30,"tag":567,"props":7453,"children":7454},{},[7455],{"type":39,"value":7456},"Time-to-patch CVE critique",{"type":30,"tag":567,"props":7458,"children":7459},{},[7460],{"type":39,"value":7461},"38 jours",{"type":30,"tag":567,"props":7463,"children":7464},{},[7465],{"type":39,"value":7466},"6 jours",{"type":30,"tag":545,"props":7468,"children":7469},{},[7470,7475,7480],{"type":30,"tag":567,"props":7471,"children":7472},{},[7473],{"type":39,"value":7474},"Heures consacrées au refactoring d'urgence",{"type":30,"tag":567,"props":7476,"children":7477},{},[7478],{"type":39,"value":7479},"12h/semaine",{"type":30,"tag":567,"props":7481,"children":7482},{},[7483],{"type":39,"value":7484},"3h/semaine",{"type":30,"tag":31,"props":7486,"children":7487},{},[7488,7490,7494],{"type":39,"value":7489},"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":30,"tag":88,"props":7491,"children":7492},{"href":790},[7493],{"type":39,"value":793},{"type":39,"value":205},{"type":30,"tag":55,"props":7496,"children":7497},{},[],{"type":30,"tag":59,"props":7499,"children":7500},{"id":801},[7501],{"type":39,"value":804},{"type":30,"tag":31,"props":7503,"children":7504},{},[7505],{"type":39,"value":7506},"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":30,"tag":31,"props":7508,"children":7509},{},[7510],{"type":39,"value":7511},"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":30,"tag":31,"props":7513,"children":7514},{},[7515],{"type":39,"value":7516},"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":30,"tag":31,"props":7518,"children":7519},{},[7520,7522,7527],{"type":39,"value":7521},"Pour suivre la suite des patterns craft que je documente chaque semaine, retrouvez-moi sur ",{"type":30,"tag":88,"props":7523,"children":7525},{"href":125,"rel":7524},[127],[7526],{"type":39,"value":130},{"type":39,"value":205},{"type":30,"tag":55,"props":7529,"children":7530},{},[],{"type":30,"tag":392,"props":7532,"children":7534},{"cta":833,"href":834,"title":7533,"type":836},"Ces 5 garde-fous ne sont qu'un début : il en existe 100",[7535],{"type":30,"tag":31,"props":7536,"children":7537},{},[7538],{"type":39,"value":7539},"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":30,"tag":55,"props":7541,"children":7542},{},[],{"type":30,"tag":59,"props":7544,"children":7546},{"id":7545},"faq-sur-les-anti-patterns-claude-et-la-review-craft",[7547],{"type":39,"value":7548},"FAQ sur les anti-patterns Claude et la review craft",{"type":30,"tag":853,"props":7550,"children":7551},{},[7552,7557],{"type":30,"tag":857,"props":7553,"children":7554},{},[7555],{"type":39,"value":7556},"1. Comment introduire cette grille sans braquer une équipe qui aime Claude ?",{"type":30,"tag":31,"props":7558,"children":7559},{},[7560],{"type":39,"value":7561},"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":30,"tag":853,"props":7563,"children":7564},{},[7565,7570],{"type":30,"tag":857,"props":7566,"children":7567},{},[7568],{"type":39,"value":7569},"2. Faut-il refuser Claude sur les use cases critiques (paiement, auth) ?",{"type":30,"tag":31,"props":7571,"children":7572},{},[7573,7575,7580],{"type":39,"value":7574},"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":30,"tag":42,"props":7576,"children":7577},{},[7578],{"type":39,"value":7579},"\"Ce use case gère un checkout Stripe sur un SaaS multi-tenant. Utilise une transaction Prisma, type les exceptions, ne swallow rien.\"",{"type":39,"value":7581}," Le résultat est radicalement meilleur.",{"type":30,"tag":853,"props":7583,"children":7584},{},[7585,7590],{"type":30,"tag":857,"props":7586,"children":7587},{},[7588],{"type":39,"value":7589},"3. Comment automatiser la détection de ces 5 patterns ?",{"type":30,"tag":31,"props":7591,"children":7592},{},[7593,7595,7601,7603,7609,7611,7616,7618,7623],{"type":39,"value":7594},"Partiellement. Biome détecte les fonctions trop longues (",{"type":30,"tag":262,"props":7596,"children":7598},{"className":7597},[],[7599],{"type":39,"value":7600},"noExcessiveLinesPerFunction",{"type":39,"value":7602},"), la complexité cognitive (",{"type":30,"tag":262,"props":7604,"children":7606},{"className":7605},[],[7607],{"type":39,"value":7608},"noExcessiveCognitiveComplexity",{"type":39,"value":7610},"), et les ",{"type":30,"tag":262,"props":7612,"children":7614},{"className":7613},[],[7615],{"type":39,"value":6609},{"type":39,"value":7617}," 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":30,"tag":262,"props":7619,"children":7621},{"className":7620},[],[7622],{"type":39,"value":7163},{"type":39,"value":7624}," + Dependabot pour les packages npm). L'arsenal complet est détaillé dans les outils d'analyse statique en 2026.",{"type":30,"tag":853,"props":7626,"children":7627},{},[7628,7633],{"type":30,"tag":857,"props":7629,"children":7630},{},[7631],{"type":39,"value":7632},"4. Le pattern God Function vient-il vraiment de Claude ou existait-il déjà ?",{"type":30,"tag":31,"props":7634,"children":7635},{},[7636],{"type":39,"value":7637},"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":30,"tag":853,"props":7639,"children":7640},{},[7641,7646],{"type":30,"tag":857,"props":7642,"children":7643},{},[7644],{"type":39,"value":7645},"5. Quelle taille maximum recommander pour une fonction ?",{"type":30,"tag":31,"props":7647,"children":7648},{},[7649,7651,7655,7657,7662],{"type":39,"value":7650},"Robert C. Martin disait dans ",{"type":30,"tag":42,"props":7652,"children":7653},{},[7654],{"type":39,"value":1054},{"type":39,"value":7656}," : \"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":30,"tag":262,"props":7658,"children":7660},{"className":7659},[],[7661],{"type":39,"value":7600},{"type":39,"value":7663},") fait échouer le lint si on dépasse.",{"type":30,"tag":853,"props":7665,"children":7666},{},[7667,7672],{"type":30,"tag":857,"props":7668,"children":7669},{},[7670],{"type":39,"value":7671},"6. Les tests behavior-level ne ralentissent-ils pas la CI ?",{"type":30,"tag":31,"props":7673,"children":7674},{},[7675],{"type":39,"value":7676},"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":30,"tag":55,"props":7678,"children":7679},{},[],{"type":30,"tag":392,"props":7681,"children":7682},{"cta":944,"href":945,"title":946,"type":947},[7683],{"type":30,"tag":31,"props":7684,"children":7685},{},[7686],{"type":39,"value":7687},"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":30,"tag":7689,"props":7690,"children":7691},"style",{},[7692],{"type":39,"value":7693},"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":955,"depth":955,"links":7695},[7696,7697,7698,7699,7700,7701,7702,7703,7704,7705],{"id":1790,"depth":955,"text":1793},{"id":1856,"depth":955,"text":1859},{"id":4025,"depth":955,"text":4028},{"id":5154,"depth":955,"text":5157},{"id":6291,"depth":955,"text":6294},{"id":7080,"depth":955,"text":7083},{"id":7171,"depth":955,"text":7174},{"id":639,"depth":955,"text":642},{"id":801,"depth":955,"text":804},{"id":7545,"depth":955,"text":7548},"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":1086,"_dir":974,"_draft":7,"_partial":7,"_locale":8,"title":7710,"description":7711,"id":3820,"date":7712,"listed":13,"nocomments":7,"hidden":7,"categories":7713,"tags":7714,"cover":7716,"readingTime":7717,"body":7722,"_type":967,"_id":10119,"_source":969,"_file":10120,"_stem":10121,"_extension":972},"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",[974],[981,7715,1764,16,983],"race-condition","covers/articles/bug-claude-vendredi-dernier.jpg",{"text":7718,"minutes":7719,"time":7720,"words":7721},"12 min read",11.12,667200,2224,{"type":27,"children":7723,"toc":10110},[7724,7740,7745,7754,7757,7763,7775,7803,7822,7848,7851,7857,7869,8386,8412,8431,8443,8446,8455,8458,8464,8469,8994,8999,9168,9212,9231,9234,9240,9245,9262,9279,9311,9343,9819,9824,9827,9831,9836,9932,9944,9947,9956,9959,9963,9968,9973,9978,9990,9993,9999,10017,10030,10056,10069,10082,10095,10098,10106],{"type":30,"tag":31,"props":7725,"children":7726},{},[7727],{"type":30,"tag":35,"props":7728,"children":7729},{},[7730,7732,7738],{"type":39,"value":7731},"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":30,"tag":262,"props":7733,"children":7735},{"className":7734},[],[7736],{"type":39,"value":7737},"holdSlot",{"type":39,"value":7739}," 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":30,"tag":31,"props":7741,"children":7742},{},[7743],{"type":39,"value":7744},"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":30,"tag":31,"props":7746,"children":7747},{},[7748],{"type":30,"tag":7749,"props":7750,"children":7753},"img",{"alt":7751,"src":7752},"Le module client de crmcoaching, que je développe avec Claude","/images/crm/client.png",[],{"type":30,"tag":55,"props":7755,"children":7756},{},[],{"type":30,"tag":59,"props":7758,"children":7760},{"id":7759},"pourquoi-les-bugs-claude-passent-en-review",[7761],{"type":39,"value":7762},"Pourquoi les bugs Claude passent en review",{"type":30,"tag":31,"props":7764,"children":7765},{},[7766,7768,7773],{"type":39,"value":7767},"Le constat est simple, et il est documenté. Selon le ",{"type":30,"tag":88,"props":7769,"children":7771},{"href":1801,"rel":7770},[127],[7772],{"type":39,"value":1805},{"type":39,"value":7774},", 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":30,"tag":31,"props":7776,"children":7777},{},[7778,7780,7785,7787,7793,7795,7801],{"type":39,"value":7779},"Le vendredi dont je parle, la PR portait sur ",{"type":30,"tag":262,"props":7781,"children":7783},{"className":7782},[],[7784],{"type":39,"value":7737},{"type":39,"value":7786}," : un use case NestJS qui lisait le statut du créneau en base, vérifiait qu'il était ",{"type":30,"tag":262,"props":7788,"children":7790},{"className":7789},[],[7791],{"type":39,"value":7792},"AVAILABLE",{"type":39,"value":7794},", puis écrivait ",{"type":30,"tag":262,"props":7796,"children":7798},{"className":7797},[],[7799],{"type":39,"value":7800},"HELD",{"type":39,"value":7802},". 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":30,"tag":97,"props":7804,"children":7805},{},[7806],{"type":30,"tag":31,"props":7807,"children":7808},{},[7809,7814,7816,7820],{"type":30,"tag":35,"props":7810,"children":7811},{},[7812],{"type":39,"value":7813},"Ce que j'observe sur crmcoaching",{"type":39,"value":7815}," : 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":30,"tag":88,"props":7817,"children":7818},{"href":1027},[7819],{"type":39,"value":1030},{"type":39,"value":7821}," que j'ai publié l'année dernière.",{"type":30,"tag":31,"props":7823,"children":7824},{},[7825,7827,7832,7834,7839,7841,7846],{"type":39,"value":7826},"C'est exactement ce que Bruce Schneier appelait ",{"type":30,"tag":42,"props":7828,"children":7829},{},[7830],{"type":39,"value":7831},"\"Security is a process, not a product\"",{"type":39,"value":7833}," dans son livre fondateur de 2000. La robustesse d'un ",{"type":30,"tag":262,"props":7835,"children":7837},{"className":7836},[],[7838],{"type":39,"value":7737},{"type":39,"value":7840}," 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":30,"tag":88,"props":7842,"children":7843},{"href":112},[7844],{"type":39,"value":7845},"les principes de clean code et software craftsmanship",{"type":39,"value":7847}," que je rappelle systématiquement en mission.",{"type":30,"tag":55,"props":7849,"children":7850},{},[],{"type":30,"tag":59,"props":7852,"children":7854},{"id":7853},"anatomie-dune-race-condition-typique-générée-par-ia",[7855],{"type":39,"value":7856},"Anatomie d'une race condition typique générée par IA",{"type":30,"tag":31,"props":7858,"children":7859},{},[7860,7862,7867],{"type":39,"value":7861},"Reprenons le code que Claude m'avait produit pour ",{"type":30,"tag":262,"props":7863,"children":7865},{"className":7864},[],[7866],{"type":39,"value":7737},{"type":39,"value":7868},". Voici la version simplifiée qui illustre le pattern :",{"type":30,"tag":1871,"props":7870,"children":7872},{"className":1873,"code":7871,"language":1875,"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",[7873],{"type":30,"tag":262,"props":7874,"children":7875},{"__ignoreMap":8},[7876,7884,7899,7919,7960,7967,8039,8095,8126,8141,8148,8185,8218,8226,8233,8276,8307,8357,8372,8379],{"type":30,"tag":1881,"props":7877,"children":7878},{"class":1883,"line":1884},[7879],{"type":30,"tag":1881,"props":7880,"children":7881},{"style":1888},[7882],{"type":39,"value":7883},"// apps/api/src/application/slot-hold/hold-slot.use-case.ts\n",{"type":30,"tag":1881,"props":7885,"children":7886},{"class":1883,"line":955},[7887,7891,7895],{"type":30,"tag":1881,"props":7888,"children":7889},{"style":1915},[7890],{"type":39,"value":1918},{"type":30,"tag":1881,"props":7892,"children":7893},{"style":1921},[7894],{"type":39,"value":1924},{"type":30,"tag":1881,"props":7896,"children":7897},{"style":1927},[7898],{"type":39,"value":1930},{"type":30,"tag":1881,"props":7900,"children":7901},{"class":1883,"line":1902},[7902,7906,7910,7915],{"type":30,"tag":1881,"props":7903,"children":7904},{"style":1937},[7905],{"type":39,"value":1940},{"type":30,"tag":1881,"props":7907,"children":7908},{"style":1937},[7909],{"type":39,"value":1945},{"type":30,"tag":1881,"props":7911,"children":7912},{"style":1948},[7913],{"type":39,"value":7914}," HoldSlotUseCase",{"type":30,"tag":1881,"props":7916,"children":7917},{"style":1954},[7918],{"type":39,"value":1957},{"type":30,"tag":1881,"props":7920,"children":7921},{"class":1883,"line":1911},[7922,7926,7930,7935,7939,7943,7947,7952,7956],{"type":30,"tag":1881,"props":7923,"children":7924},{"style":1937},[7925],{"type":39,"value":1966},{"type":30,"tag":1881,"props":7927,"children":7928},{"style":1954},[7929],{"type":39,"value":2138},{"type":30,"tag":1881,"props":7931,"children":7932},{"style":1937},[7933],{"type":39,"value":7934},"private",{"type":30,"tag":1881,"props":7936,"children":7937},{"style":1937},[7938],{"type":39,"value":1985},{"type":30,"tag":1881,"props":7940,"children":7941},{"style":1988},[7942],{"type":39,"value":1991},{"type":30,"tag":1881,"props":7944,"children":7945},{"style":1994},[7946],{"type":39,"value":1997},{"type":30,"tag":1881,"props":7948,"children":7949},{"style":1948},[7950],{"type":39,"value":7951}," PrismaService",{"type":30,"tag":1881,"props":7953,"children":7954},{"style":1954},[7955],{"type":39,"value":2176},{"type":30,"tag":1881,"props":7957,"children":7958},{"style":1954},[7959],{"type":39,"value":2111},{"type":30,"tag":1881,"props":7961,"children":7962},{"class":1883,"line":1933},[7963],{"type":30,"tag":1881,"props":7964,"children":7965},{"emptyLinePlaceholder":13},[7966],{"type":39,"value":1908},{"type":30,"tag":1881,"props":7968,"children":7969},{"class":1883,"line":1960},[7970,7974,7978,7982,7986,7990,7994,7998,8002,8006,8010,8014,8018,8022,8026,8031,8035],{"type":30,"tag":1881,"props":7971,"children":7972},{"style":1937},[7973],{"type":39,"value":2128},{"type":30,"tag":1881,"props":7975,"children":7976},{"style":1921},[7977],{"type":39,"value":2133},{"type":30,"tag":1881,"props":7979,"children":7980},{"style":1954},[7981],{"type":39,"value":2138},{"type":30,"tag":1881,"props":7983,"children":7984},{"style":1988},[7985],{"type":39,"value":4200},{"type":30,"tag":1881,"props":7987,"children":7988},{"style":1994},[7989],{"type":39,"value":1997},{"type":30,"tag":1881,"props":7991,"children":7992},{"style":2150},[7993],{"type":39,"value":2153},{"type":30,"tag":1881,"props":7995,"children":7996},{"style":1954},[7997],{"type":39,"value":2158},{"type":30,"tag":1881,"props":7999,"children":8000},{"style":1988},[8001],{"type":39,"value":3866},{"type":30,"tag":1881,"props":8003,"children":8004},{"style":1994},[8005],{"type":39,"value":1997},{"type":30,"tag":1881,"props":8007,"children":8008},{"style":2150},[8009],{"type":39,"value":2153},{"type":30,"tag":1881,"props":8011,"children":8012},{"style":1954},[8013],{"type":39,"value":2176},{"type":30,"tag":1881,"props":8015,"children":8016},{"style":1994},[8017],{"type":39,"value":1997},{"type":30,"tag":1881,"props":8019,"children":8020},{"style":1948},[8021],{"type":39,"value":2185},{"type":30,"tag":1881,"props":8023,"children":8024},{"style":2188},[8025],{"type":39,"value":2191},{"type":30,"tag":1881,"props":8027,"children":8028},{"style":2150},[8029],{"type":39,"value":8030},"void",{"type":30,"tag":1881,"props":8032,"children":8033},{"style":2188},[8034],{"type":39,"value":2201},{"type":30,"tag":1881,"props":8036,"children":8037},{"style":1954},[8038],{"type":39,"value":1957},{"type":30,"tag":1881,"props":8040,"children":8041},{"class":1883,"line":1974},[8042,8046,8050,8054,8058,8062,8066,8070,8074,8078,8082,8087,8091],{"type":30,"tag":1881,"props":8043,"children":8044},{"style":1937},[8045],{"type":39,"value":2283},{"type":30,"tag":1881,"props":8047,"children":8048},{"style":2286},[8049],{"type":39,"value":4422},{"type":30,"tag":1881,"props":8051,"children":8052},{"style":1994},[8053],{"type":39,"value":2294},{"type":30,"tag":1881,"props":8055,"children":8056},{"style":1937},[8057],{"type":39,"value":2299},{"type":30,"tag":1881,"props":8059,"children":8060},{"style":2302},[8061],{"type":39,"value":2305},{"type":30,"tag":1881,"props":8063,"children":8064},{"style":2308},[8065],{"type":39,"value":205},{"type":30,"tag":1881,"props":8067,"children":8068},{"style":2226},[8069],{"type":39,"value":2315},{"type":30,"tag":1881,"props":8071,"children":8072},{"style":2308},[8073],{"type":39,"value":205},{"type":30,"tag":1881,"props":8075,"children":8076},{"style":2226},[8077],{"type":39,"value":4451},{"type":30,"tag":1881,"props":8079,"children":8080},{"style":2308},[8081],{"type":39,"value":205},{"type":30,"tag":1881,"props":8083,"children":8084},{"style":1921},[8085],{"type":39,"value":8086},"findUniqueOrThrow",{"type":30,"tag":1881,"props":8088,"children":8089},{"style":2226},[8090],{"type":39,"value":2138},{"type":30,"tag":1881,"props":8092,"children":8093},{"style":1954},[8094],{"type":39,"value":2645},{"type":30,"tag":1881,"props":8096,"children":8097},{"class":1883,"line":2010},[8098,8102,8106,8110,8114,8118,8122],{"type":30,"tag":1881,"props":8099,"children":8100},{"style":2226},[8101],{"type":39,"value":2654},{"type":30,"tag":1881,"props":8103,"children":8104},{"style":2308},[8105],{"type":39,"value":1997},{"type":30,"tag":1881,"props":8107,"children":8108},{"style":1954},[8109],{"type":39,"value":2355},{"type":30,"tag":1881,"props":8111,"children":8112},{"style":2226},[8113],{"type":39,"value":2360},{"type":30,"tag":1881,"props":8115,"children":8116},{"style":2308},[8117],{"type":39,"value":1997},{"type":30,"tag":1881,"props":8119,"children":8120},{"style":2226},[8121],{"type":39,"value":4492},{"type":30,"tag":1881,"props":8123,"children":8124},{"style":1954},[8125],{"type":39,"value":2698},{"type":30,"tag":1881,"props":8127,"children":8128},{"class":1883,"line":2040},[8129,8133,8137],{"type":30,"tag":1881,"props":8130,"children":8131},{"style":1954},[8132],{"type":39,"value":2707},{"type":30,"tag":1881,"props":8134,"children":8135},{"style":2226},[8136],{"type":39,"value":2176},{"type":30,"tag":1881,"props":8138,"children":8139},{"style":1954},[8140],{"type":39,"value":2274},{"type":30,"tag":1881,"props":8142,"children":8143},{"class":1883,"line":2070},[8144],{"type":30,"tag":1881,"props":8145,"children":8146},{"emptyLinePlaceholder":13},[8147],{"type":39,"value":1908},{"type":30,"tag":1881,"props":8149,"children":8150},{"class":1883,"line":2100},[8151,8155,8160,8164,8168,8172,8177,8181],{"type":30,"tag":1881,"props":8152,"children":8153},{"style":1937},[8154],{"type":39,"value":2223},{"type":30,"tag":1881,"props":8156,"children":8157},{"style":2226},[8158],{"type":39,"value":8159}," (slot",{"type":30,"tag":1881,"props":8161,"children":8162},{"style":2308},[8163],{"type":39,"value":205},{"type":30,"tag":1881,"props":8165,"children":8166},{"style":2226},[8167],{"type":39,"value":2540},{"type":30,"tag":1881,"props":8169,"children":8170},{"style":1994},[8171],{"type":39,"value":2484},{"type":30,"tag":1881,"props":8173,"children":8174},{"style":2262},[8175],{"type":39,"value":8176}," 'AVAILABLE'",{"type":30,"tag":1881,"props":8178,"children":8179},{"style":2226},[8180],{"type":39,"value":2555},{"type":30,"tag":1881,"props":8182,"children":8183},{"style":1954},[8184],{"type":39,"value":2645},{"type":30,"tag":1881,"props":8186,"children":8187},{"class":1883,"line":2114},[8188,8193,8197,8201,8205,8210,8214],{"type":30,"tag":1881,"props":8189,"children":8190},{"style":1937},[8191],{"type":39,"value":8192},"      throw",{"type":30,"tag":1881,"props":8194,"children":8195},{"style":2247},[8196],{"type":39,"value":2250},{"type":30,"tag":1881,"props":8198,"children":8199},{"style":1921},[8200],{"type":39,"value":6900},{"type":30,"tag":1881,"props":8202,"children":8203},{"style":2226},[8204],{"type":39,"value":2138},{"type":30,"tag":1881,"props":8206,"children":8207},{"style":2262},[8208],{"type":39,"value":8209},"'Slot not available'",{"type":30,"tag":1881,"props":8211,"children":8212},{"style":2226},[8213],{"type":39,"value":2176},{"type":30,"tag":1881,"props":8215,"children":8216},{"style":1954},[8217],{"type":39,"value":2274},{"type":30,"tag":1881,"props":8219,"children":8220},{"class":1883,"line":2122},[8221],{"type":30,"tag":1881,"props":8222,"children":8223},{"style":1954},[8224],{"type":39,"value":8225},"    }\n",{"type":30,"tag":1881,"props":8227,"children":8228},{"class":1883,"line":2208},[8229],{"type":30,"tag":1881,"props":8230,"children":8231},{"emptyLinePlaceholder":13},[8232],{"type":39,"value":1908},{"type":30,"tag":1881,"props":8234,"children":8235},{"class":1883,"line":2217},[8236,8240,8244,8248,8252,8256,8260,8264,8268,8272],{"type":30,"tag":1881,"props":8237,"children":8238},{"style":1937},[8239],{"type":39,"value":3089},{"type":30,"tag":1881,"props":8241,"children":8242},{"style":2302},[8243],{"type":39,"value":2305},{"type":30,"tag":1881,"props":8245,"children":8246},{"style":2308},[8247],{"type":39,"value":205},{"type":30,"tag":1881,"props":8249,"children":8250},{"style":2226},[8251],{"type":39,"value":2315},{"type":30,"tag":1881,"props":8253,"children":8254},{"style":2308},[8255],{"type":39,"value":205},{"type":30,"tag":1881,"props":8257,"children":8258},{"style":2226},[8259],{"type":39,"value":4451},{"type":30,"tag":1881,"props":8261,"children":8262},{"style":2308},[8263],{"type":39,"value":205},{"type":30,"tag":1881,"props":8265,"children":8266},{"style":1921},[8267],{"type":39,"value":3118},{"type":30,"tag":1881,"props":8269,"children":8270},{"style":2226},[8271],{"type":39,"value":2138},{"type":30,"tag":1881,"props":8273,"children":8274},{"style":1954},[8275],{"type":39,"value":2645},{"type":30,"tag":1881,"props":8277,"children":8278},{"class":1883,"line":2277},[8279,8283,8287,8291,8295,8299,8303],{"type":30,"tag":1881,"props":8280,"children":8281},{"style":2226},[8282],{"type":39,"value":2654},{"type":30,"tag":1881,"props":8284,"children":8285},{"style":2308},[8286],{"type":39,"value":1997},{"type":30,"tag":1881,"props":8288,"children":8289},{"style":1954},[8290],{"type":39,"value":2355},{"type":30,"tag":1881,"props":8292,"children":8293},{"style":2226},[8294],{"type":39,"value":2360},{"type":30,"tag":1881,"props":8296,"children":8297},{"style":2308},[8298],{"type":39,"value":1997},{"type":30,"tag":1881,"props":8300,"children":8301},{"style":2226},[8302],{"type":39,"value":4492},{"type":30,"tag":1881,"props":8304,"children":8305},{"style":1954},[8306],{"type":39,"value":2698},{"type":30,"tag":1881,"props":8308,"children":8309},{"class":1883,"line":2390},[8310,8314,8318,8322,8326,8330,8335,8339,8344,8348,8353],{"type":30,"tag":1881,"props":8311,"children":8312},{"style":2226},[8313],{"type":39,"value":2850},{"type":30,"tag":1881,"props":8315,"children":8316},{"style":2308},[8317],{"type":39,"value":1997},{"type":30,"tag":1881,"props":8319,"children":8320},{"style":1954},[8321],{"type":39,"value":2355},{"type":30,"tag":1881,"props":8323,"children":8324},{"style":2226},[8325],{"type":39,"value":3179},{"type":30,"tag":1881,"props":8327,"children":8328},{"style":2308},[8329],{"type":39,"value":1997},{"type":30,"tag":1881,"props":8331,"children":8332},{"style":2262},[8333],{"type":39,"value":8334}," 'HELD'",{"type":30,"tag":1881,"props":8336,"children":8337},{"style":1954},[8338],{"type":39,"value":2158},{"type":30,"tag":1881,"props":8340,"children":8341},{"style":2226},[8342],{"type":39,"value":8343}," heldByClientId",{"type":30,"tag":1881,"props":8345,"children":8346},{"style":2308},[8347],{"type":39,"value":1997},{"type":30,"tag":1881,"props":8349,"children":8350},{"style":2226},[8351],{"type":39,"value":8352}," clientId ",{"type":30,"tag":1881,"props":8354,"children":8355},{"style":1954},[8356],{"type":39,"value":2698},{"type":30,"tag":1881,"props":8358,"children":8359},{"class":1883,"line":2460},[8360,8364,8368],{"type":30,"tag":1881,"props":8361,"children":8362},{"style":1954},[8363],{"type":39,"value":2707},{"type":30,"tag":1881,"props":8365,"children":8366},{"style":2226},[8367],{"type":39,"value":2176},{"type":30,"tag":1881,"props":8369,"children":8370},{"style":1954},[8371],{"type":39,"value":2274},{"type":30,"tag":1881,"props":8373,"children":8374},{"class":1883,"line":2522},[8375],{"type":30,"tag":1881,"props":8376,"children":8377},{"style":1954},[8378],{"type":39,"value":3950},{"type":30,"tag":1881,"props":8380,"children":8381},{"class":1883,"line":2588},[8382],{"type":30,"tag":1881,"props":8383,"children":8384},{"style":1954},[8385],{"type":39,"value":3959},{"type":30,"tag":31,"props":8387,"children":8388},{},[8389,8391,8397,8399,8404,8406,8411],{"type":39,"value":8390},"Le bug est à deux endroits. D'abord, la lecture de ",{"type":30,"tag":262,"props":8392,"children":8394},{"className":8393},[],[8395],{"type":39,"value":8396},"slot.status",{"type":39,"value":8398}," n'est pas verrouillée : deux requêtes parallèles peuvent toutes les deux lire ",{"type":30,"tag":262,"props":8400,"children":8402},{"className":8401},[],[8403],{"type":39,"value":7792},{"type":39,"value":8405}," 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":30,"tag":262,"props":8407,"children":8409},{"className":8408},[],[8410],{"type":39,"value":7800},{"type":39,"value":205},{"type":30,"tag":31,"props":8413,"children":8414},{},[8415,8417,8422,8424,8429],{"type":39,"value":8416},"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":30,"tag":262,"props":8418,"children":8420},{"className":8419},[],[8421],{"type":39,"value":2332},{"type":39,"value":8423}," + ",{"type":30,"tag":262,"props":8425,"children":8427},{"className":8426},[],[8428],{"type":39,"value":3118},{"type":39,"value":8430},". 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":30,"tag":31,"props":8432,"children":8433},{},[8434,8436,8441],{"type":39,"value":8435},"C'est aussi ce que Martin Fowler a documenté dans ",{"type":30,"tag":42,"props":8437,"children":8438},{},[8439],{"type":39,"value":8440},"Refactoring",{"type":39,"value":8442}," (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":30,"tag":55,"props":8444,"children":8445},{},[],{"type":30,"tag":392,"props":8447,"children":8449},{"cta":394,"href":395,"title":8448,"type":397},"Vous voulez développer le réflexe qui attrape ces bugs avant la prod ?",[8450],{"type":30,"tag":31,"props":8451,"children":8452},{},[8453],{"type":39,"value":8454},"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":30,"tag":55,"props":8456,"children":8457},{},[],{"type":30,"tag":59,"props":8459,"children":8461},{"id":8460},"le-fix-craft-transaction-atomique-et-garde-explicite",[8462],{"type":39,"value":8463},"Le fix craft : transaction atomique et garde explicite",{"type":30,"tag":31,"props":8465,"children":8466},{},[8467],{"type":39,"value":8468},"Voici la version que j'ai réécrite avec Claude, en lui donnant le bon contexte cette fois :",{"type":30,"tag":1871,"props":8470,"children":8472},{"className":1873,"code":8471,"language":1875,"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",[8473],{"type":30,"tag":262,"props":8474,"children":8475},{"__ignoreMap":8},[8476,8483,8498,8517,8556,8563,8634,8666,8695,8745,8793,8841,8857,8864,8903,8928,8936,8943,8969,8980,8987],{"type":30,"tag":1881,"props":8477,"children":8478},{"class":1883,"line":1884},[8479],{"type":30,"tag":1881,"props":8480,"children":8481},{"style":1888},[8482],{"type":39,"value":7883},{"type":30,"tag":1881,"props":8484,"children":8485},{"class":1883,"line":955},[8486,8490,8494],{"type":30,"tag":1881,"props":8487,"children":8488},{"style":1915},[8489],{"type":39,"value":1918},{"type":30,"tag":1881,"props":8491,"children":8492},{"style":1921},[8493],{"type":39,"value":1924},{"type":30,"tag":1881,"props":8495,"children":8496},{"style":1927},[8497],{"type":39,"value":1930},{"type":30,"tag":1881,"props":8499,"children":8500},{"class":1883,"line":1902},[8501,8505,8509,8513],{"type":30,"tag":1881,"props":8502,"children":8503},{"style":1937},[8504],{"type":39,"value":1940},{"type":30,"tag":1881,"props":8506,"children":8507},{"style":1937},[8508],{"type":39,"value":1945},{"type":30,"tag":1881,"props":8510,"children":8511},{"style":1948},[8512],{"type":39,"value":7914},{"type":30,"tag":1881,"props":8514,"children":8515},{"style":1954},[8516],{"type":39,"value":1957},{"type":30,"tag":1881,"props":8518,"children":8519},{"class":1883,"line":1911},[8520,8524,8528,8532,8536,8540,8544,8548,8552],{"type":30,"tag":1881,"props":8521,"children":8522},{"style":1937},[8523],{"type":39,"value":1966},{"type":30,"tag":1881,"props":8525,"children":8526},{"style":1954},[8527],{"type":39,"value":2138},{"type":30,"tag":1881,"props":8529,"children":8530},{"style":1937},[8531],{"type":39,"value":7934},{"type":30,"tag":1881,"props":8533,"children":8534},{"style":1937},[8535],{"type":39,"value":1985},{"type":30,"tag":1881,"props":8537,"children":8538},{"style":1988},[8539],{"type":39,"value":1991},{"type":30,"tag":1881,"props":8541,"children":8542},{"style":1994},[8543],{"type":39,"value":1997},{"type":30,"tag":1881,"props":8545,"children":8546},{"style":1948},[8547],{"type":39,"value":7951},{"type":30,"tag":1881,"props":8549,"children":8550},{"style":1954},[8551],{"type":39,"value":2176},{"type":30,"tag":1881,"props":8553,"children":8554},{"style":1954},[8555],{"type":39,"value":2111},{"type":30,"tag":1881,"props":8557,"children":8558},{"class":1883,"line":1933},[8559],{"type":30,"tag":1881,"props":8560,"children":8561},{"emptyLinePlaceholder":13},[8562],{"type":39,"value":1908},{"type":30,"tag":1881,"props":8564,"children":8565},{"class":1883,"line":1960},[8566,8570,8574,8578,8582,8586,8590,8594,8598,8602,8606,8610,8614,8618,8622,8626,8630],{"type":30,"tag":1881,"props":8567,"children":8568},{"style":1937},[8569],{"type":39,"value":2128},{"type":30,"tag":1881,"props":8571,"children":8572},{"style":1921},[8573],{"type":39,"value":2133},{"type":30,"tag":1881,"props":8575,"children":8576},{"style":1954},[8577],{"type":39,"value":2138},{"type":30,"tag":1881,"props":8579,"children":8580},{"style":1988},[8581],{"type":39,"value":4200},{"type":30,"tag":1881,"props":8583,"children":8584},{"style":1994},[8585],{"type":39,"value":1997},{"type":30,"tag":1881,"props":8587,"children":8588},{"style":2150},[8589],{"type":39,"value":2153},{"type":30,"tag":1881,"props":8591,"children":8592},{"style":1954},[8593],{"type":39,"value":2158},{"type":30,"tag":1881,"props":8595,"children":8596},{"style":1988},[8597],{"type":39,"value":3866},{"type":30,"tag":1881,"props":8599,"children":8600},{"style":1994},[8601],{"type":39,"value":1997},{"type":30,"tag":1881,"props":8603,"children":8604},{"style":2150},[8605],{"type":39,"value":2153},{"type":30,"tag":1881,"props":8607,"children":8608},{"style":1954},[8609],{"type":39,"value":2176},{"type":30,"tag":1881,"props":8611,"children":8612},{"style":1994},[8613],{"type":39,"value":1997},{"type":30,"tag":1881,"props":8615,"children":8616},{"style":1948},[8617],{"type":39,"value":2185},{"type":30,"tag":1881,"props":8619,"children":8620},{"style":2188},[8621],{"type":39,"value":2191},{"type":30,"tag":1881,"props":8623,"children":8624},{"style":2150},[8625],{"type":39,"value":8030},{"type":30,"tag":1881,"props":8627,"children":8628},{"style":2188},[8629],{"type":39,"value":2201},{"type":30,"tag":1881,"props":8631,"children":8632},{"style":1954},[8633],{"type":39,"value":1957},{"type":30,"tag":1881,"props":8635,"children":8636},{"class":1883,"line":1974},[8637,8641,8645,8649,8653,8657,8662],{"type":30,"tag":1881,"props":8638,"children":8639},{"style":1937},[8640],{"type":39,"value":3089},{"type":30,"tag":1881,"props":8642,"children":8643},{"style":2302},[8644],{"type":39,"value":2305},{"type":30,"tag":1881,"props":8646,"children":8647},{"style":2308},[8648],{"type":39,"value":205},{"type":30,"tag":1881,"props":8650,"children":8651},{"style":2226},[8652],{"type":39,"value":2315},{"type":30,"tag":1881,"props":8654,"children":8655},{"style":2308},[8656],{"type":39,"value":205},{"type":30,"tag":1881,"props":8658,"children":8659},{"style":1921},[8660],{"type":39,"value":8661},"$transaction",{"type":30,"tag":1881,"props":8663,"children":8664},{"style":2226},[8665],{"type":39,"value":1971},{"type":30,"tag":1881,"props":8667,"children":8668},{"class":1883,"line":2010},[8669,8674,8678,8683,8687,8691],{"type":30,"tag":1881,"props":8670,"children":8671},{"style":1937},[8672],{"type":39,"value":8673},"      async",{"type":30,"tag":1881,"props":8675,"children":8676},{"style":1954},[8677],{"type":39,"value":2229},{"type":30,"tag":1881,"props":8679,"children":8680},{"style":1988},[8681],{"type":39,"value":8682},"tx",{"type":30,"tag":1881,"props":8684,"children":8685},{"style":1954},[8686],{"type":39,"value":2176},{"type":30,"tag":1881,"props":8688,"children":8689},{"style":1994},[8690],{"type":39,"value":5238},{"type":30,"tag":1881,"props":8692,"children":8693},{"style":1954},[8694],{"type":39,"value":1957},{"type":30,"tag":1881,"props":8696,"children":8697},{"class":1883,"line":2040},[8698,8703,8707,8711,8715,8720,8724,8728,8732,8737,8741],{"type":30,"tag":1881,"props":8699,"children":8700},{"style":1937},[8701],{"type":39,"value":8702},"        const",{"type":30,"tag":1881,"props":8704,"children":8705},{"style":2286},[8706],{"type":39,"value":6003},{"type":30,"tag":1881,"props":8708,"children":8709},{"style":1994},[8710],{"type":39,"value":2294},{"type":30,"tag":1881,"props":8712,"children":8713},{"style":1937},[8714],{"type":39,"value":2299},{"type":30,"tag":1881,"props":8716,"children":8717},{"style":2226},[8718],{"type":39,"value":8719}," tx",{"type":30,"tag":1881,"props":8721,"children":8722},{"style":2308},[8723],{"type":39,"value":205},{"type":30,"tag":1881,"props":8725,"children":8726},{"style":2226},[8727],{"type":39,"value":4451},{"type":30,"tag":1881,"props":8729,"children":8730},{"style":2308},[8731],{"type":39,"value":205},{"type":30,"tag":1881,"props":8733,"children":8734},{"style":1921},[8735],{"type":39,"value":8736},"updateMany",{"type":30,"tag":1881,"props":8738,"children":8739},{"style":2226},[8740],{"type":39,"value":2138},{"type":30,"tag":1881,"props":8742,"children":8743},{"style":1954},[8744],{"type":39,"value":2645},{"type":30,"tag":1881,"props":8746,"children":8747},{"class":1883,"line":2070},[8748,8753,8757,8761,8765,8769,8773,8777,8781,8785,8789],{"type":30,"tag":1881,"props":8749,"children":8750},{"style":2226},[8751],{"type":39,"value":8752},"          where",{"type":30,"tag":1881,"props":8754,"children":8755},{"style":2308},[8756],{"type":39,"value":1997},{"type":30,"tag":1881,"props":8758,"children":8759},{"style":1954},[8760],{"type":39,"value":2355},{"type":30,"tag":1881,"props":8762,"children":8763},{"style":2226},[8764],{"type":39,"value":2360},{"type":30,"tag":1881,"props":8766,"children":8767},{"style":2308},[8768],{"type":39,"value":1997},{"type":30,"tag":1881,"props":8770,"children":8771},{"style":2226},[8772],{"type":39,"value":4331},{"type":30,"tag":1881,"props":8774,"children":8775},{"style":1954},[8776],{"type":39,"value":2158},{"type":30,"tag":1881,"props":8778,"children":8779},{"style":2226},[8780],{"type":39,"value":3179},{"type":30,"tag":1881,"props":8782,"children":8783},{"style":2308},[8784],{"type":39,"value":1997},{"type":30,"tag":1881,"props":8786,"children":8787},{"style":2262},[8788],{"type":39,"value":8176},{"type":30,"tag":1881,"props":8790,"children":8791},{"style":1954},[8792],{"type":39,"value":4395},{"type":30,"tag":1881,"props":8794,"children":8795},{"class":1883,"line":2100},[8796,8801,8805,8809,8813,8817,8821,8825,8829,8833,8837],{"type":30,"tag":1881,"props":8797,"children":8798},{"style":2226},[8799],{"type":39,"value":8800},"          data",{"type":30,"tag":1881,"props":8802,"children":8803},{"style":2308},[8804],{"type":39,"value":1997},{"type":30,"tag":1881,"props":8806,"children":8807},{"style":1954},[8808],{"type":39,"value":2355},{"type":30,"tag":1881,"props":8810,"children":8811},{"style":2226},[8812],{"type":39,"value":3179},{"type":30,"tag":1881,"props":8814,"children":8815},{"style":2308},[8816],{"type":39,"value":1997},{"type":30,"tag":1881,"props":8818,"children":8819},{"style":2262},[8820],{"type":39,"value":8334},{"type":30,"tag":1881,"props":8822,"children":8823},{"style":1954},[8824],{"type":39,"value":2158},{"type":30,"tag":1881,"props":8826,"children":8827},{"style":2226},[8828],{"type":39,"value":8343},{"type":30,"tag":1881,"props":8830,"children":8831},{"style":2308},[8832],{"type":39,"value":1997},{"type":30,"tag":1881,"props":8834,"children":8835},{"style":2226},[8836],{"type":39,"value":8352},{"type":30,"tag":1881,"props":8838,"children":8839},{"style":1954},[8840],{"type":39,"value":2698},{"type":30,"tag":1881,"props":8842,"children":8843},{"class":1883,"line":2114},[8844,8849,8853],{"type":30,"tag":1881,"props":8845,"children":8846},{"style":1954},[8847],{"type":39,"value":8848},"        }",{"type":30,"tag":1881,"props":8850,"children":8851},{"style":2226},[8852],{"type":39,"value":2176},{"type":30,"tag":1881,"props":8854,"children":8855},{"style":1954},[8856],{"type":39,"value":2274},{"type":30,"tag":1881,"props":8858,"children":8859},{"class":1883,"line":2122},[8860],{"type":30,"tag":1881,"props":8861,"children":8862},{"emptyLinePlaceholder":13},[8863],{"type":39,"value":1908},{"type":30,"tag":1881,"props":8865,"children":8866},{"class":1883,"line":2208},[8867,8872,8877,8881,8886,8890,8895,8899],{"type":30,"tag":1881,"props":8868,"children":8869},{"style":1937},[8870],{"type":39,"value":8871},"        if",{"type":30,"tag":1881,"props":8873,"children":8874},{"style":2226},[8875],{"type":39,"value":8876}," (result",{"type":30,"tag":1881,"props":8878,"children":8879},{"style":2308},[8880],{"type":39,"value":205},{"type":30,"tag":1881,"props":8882,"children":8883},{"style":2226},[8884],{"type":39,"value":8885},"count ",{"type":30,"tag":1881,"props":8887,"children":8888},{"style":1994},[8889],{"type":39,"value":2484},{"type":30,"tag":1881,"props":8891,"children":8892},{"style":3451},[8893],{"type":39,"value":8894}," 1",{"type":30,"tag":1881,"props":8896,"children":8897},{"style":2226},[8898],{"type":39,"value":2555},{"type":30,"tag":1881,"props":8900,"children":8901},{"style":1954},[8902],{"type":39,"value":2645},{"type":30,"tag":1881,"props":8904,"children":8905},{"class":1883,"line":2217},[8906,8911,8915,8920,8924],{"type":30,"tag":1881,"props":8907,"children":8908},{"style":1937},[8909],{"type":39,"value":8910},"          throw",{"type":30,"tag":1881,"props":8912,"children":8913},{"style":2247},[8914],{"type":39,"value":2250},{"type":30,"tag":1881,"props":8916,"children":8917},{"style":1921},[8918],{"type":39,"value":8919}," SlotAlreadyHeldError",{"type":30,"tag":1881,"props":8921,"children":8922},{"style":2226},[8923],{"type":39,"value":4991},{"type":30,"tag":1881,"props":8925,"children":8926},{"style":1954},[8927],{"type":39,"value":2274},{"type":30,"tag":1881,"props":8929,"children":8930},{"class":1883,"line":2277},[8931],{"type":30,"tag":1881,"props":8932,"children":8933},{"style":1954},[8934],{"type":39,"value":8935},"        }\n",{"type":30,"tag":1881,"props":8937,"children":8938},{"class":1883,"line":2390},[8939],{"type":30,"tag":1881,"props":8940,"children":8941},{"style":1954},[8942],{"type":39,"value":3064},{"type":30,"tag":1881,"props":8944,"children":8945},{"class":1883,"line":2460},[8946,8951,8956,8960,8965],{"type":30,"tag":1881,"props":8947,"children":8948},{"style":1954},[8949],{"type":39,"value":8950},"      {",{"type":30,"tag":1881,"props":8952,"children":8953},{"style":2226},[8954],{"type":39,"value":8955}," isolationLevel",{"type":30,"tag":1881,"props":8957,"children":8958},{"style":2308},[8959],{"type":39,"value":1997},{"type":30,"tag":1881,"props":8961,"children":8962},{"style":2262},[8963],{"type":39,"value":8964}," 'Serializable'",{"type":30,"tag":1881,"props":8966,"children":8967},{"style":1954},[8968],{"type":39,"value":4395},{"type":30,"tag":1881,"props":8970,"children":8971},{"class":1883,"line":2522},[8972,8976],{"type":30,"tag":1881,"props":8973,"children":8974},{"style":2226},[8975],{"type":39,"value":5612},{"type":30,"tag":1881,"props":8977,"children":8978},{"style":1954},[8979],{"type":39,"value":2274},{"type":30,"tag":1881,"props":8981,"children":8982},{"class":1883,"line":2588},[8983],{"type":30,"tag":1881,"props":8984,"children":8985},{"style":1954},[8986],{"type":39,"value":3950},{"type":30,"tag":1881,"props":8988,"children":8989},{"class":1883,"line":2648},[8990],{"type":30,"tag":1881,"props":8991,"children":8992},{"style":1954},[8993],{"type":39,"value":3959},{"type":30,"tag":31,"props":8995,"children":8996},{},[8997],{"type":39,"value":8998},"avec l'exception typée dans le domaine :",{"type":30,"tag":1871,"props":9000,"children":9002},{"className":1873,"code":9001,"language":1875,"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",[9003],{"type":30,"tag":262,"props":9004,"children":9005},{"__ignoreMap":8},[9006,9014,9042,9082,9124,9154,9161],{"type":30,"tag":1881,"props":9007,"children":9008},{"class":1883,"line":1884},[9009],{"type":30,"tag":1881,"props":9010,"children":9011},{"style":1888},[9012],{"type":39,"value":9013},"// apps/api/src/domain/slot-hold/slot-already-held.error.ts\n",{"type":30,"tag":1881,"props":9015,"children":9016},{"class":1883,"line":955},[9017,9021,9025,9029,9034,9038],{"type":30,"tag":1881,"props":9018,"children":9019},{"style":1937},[9020],{"type":39,"value":1940},{"type":30,"tag":1881,"props":9022,"children":9023},{"style":1937},[9024],{"type":39,"value":1945},{"type":30,"tag":1881,"props":9026,"children":9027},{"style":1948},[9028],{"type":39,"value":8919},{"type":30,"tag":1881,"props":9030,"children":9031},{"style":1937},[9032],{"type":39,"value":9033}," extends",{"type":30,"tag":1881,"props":9035,"children":9036},{"style":1948},[9037],{"type":39,"value":6900},{"type":30,"tag":1881,"props":9039,"children":9040},{"style":1954},[9041],{"type":39,"value":1957},{"type":30,"tag":1881,"props":9043,"children":9044},{"class":1883,"line":1902},[9045,9049,9053,9058,9062,9066,9070,9074,9078],{"type":30,"tag":1881,"props":9046,"children":9047},{"style":1937},[9048],{"type":39,"value":1966},{"type":30,"tag":1881,"props":9050,"children":9051},{"style":1954},[9052],{"type":39,"value":2138},{"type":30,"tag":1881,"props":9054,"children":9055},{"style":1937},[9056],{"type":39,"value":9057},"public",{"type":30,"tag":1881,"props":9059,"children":9060},{"style":1937},[9061],{"type":39,"value":1985},{"type":30,"tag":1881,"props":9063,"children":9064},{"style":1988},[9065],{"type":39,"value":4331},{"type":30,"tag":1881,"props":9067,"children":9068},{"style":1994},[9069],{"type":39,"value":1997},{"type":30,"tag":1881,"props":9071,"children":9072},{"style":2150},[9073],{"type":39,"value":2153},{"type":30,"tag":1881,"props":9075,"children":9076},{"style":1954},[9077],{"type":39,"value":2176},{"type":30,"tag":1881,"props":9079,"children":9080},{"style":1954},[9081],{"type":39,"value":1957},{"type":30,"tag":1881,"props":9083,"children":9084},{"class":1883,"line":1911},[9085,9090,9094,9099,9103,9107,9111,9116,9120],{"type":30,"tag":1881,"props":9086,"children":9087},{"style":2150},[9088],{"type":39,"value":9089},"    super",{"type":30,"tag":1881,"props":9091,"children":9092},{"style":2226},[9093],{"type":39,"value":2138},{"type":30,"tag":1881,"props":9095,"children":9096},{"style":2262},[9097],{"type":39,"value":9098},"`Slot ",{"type":30,"tag":1881,"props":9100,"children":9101},{"style":2433},[9102],{"type":39,"value":2436},{"type":30,"tag":1881,"props":9104,"children":9105},{"style":2226},[9106],{"type":39,"value":4200},{"type":30,"tag":1881,"props":9108,"children":9109},{"style":2433},[9110],{"type":39,"value":2374},{"type":30,"tag":1881,"props":9112,"children":9113},{"style":2262},[9114],{"type":39,"value":9115}," is no longer available`",{"type":30,"tag":1881,"props":9117,"children":9118},{"style":2226},[9119],{"type":39,"value":2176},{"type":30,"tag":1881,"props":9121,"children":9122},{"style":1954},[9123],{"type":39,"value":2274},{"type":30,"tag":1881,"props":9125,"children":9126},{"class":1883,"line":1933},[9127,9131,9135,9140,9145,9150],{"type":30,"tag":1881,"props":9128,"children":9129},{"style":2302},[9130],{"type":39,"value":3826},{"type":30,"tag":1881,"props":9132,"children":9133},{"style":2308},[9134],{"type":39,"value":205},{"type":30,"tag":1881,"props":9136,"children":9137},{"style":2226},[9138],{"type":39,"value":9139},"name ",{"type":30,"tag":1881,"props":9141,"children":9142},{"style":1994},[9143],{"type":39,"value":9144},"=",{"type":30,"tag":1881,"props":9146,"children":9147},{"style":2262},[9148],{"type":39,"value":9149}," 'SlotAlreadyHeldError'",{"type":30,"tag":1881,"props":9151,"children":9152},{"style":1954},[9153],{"type":39,"value":2274},{"type":30,"tag":1881,"props":9155,"children":9156},{"class":1883,"line":1960},[9157],{"type":30,"tag":1881,"props":9158,"children":9159},{"style":1954},[9160],{"type":39,"value":3950},{"type":30,"tag":1881,"props":9162,"children":9163},{"class":1883,"line":1974},[9164],{"type":30,"tag":1881,"props":9165,"children":9166},{"style":1954},[9167],{"type":39,"value":3959},{"type":30,"tag":31,"props":9169,"children":9170},{},[9171,9173,9179,9181,9187,9189,9194,9196,9202,9204,9210],{"type":39,"value":9172},"Trois changements comptent. D'abord le recours à ",{"type":30,"tag":262,"props":9174,"children":9176},{"className":9175},[],[9177],{"type":39,"value":9178},"prisma.$transaction",{"type":39,"value":9180}," avec ",{"type":30,"tag":262,"props":9182,"children":9184},{"className":9183},[],[9185],{"type":39,"value":9186},"isolationLevel: 'Serializable'",{"type":39,"value":9188}," 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":30,"tag":262,"props":9190,"children":9192},{"className":9191},[],[9193],{"type":39,"value":8736},{"type":39,"value":9195}," conditionnel (avec ",{"type":30,"tag":262,"props":9197,"children":9199},{"className":9198},[],[9200],{"type":39,"value":9201},"where: { status: 'AVAILABLE' }",{"type":39,"value":9203},") 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":30,"tag":262,"props":9205,"children":9207},{"className":9206},[],[9208],{"type":39,"value":9209},"SlotAlreadyHeldError",{"type":39,"value":9211}," qui porte le contexte nécessaire aux couches supérieures.",{"type":30,"tag":31,"props":9213,"children":9214},{},[9215,9217,9222,9224,9230],{"type":39,"value":9216},"Quand je prompte Claude pour ce fix, je ne dis pas \"ajoute une transaction\". Je dis : ",{"type":30,"tag":42,"props":9218,"children":9219},{},[9220],{"type":39,"value":9221},"\"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":39,"value":9223}," 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":30,"tag":88,"props":9225,"children":9227},{"href":9226},"/fr/dette-technique/definition-of-done-qualite",[9228],{"type":39,"value":9229},"Definition of Done sur la qualité",{"type":39,"value":205},{"type":30,"tag":55,"props":9232,"children":9233},{},[],{"type":30,"tag":59,"props":9235,"children":9237},{"id":9236},"les-4-garde-fous-à-appliquer-dès-lundi",[9238],{"type":39,"value":9239},"Les 4 garde-fous à appliquer dès lundi",{"type":30,"tag":31,"props":9241,"children":9242},{},[9243],{"type":39,"value":9244},"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":30,"tag":31,"props":9246,"children":9247},{},[9248,9253,9255,9260],{"type":30,"tag":35,"props":9249,"children":9250},{},[9251],{"type":39,"value":9252},"Garde-fou 1 : la concurrence est-elle nommée explicitement ?",{"type":39,"value":9254}," Pour toute fonction qui lit puis écrit, je me pose la question : ",{"type":30,"tag":42,"props":9256,"children":9257},{},[9258],{"type":39,"value":9259},"\"Ce use case peut-il être appelé par 2 requêtes simultanées ? Si oui, que se passe-t-il ?\"",{"type":39,"value":9261}," Si la réponse est \"je ne sais pas\", la PR retourne en draft.",{"type":30,"tag":31,"props":9263,"children":9264},{},[9265,9270,9272,9277],{"type":30,"tag":35,"props":9266,"children":9267},{},[9268],{"type":39,"value":9269},"Garde-fou 2 : les écritures qui dépendent de lectures passent-elles par une transaction ?",{"type":39,"value":9271}," Pas de read-modify-write hors ",{"type":30,"tag":262,"props":9273,"children":9275},{"className":9274},[],[9276],{"type":39,"value":9178},{"type":39,"value":9278},". 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":30,"tag":31,"props":9280,"children":9281},{},[9282,9287,9289,9295,9297,9303,9305,9309],{"type":30,"tag":35,"props":9283,"children":9284},{},[9285],{"type":39,"value":9286},"Garde-fou 3 : les exceptions sont-elles typées et porteuses de contexte ?",{"type":39,"value":9288}," ",{"type":30,"tag":262,"props":9290,"children":9292},{"className":9291},[],[9293],{"type":39,"value":9294},"throw new Error('Slot not available')",{"type":39,"value":9296}," est insuffisant. ",{"type":30,"tag":262,"props":9298,"children":9300},{"className":9299},[],[9301],{"type":39,"value":9302},"throw new SlotAlreadyHeldError(slotId)",{"type":39,"value":9304}," 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":30,"tag":88,"props":9306,"children":9307},{"href":7069},[9308],{"type":39,"value":7072},{"type":39,"value":9310}," en aval.",{"type":30,"tag":31,"props":9312,"children":9313},{},[9314,9319,9321,9327,9329,9334,9336,9341],{"type":30,"tag":35,"props":9315,"children":9316},{},[9317],{"type":39,"value":9318},"Garde-fou 4 : un test de concurrence existe-t-il ?",{"type":39,"value":9320}," Pour toute méthode critique, j'exige un test Vitest qui soumet le use case en parallèle via ",{"type":30,"tag":262,"props":9322,"children":9324},{"className":9323},[],[9325],{"type":39,"value":9326},"Promise.all",{"type":39,"value":9328}," sur le même créneau, et qui vérifie que l'état final est cohérent (un seul ",{"type":30,"tag":262,"props":9330,"children":9332},{"className":9331},[],[9333],{"type":39,"value":7800},{"type":39,"value":9335},", une seule erreur ",{"type":30,"tag":262,"props":9337,"children":9339},{"className":9338},[],[9340],{"type":39,"value":9209},{"type":39,"value":9342},"). Si ce test n'existe pas, Claude ne l'a pas écrit. C'est à la review de l'exiger.",{"type":30,"tag":1871,"props":9344,"children":9346},{"className":1873,"code":9345,"language":1875,"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",[9347],{"type":30,"tag":262,"props":9348,"children":9349},{"__ignoreMap":8},[9350,9358,9390,9411,9445,9483,9519,9527,9534,9607,9676,9683,9718,9750,9807],{"type":30,"tag":1881,"props":9351,"children":9352},{"class":1883,"line":1884},[9353],{"type":30,"tag":1881,"props":9354,"children":9355},{"style":1888},[9356],{"type":39,"value":9357},"// Exemple de test de concurrence Vitest\n",{"type":30,"tag":1881,"props":9359,"children":9360},{"class":1883,"line":955},[9361,9366,9370,9375,9380,9385],{"type":30,"tag":1881,"props":9362,"children":9363},{"style":1921},[9364],{"type":39,"value":9365},"it",{"type":30,"tag":1881,"props":9367,"children":9368},{"style":2226},[9369],{"type":39,"value":2138},{"type":30,"tag":1881,"props":9371,"children":9372},{"style":2262},[9373],{"type":39,"value":9374},"'ne doit accorder le créneau qu'",{"type":30,"tag":1881,"props":9376,"children":9377},{"style":2226},[9378],{"type":39,"value":9379},"à un seul client en concurrence",{"type":30,"tag":1881,"props":9381,"children":9382},{"style":2262},[9383],{"type":39,"value":9384},"', async () => ",{"type":30,"tag":1881,"props":9386,"children":9388},{"style":9387},"--shiki-default:#A6D189;--shiki-default-font-style:inherit;--shiki-dark:#FDAEB7;--shiki-dark-font-style:italic",[9389],{"type":39,"value":2645},{"type":30,"tag":1881,"props":9391,"children":9392},{"class":1883,"line":1902},[9393,9398,9402,9407],{"type":30,"tag":1881,"props":9394,"children":9395},{"style":2226},[9396],{"type":39,"value":9397},"  const slotId ",{"type":30,"tag":1881,"props":9399,"children":9400},{"style":1994},[9401],{"type":39,"value":9144},{"type":30,"tag":1881,"props":9403,"children":9404},{"style":2262},[9405],{"type":39,"value":9406}," 'slot-test-id'",{"type":30,"tag":1881,"props":9408,"children":9409},{"style":2226},[9410],{"type":39,"value":2274},{"type":30,"tag":1881,"props":9412,"children":9413},{"class":1883,"line":1911},[9414,9419,9423,9427,9431,9435,9440],{"type":30,"tag":1881,"props":9415,"children":9416},{"style":2226},[9417],{"type":39,"value":9418},"  const results ",{"type":30,"tag":1881,"props":9420,"children":9421},{"style":1994},[9422],{"type":39,"value":9144},{"type":30,"tag":1881,"props":9424,"children":9425},{"style":1937},[9426],{"type":39,"value":2299},{"type":30,"tag":1881,"props":9428,"children":9429},{"style":6351},[9430],{"type":39,"value":2185},{"type":30,"tag":1881,"props":9432,"children":9433},{"style":2308},[9434],{"type":39,"value":205},{"type":30,"tag":1881,"props":9436,"children":9437},{"style":1921},[9438],{"type":39,"value":9439},"allSettled",{"type":30,"tag":1881,"props":9441,"children":9442},{"style":2226},[9443],{"type":39,"value":9444},"([\n",{"type":30,"tag":1881,"props":9446,"children":9447},{"class":1883,"line":1933},[9448,9453,9457,9461,9466,9470,9475,9479],{"type":30,"tag":1881,"props":9449,"children":9450},{"style":2226},[9451],{"type":39,"value":9452},"    holdSlotUseCase",{"type":30,"tag":1881,"props":9454,"children":9455},{"style":2308},[9456],{"type":39,"value":205},{"type":30,"tag":1881,"props":9458,"children":9459},{"style":1921},[9460],{"type":39,"value":5445},{"type":30,"tag":1881,"props":9462,"children":9463},{"style":2226},[9464],{"type":39,"value":9465},"(slotId",{"type":30,"tag":1881,"props":9467,"children":9468},{"style":1954},[9469],{"type":39,"value":2158},{"type":30,"tag":1881,"props":9471,"children":9472},{"style":2262},[9473],{"type":39,"value":9474}," 'client-A'",{"type":30,"tag":1881,"props":9476,"children":9477},{"style":2226},[9478],{"type":39,"value":2176},{"type":30,"tag":1881,"props":9480,"children":9481},{"style":1954},[9482],{"type":39,"value":2007},{"type":30,"tag":1881,"props":9484,"children":9485},{"class":1883,"line":1960},[9486,9490,9494,9498,9502,9506,9511,9515],{"type":30,"tag":1881,"props":9487,"children":9488},{"style":2226},[9489],{"type":39,"value":9452},{"type":30,"tag":1881,"props":9491,"children":9492},{"style":2308},[9493],{"type":39,"value":205},{"type":30,"tag":1881,"props":9495,"children":9496},{"style":1921},[9497],{"type":39,"value":5445},{"type":30,"tag":1881,"props":9499,"children":9500},{"style":2226},[9501],{"type":39,"value":9465},{"type":30,"tag":1881,"props":9503,"children":9504},{"style":1954},[9505],{"type":39,"value":2158},{"type":30,"tag":1881,"props":9507,"children":9508},{"style":2262},[9509],{"type":39,"value":9510}," 'client-B'",{"type":30,"tag":1881,"props":9512,"children":9513},{"style":2226},[9514],{"type":39,"value":2176},{"type":30,"tag":1881,"props":9516,"children":9517},{"style":1954},[9518],{"type":39,"value":2007},{"type":30,"tag":1881,"props":9520,"children":9521},{"class":1883,"line":1974},[9522],{"type":30,"tag":1881,"props":9523,"children":9524},{"style":2226},[9525],{"type":39,"value":9526},"  ]);\n",{"type":30,"tag":1881,"props":9528,"children":9529},{"class":1883,"line":2010},[9530],{"type":30,"tag":1881,"props":9531,"children":9532},{"emptyLinePlaceholder":13},[9533],{"type":39,"value":1908},{"type":30,"tag":1881,"props":9535,"children":9536},{"class":1883,"line":2040},[9537,9542,9546,9551,9555,9560,9564,9568,9573,9577,9581,9586,9590,9594,9598,9603],{"type":30,"tag":1881,"props":9538,"children":9539},{"style":2226},[9540],{"type":39,"value":9541},"  const fulfilled ",{"type":30,"tag":1881,"props":9543,"children":9544},{"style":1994},[9545],{"type":39,"value":9144},{"type":30,"tag":1881,"props":9547,"children":9548},{"style":2226},[9549],{"type":39,"value":9550}," results",{"type":30,"tag":1881,"props":9552,"children":9553},{"style":2308},[9554],{"type":39,"value":205},{"type":30,"tag":1881,"props":9556,"children":9557},{"style":1921},[9558],{"type":39,"value":9559},"filter",{"type":30,"tag":1881,"props":9561,"children":9562},{"style":2226},[9563],{"type":39,"value":2138},{"type":30,"tag":1881,"props":9565,"children":9566},{"style":1954},[9567],{"type":39,"value":2138},{"type":30,"tag":1881,"props":9569,"children":9570},{"style":1988},[9571],{"type":39,"value":9572},"r",{"type":30,"tag":1881,"props":9574,"children":9575},{"style":1954},[9576],{"type":39,"value":2176},{"type":30,"tag":1881,"props":9578,"children":9579},{"style":1994},[9580],{"type":39,"value":5238},{"type":30,"tag":1881,"props":9582,"children":9583},{"style":2226},[9584],{"type":39,"value":9585}," r",{"type":30,"tag":1881,"props":9587,"children":9588},{"style":2308},[9589],{"type":39,"value":205},{"type":30,"tag":1881,"props":9591,"children":9592},{"style":2226},[9593],{"type":39,"value":2540},{"type":30,"tag":1881,"props":9595,"children":9596},{"style":1994},[9597],{"type":39,"value":2545},{"type":30,"tag":1881,"props":9599,"children":9600},{"style":2262},[9601],{"type":39,"value":9602}," 'fulfilled'",{"type":30,"tag":1881,"props":9604,"children":9605},{"style":2226},[9606],{"type":39,"value":6994},{"type":30,"tag":1881,"props":9608,"children":9609},{"class":1883,"line":2070},[9610,9615,9619,9623,9627,9631,9635,9639,9643,9647,9651,9655,9659,9663,9667,9672],{"type":30,"tag":1881,"props":9611,"children":9612},{"style":2226},[9613],{"type":39,"value":9614},"  const rejected ",{"type":30,"tag":1881,"props":9616,"children":9617},{"style":1994},[9618],{"type":39,"value":9144},{"type":30,"tag":1881,"props":9620,"children":9621},{"style":2226},[9622],{"type":39,"value":9550},{"type":30,"tag":1881,"props":9624,"children":9625},{"style":2308},[9626],{"type":39,"value":205},{"type":30,"tag":1881,"props":9628,"children":9629},{"style":1921},[9630],{"type":39,"value":9559},{"type":30,"tag":1881,"props":9632,"children":9633},{"style":2226},[9634],{"type":39,"value":2138},{"type":30,"tag":1881,"props":9636,"children":9637},{"style":1954},[9638],{"type":39,"value":2138},{"type":30,"tag":1881,"props":9640,"children":9641},{"style":1988},[9642],{"type":39,"value":9572},{"type":30,"tag":1881,"props":9644,"children":9645},{"style":1954},[9646],{"type":39,"value":2176},{"type":30,"tag":1881,"props":9648,"children":9649},{"style":1994},[9650],{"type":39,"value":5238},{"type":30,"tag":1881,"props":9652,"children":9653},{"style":2226},[9654],{"type":39,"value":9585},{"type":30,"tag":1881,"props":9656,"children":9657},{"style":2308},[9658],{"type":39,"value":205},{"type":30,"tag":1881,"props":9660,"children":9661},{"style":2226},[9662],{"type":39,"value":2540},{"type":30,"tag":1881,"props":9664,"children":9665},{"style":1994},[9666],{"type":39,"value":2545},{"type":30,"tag":1881,"props":9668,"children":9669},{"style":2262},[9670],{"type":39,"value":9671}," 'rejected'",{"type":30,"tag":1881,"props":9673,"children":9674},{"style":2226},[9675],{"type":39,"value":6994},{"type":30,"tag":1881,"props":9677,"children":9678},{"class":1883,"line":2100},[9679],{"type":30,"tag":1881,"props":9680,"children":9681},{"emptyLinePlaceholder":13},[9682],{"type":39,"value":1908},{"type":30,"tag":1881,"props":9684,"children":9685},{"class":1883,"line":2114},[9686,9691,9696,9700,9705,9709,9714],{"type":30,"tag":1881,"props":9687,"children":9688},{"style":1921},[9689],{"type":39,"value":9690},"  expect",{"type":30,"tag":1881,"props":9692,"children":9693},{"style":2226},[9694],{"type":39,"value":9695},"(fulfilled)",{"type":30,"tag":1881,"props":9697,"children":9698},{"style":2308},[9699],{"type":39,"value":205},{"type":30,"tag":1881,"props":9701,"children":9702},{"style":1921},[9703],{"type":39,"value":9704},"toHaveLength",{"type":30,"tag":1881,"props":9706,"children":9707},{"style":2226},[9708],{"type":39,"value":2138},{"type":30,"tag":1881,"props":9710,"children":9711},{"style":3451},[9712],{"type":39,"value":9713},"1",{"type":30,"tag":1881,"props":9715,"children":9716},{"style":2226},[9717],{"type":39,"value":6994},{"type":30,"tag":1881,"props":9719,"children":9720},{"class":1883,"line":2122},[9721,9725,9730,9734,9738,9742,9746],{"type":30,"tag":1881,"props":9722,"children":9723},{"style":1921},[9724],{"type":39,"value":9690},{"type":30,"tag":1881,"props":9726,"children":9727},{"style":2226},[9728],{"type":39,"value":9729},"(rejected)",{"type":30,"tag":1881,"props":9731,"children":9732},{"style":2308},[9733],{"type":39,"value":205},{"type":30,"tag":1881,"props":9735,"children":9736},{"style":1921},[9737],{"type":39,"value":9704},{"type":30,"tag":1881,"props":9739,"children":9740},{"style":2226},[9741],{"type":39,"value":2138},{"type":30,"tag":1881,"props":9743,"children":9744},{"style":3451},[9745],{"type":39,"value":9713},{"type":30,"tag":1881,"props":9747,"children":9748},{"style":2226},[9749],{"type":39,"value":6994},{"type":30,"tag":1881,"props":9751,"children":9752},{"class":1883,"line":2208},[9753,9757,9762,9766,9771,9775,9780,9784,9788,9793,9797,9802],{"type":30,"tag":1881,"props":9754,"children":9755},{"style":1921},[9756],{"type":39,"value":9690},{"type":30,"tag":1881,"props":9758,"children":9759},{"style":2226},[9760],{"type":39,"value":9761},"((rejected[",{"type":30,"tag":1881,"props":9763,"children":9764},{"style":3451},[9765],{"type":39,"value":746},{"type":30,"tag":1881,"props":9767,"children":9768},{"style":2226},[9769],{"type":39,"value":9770},"] ",{"type":30,"tag":1881,"props":9772,"children":9773},{"style":1937},[9774],{"type":39,"value":5405},{"type":30,"tag":1881,"props":9776,"children":9777},{"style":1948},[9778],{"type":39,"value":9779}," PromiseRejectedResult",{"type":30,"tag":1881,"props":9781,"children":9782},{"style":2226},[9783],{"type":39,"value":2176},{"type":30,"tag":1881,"props":9785,"children":9786},{"style":2308},[9787],{"type":39,"value":205},{"type":30,"tag":1881,"props":9789,"children":9790},{"style":2226},[9791],{"type":39,"value":9792},"reason)",{"type":30,"tag":1881,"props":9794,"children":9795},{"style":2308},[9796],{"type":39,"value":205},{"type":30,"tag":1881,"props":9798,"children":9799},{"style":1921},[9800],{"type":39,"value":9801},"toBeInstanceOf",{"type":30,"tag":1881,"props":9803,"children":9804},{"style":2226},[9805],{"type":39,"value":9806},"(SlotAlreadyHeldError);\n",{"type":30,"tag":1881,"props":9808,"children":9809},{"class":1883,"line":2217},[9810,9815],{"type":30,"tag":1881,"props":9811,"children":9812},{"style":2226},[9813],{"type":39,"value":9814},"})",{"type":30,"tag":1881,"props":9816,"children":9817},{"style":1954},[9818],{"type":39,"value":2274},{"type":30,"tag":31,"props":9820,"children":9821},{},[9822],{"type":39,"value":9823},"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":30,"tag":55,"props":9825,"children":9826},{},[],{"type":30,"tag":59,"props":9828,"children":9829},{"id":639},[9830],{"type":39,"value":642},{"type":30,"tag":31,"props":9832,"children":9833},{},[9834],{"type":39,"value":9835},"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":30,"tag":537,"props":9837,"children":9838},{},[9839,9858],{"type":30,"tag":541,"props":9840,"children":9841},{},[9842],{"type":30,"tag":545,"props":9843,"children":9844},{},[9845,9849,9853],{"type":30,"tag":549,"props":9846,"children":9847},{},[9848],{"type":39,"value":661},{"type":30,"tag":549,"props":9850,"children":9851},{},[9852],{"type":39,"value":7386},{"type":30,"tag":549,"props":9854,"children":9855},{},[9856],{"type":39,"value":9857},"Après 4 mois",{"type":30,"tag":560,"props":9859,"children":9860},{},[9861,9879,9896,9914],{"type":30,"tag":545,"props":9862,"children":9863},{},[9864,9869,9874],{"type":30,"tag":567,"props":9865,"children":9866},{},[9867],{"type":39,"value":9868},"Bugs de concurrence trouvés en review",{"type":30,"tag":567,"props":9870,"children":9871},{},[9872],{"type":39,"value":9873},"2 par mois en moyenne",{"type":30,"tag":567,"props":9875,"children":9876},{},[9877],{"type":39,"value":9878},"11 par mois en moyenne",{"type":30,"tag":545,"props":9880,"children":9881},{},[9882,9887,9892],{"type":30,"tag":567,"props":9883,"children":9884},{},[9885],{"type":39,"value":9886},"Bugs de concurrence remontés depuis la prod",{"type":30,"tag":567,"props":9888,"children":9889},{},[9890],{"type":39,"value":9891},"5 par trimestre",{"type":30,"tag":567,"props":9893,"children":9894},{},[9895],{"type":39,"value":741},{"type":30,"tag":545,"props":9897,"children":9898},{},[9899,9904,9909],{"type":30,"tag":567,"props":9900,"children":9901},{},[9902],{"type":39,"value":9903},"Temps moyen de review d'une PR Claude",{"type":30,"tag":567,"props":9905,"children":9906},{},[9907],{"type":39,"value":9908},"8 minutes",{"type":30,"tag":567,"props":9910,"children":9911},{},[9912],{"type":39,"value":9913},"11 minutes",{"type":30,"tag":545,"props":9915,"children":9916},{},[9917,9922,9927],{"type":30,"tag":567,"props":9918,"children":9919},{},[9920],{"type":39,"value":9921},"Confiance équipe dans le code IA-généré (sondage 1-10)",{"type":30,"tag":567,"props":9923,"children":9924},{},[9925],{"type":39,"value":9926},"6,2",{"type":30,"tag":567,"props":9928,"children":9929},{},[9930],{"type":39,"value":9931},"8,1",{"type":30,"tag":31,"props":9933,"children":9934},{},[9935,9937,9942],{"type":39,"value":9936},"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":30,"tag":88,"props":9938,"children":9939},{"href":1099},[9940],{"type":39,"value":9941},"revue de code structurée et appliquée à l'ère IA",{"type":39,"value":9943}," permet d'enclencher : pas un contrôle qualité figé, mais un filet adaptatif qui suit là où l'IA produit ses angles morts.",{"type":30,"tag":55,"props":9945,"children":9946},{},[],{"type":30,"tag":392,"props":9948,"children":9950},{"cta":833,"href":834,"title":9949,"type":836},"Ces 4 garde-fous ne sont qu'un début : il en existe 100",[9951],{"type":30,"tag":31,"props":9952,"children":9953},{},[9954],{"type":39,"value":9955},"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":30,"tag":55,"props":9957,"children":9958},{},[],{"type":30,"tag":59,"props":9960,"children":9961},{"id":801},[9962],{"type":39,"value":804},{"type":30,"tag":31,"props":9964,"children":9965},{},[9966],{"type":39,"value":9967},"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":30,"tag":31,"props":9969,"children":9970},{},[9971],{"type":39,"value":9972},"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":30,"tag":31,"props":9974,"children":9975},{},[9976],{"type":39,"value":9977},"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":30,"tag":31,"props":9979,"children":9980},{},[9981,9983,9988],{"type":39,"value":9982},"Pour la suite des patterns craft + IA en format court, retrouvez-moi sur ",{"type":30,"tag":88,"props":9984,"children":9986},{"href":125,"rel":9985},[127],[9987],{"type":39,"value":130},{"type":39,"value":9989},", où je publie chaque semaine les pièges que je vois revenir en mission.",{"type":30,"tag":55,"props":9991,"children":9992},{},[],{"type":30,"tag":59,"props":9994,"children":9996},{"id":9995},"faq-sur-les-bugs-claude-et-la-review-ia-générée",[9997],{"type":39,"value":9998},"FAQ sur les bugs Claude et la review IA-générée",{"type":30,"tag":853,"props":10000,"children":10001},{},[10002,10007],{"type":30,"tag":857,"props":10003,"children":10004},{},[10005],{"type":39,"value":10006},"1. Comment justifier auprès de mon équipe le temps supplémentaire de review ?",{"type":30,"tag":31,"props":10008,"children":10009},{},[10010,10012,10016],{"type":39,"value":10011},"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":30,"tag":88,"props":10013,"children":10014},{"href":790},[10015],{"type":39,"value":793},{"type":39,"value":205},{"type":30,"tag":853,"props":10018,"children":10019},{},[10020,10025],{"type":30,"tag":857,"props":10021,"children":10022},{},[10023],{"type":39,"value":10024},"2. Faut-il refuser systématiquement les PR Claude qui touchent à l'état partagé ?",{"type":30,"tag":31,"props":10026,"children":10027},{},[10028],{"type":39,"value":10029},"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":30,"tag":853,"props":10031,"children":10032},{},[10033,10038],{"type":30,"tag":857,"props":10034,"children":10035},{},[10036],{"type":39,"value":10037},"3. Les tests automatisés ne devraient-ils pas attraper ces bugs ?",{"type":30,"tag":31,"props":10039,"children":10040},{},[10041,10043,10048,10050,10055],{"type":39,"value":10042},"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":30,"tag":262,"props":10044,"children":10046},{"className":10045},[],[10047],{"type":39,"value":9326},{"type":39,"value":10049}," sur la même ressource en Vitest), et ces tests, Claude ne les écrit jamais spontanément. C'est aussi ce que pointe ",{"type":30,"tag":88,"props":10051,"children":10052},{"href":1169},[10053],{"type":39,"value":10054},"la checklist pour tester du code généré par IA",{"type":39,"value":205},{"type":30,"tag":853,"props":10057,"children":10058},{},[10059,10064],{"type":30,"tag":857,"props":10060,"children":10061},{},[10062],{"type":39,"value":10063},"4. Quels autres patterns dangereux faut-il surveiller dans le code Claude ?",{"type":30,"tag":31,"props":10065,"children":10066},{},[10067],{"type":39,"value":10068},"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":30,"tag":853,"props":10070,"children":10071},{},[10072,10077],{"type":30,"tag":857,"props":10073,"children":10074},{},[10075],{"type":39,"value":10076},"5. Comment former mon équipe à voir ces bugs sans alourdir la charge cognitive ?",{"type":30,"tag":31,"props":10078,"children":10079},{},[10080],{"type":39,"value":10081},"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":30,"tag":853,"props":10083,"children":10084},{},[10085,10090],{"type":30,"tag":857,"props":10086,"children":10087},{},[10088],{"type":39,"value":10089},"6. Est-ce que ce problème va disparaître avec les prochaines versions de Claude ?",{"type":30,"tag":31,"props":10091,"children":10092},{},[10093],{"type":39,"value":10094},"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":30,"tag":55,"props":10096,"children":10097},{},[],{"type":30,"tag":392,"props":10099,"children":10100},{"cta":944,"href":945,"title":946,"type":947},[10101],{"type":30,"tag":31,"props":10102,"children":10103},{},[10104],{"type":39,"value":10105},"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":30,"tag":7689,"props":10107,"children":10108},{},[10109],{"type":39,"value":7693},{"title":8,"searchDepth":955,"depth":955,"links":10111},[10112,10113,10114,10115,10116,10117,10118],{"id":7759,"depth":955,"text":7762},{"id":7853,"depth":955,"text":7856},{"id":8460,"depth":955,"text":8463},{"id":9236,"depth":955,"text":9239},{"id":639,"depth":955,"text":642},{"id":801,"depth":955,"text":804},{"id":9995,"depth":955,"text":9998},"content:fr:intelligence-artificielle:bug-claude-vendredi-dernier.md","fr/intelligence-artificielle/bug-claude-vendredi-dernier.md","fr/intelligence-artificielle/bug-claude-vendredi-dernier",1782669274687]