Quand relire le code devient difficile
Un agent produit plus de code qu'une équipe ne peut en relire. Entre tout relire et tout merger sans lire, une troisième voie : confier l'architecture, les conventions et les régressions à des guardrails outillés, et garder la review humaine pour l'intention.
Pendant des décennies, le code s’est écrit à la main, ligne par ligne. Écriture et relecture avançaient à des vitesses comparables : un développeur relisait en une heure ce qu’un collègue avait écrit en une journée.
En 2021, GitHub Copilot a introduit l’autocomplétion par IA : le modèle proposait la ligne suivante, le développeur l’acceptait ou la rejetait. Les assistants conversationnels ont ensuite généré des fonctions entières, copiées depuis une fenêtre de chat. Depuis 2025, les agents de code (Claude Code, Codex, Cursor) lisent la codebase, modifient des dizaines de fichiers, lancent les tests et ouvrent eux-mêmes la merge request.
L’écriture du code a changé d’échelle. Sa relecture, non : une merge request de mille lignes générées demande le même temps de review qu’une merge request de mille lignes écrites à la main. L’étude de SmartBear chez Cisco, sur 2 500 reviews, montre qu’au-delà de 400 lignes par session, ou d’environ 500 lignes à l’heure, un relecteur trouve nettement moins de défauts. Un agent produit désormais plus de code qu’une équipe ne peut en relire.
La review n’était pas seulement un contrôle qualité. C’est en relisant les merge requests de ses collègues qu’un développeur entretenait la représentation mentale de sa codebase : où vit chaque règle, pourquoi tel module existe, quel helper réutiliser. Bacchelli et Bird l’ont observé chez Microsoft en 2013 : la review trouve moins de défauts qu’on ne l’attend d’elle, et sert surtout à transmettre la connaissance du code dans l’équipe. Quand la review ne suit plus le volume, cette représentation ne disparaît pas d’un coup : elle se dégrade par capitulations successives. Le développeur relit en entier la première merge request générée. Il survole la dixième. Il approuve la cinquantième parce que les tests passent. Chaque renoncement se justifie sur le moment, et aucun n’est décidé comme une politique. Après quelques semaines, une partie du code n’a été relue par personne.
Cette pente a un moteur psychologique. Merger du code généré procure une récompense immédiate : la fonctionnalité existe, le ticket se ferme, en quelques minutes. Le coût de la non-relecture arrive plus tard et sans auteur désigné : un bug en production trois semaines après, un module que plus personne ne comprend. Entre une récompense certaine tout de suite et un coût incertain plus tard, le développeur choisit le merge. Le sentiment de vitesse fausse aussi le jugement : dans l’essai contrôlé de METR publié en 2025, des développeurs open source expérimentés estimaient que l’IA les avait accélérés de 20 %, alors qu’elle les avait ralentis de 19 %.
Face à cette problématique, deux approches dominent :
- Les partisans de la relecture intégrale, qui relisent chaque ligne générée. Ils conservent le contrôle, mais la review devient le goulot et le gain de productivité disparaît.
- Les partisans de la validation sans relecture, qui acceptent les merge requests sans les lire. Ils tiennent la cadence, et font du vibe coding, avec les problèmes décrits dans Le mirage du vibe coding.
En 2026, la relecture systématique est déjà minoritaire : dans l’enquête State of Code de Sonar (janvier 2026, plus de 1 100 développeurs), 96 % des répondants ne font pas entièrement confiance au code généré par IA, mais seuls 48 % déclarent le vérifier systématiquement avant de le committer. Plus de la moitié laissent donc passer au moins une partie du code généré sans l’avoir vérifiée.
Aucune des deux ne tient sur la durée. La première sacrifie la vitesse. La seconde a déjà un coût visible : le rapport DORA 2024 observe que chaque hausse de 25 % de l’adoption de l’IA dans une organisation s’accompagne d’une baisse de 7,2 % de la stabilité des livraisons.
Les utilisateurs les plus avancés des agents de code pratiquent une troisième approche, qui garde la vitesse de l’agent sans renoncer au contrôle. L’équipe d’OpenAI la décrit sous le nom de « harness engineering » : l’humain ne relit plus chaque ligne, il construit l’environnement de vérification dans lequel l’agent travaille. Cet article détaille cette approche en trois temps : décomposer ce qu’une review vérifie réellement, montrer que ces vérifications relèvent d’outils plutôt que d’une lecture humaine, puis organiser ces outils en guardrails autour de l’agent (soft et hard, deux boucles de feedback, un cliquet pour les codebases existantes).
À quoi sert une review ?
Une review de MR vérifie :
- l’architecture : couches, sens des dépendances, emplacement de chaque élément ;
- les principes SOLID et les conventions de l’équipe ;
- l’absence de régression dans le code existant ;
- la cohérence du design : composants, espacements, comportements ;
- l’intention : le changement fait ce qui était demandé, et les règles métier sont justes.
Les quatre premiers points ne dépendent pas du volume de code : ce sont des règles. Lire chaque ligne est le moyen le plus coûteux de les vérifier. Le cinquième demande un humain qui connaît le besoin.
Développeur versus Agent
Un développeur a intériorisé l’architecture et les principes du projet. Il sait que le domaine n’importe pas l’infrastructure, parce qu’il a assisté à la décision ou qu’une review le lui a rappelé.
L’agent démarre chaque session sans mémoire du projet. Il ne connaît des règles que ce qui est dans sa fenêtre de contexte, et il les applique de façon non déterministe : une consigne respectée au message 5 peut être ignorée au message 60 (tirage et dégradation du contexte, détaillés dans Le mirage du vibe coding). Laban et al. mesurent en 2025 une baisse moyenne de 39 % des performances des modèles en conversation multi-tours, due surtout à une perte de fiabilité d’un tour à l’autre.
Le volume rend la relecture ligne à ligne impossible. Ce qui rend la vérification nécessaire, c’est qu’aucune des quatre règles n’est garantie en sortie de l’agent.
Ces règles se vérifient par des outils
| Ce que vérifie la review | Outil qui peut le vérifier |
|---|---|
| Architecture | Règles de dépendances entre modules (dependency-cruiser, eslint-plugin-boundaries en TypeScript, ArchUnit en Java) |
| Principes et conventions | Linter, typecheck, règles de lint écrites pour le projet |
| Absence de régression | Tests unitaires, d’intégration, end-to-end |
| Cohérence du design | Régression visuelle par captures d’écran, lint des design tokens |
La cohérence du design n’est couverte qu’en partie : un outil détecte qu’un bouton a bougé de trois pixels, pas qu’une page détonne avec le reste de l’application. Les trois autres lignes se vérifient presque entièrement sans humain. Neal Ford, Rebecca Parsons et Patrick Kua appellent ces vérifications automatisées de l’architecture des fitness functions, dans Building Evolutionary Architectures.
Exemple sur un front React en architecture hexagonale. Chaque feature est découpée en quatre couches : domain/, application/, infrastructure/, ui/. Les dépendances pointent vers le domaine : ui → application → domain, et infrastructure → domain. domain/ déclare des ports (des interfaces), infrastructure/ les implémente, et application/ ne manipule que ces ports. La règle ESLint import/no-restricted-paths interdit chaque import à contre-sens :
"import/no-restricted-paths": ["error", {
"zones": [
{
"target": "./src/features/*/domain/**",
"from": [
"./src/features/*/application/**",
"./src/features/*/infrastructure/**",
"./src/features/*/ui/**"
],
"message": "domain/ ne dépend d'aucune autre couche : types, ports et règles métier uniquement."
},
{
"target": "./src/features/*/application/**",
"from": [
"./src/features/*/infrastructure/**",
"./src/features/*/ui/**"
],
"message": "application/ passe par les ports de domain/, jamais par infrastructure/ ni ui/."
}
]
}]
Si l’agent importe un adapter HTTP de infrastructure/ depuis un fichier de domain/ ou d’application/, le linter échoue et affiche le fichier, la ligne et le message. La règle porte sur le chemin résolu : un import relatif ../ et un alias ~/ sont bloqués de la même façon, à condition que le resolver d’ESLint connaisse l’alias. Un import direct d’axios dans domain/ relève d’une autre règle, no-restricted-imports. Le message est écrit pour celui qui lit l’erreur, c’est-à-dire l’agent : il dit quelle règle est violée et dans quel sens corriger. C’est la pratique décrite par OpenAI dans « Harness engineering » : les messages de leurs lints sur mesure contiennent la consigne de correction destinée à l’agent.
Le code s’exécute, contrairement à la plupart des sorties d’un modèle. Il compile ou non, les tests passent ou non, et l’agent reçoit ce verdict au tour suivant, sans attendre un humain. À mon sens, c’est ce qui a fait progresser les agents de code plus vite que les autres usages de l’IA. Andrej Karpathy formule la même idée : le logiciel 2.0 automatise facilement ce qu’on peut vérifier, et les tâches vérifiables, comme le code, progressent plus vite que les autres.
La review humaine se concentre alors sur ce qu’aucun outil ne vérifie : l’intention du changement et les règles métier. La fonctionnalité fait-elle ce que le client a demandé ? Le calcul du prorata à la résiliation est-il juste ? Vérifier qu’un contrôleur n’importe pas directement le repository ne demande pas d’humain.
Les guardrails
Un guardrail vérifie le code produit par l’agent et le bloque ou le fait corriger quand une règle est violée.
Soft et hard
Les guardrails soft sont les instructions : CLAUDE.md, AGENTS.md, skills, règles de l’éditeur. Injectés dans le contexte, ils subissent le même tirage et la même dégradation que le reste. Un CLAUDE.md qui exige l’architecture hexagonale augmente la probabilité que l’agent la respecte, sans la garantir.
Les guardrails hard sont les outils : linter, typecheck, tests, règles d’architecture, CI. Même code, même verdict, quel que soit l’état du contexte de l’agent.
| Soft (instructions) | Hard (outils) | |
|---|---|---|
| Coût de mise en place | Faible : quelques paragraphes de markdown | Élevé : écrire des règles, des tests, configurer la CI |
| Couverture | Large : tout ce qui s’exprime en langage naturel, y compris le style et l’intention | Limitée à ce qui se formalise en règle vérifiable |
| Déterminisme | Nul : appliqué selon le tirage et l’état du contexte | Total : même entrée, même verdict |
| Feedback donné à l’agent | Aucun : l’agent ne sait pas qu’il a dérogé | Précis : fichier, ligne, règle violée |
Le soft oriente l’agent avant qu’il écrive. Le hard bloque ce qui passe quand même. Une règle qui compte doit exister côté hard : inscrite seulement dans un CLAUDE.md, elle reste une recommandation.
Le feedback est la ligne décisive du tableau. Une erreur de type tient en trois lignes et désigne le problème. Sans elle, l’agent relit dix fichiers pour le trouver, et ces fichiers occupent sa fenêtre de contexte jusqu’à la fin de la session.
Deux boucles de feedback
Boucle rapide, scope local. Linter, typecheck, formatage, à chaque modification de fichier. Avec Claude Code, un hook PostToolUse sur les outils d’écriture lance le linter sur le fichier modifié et renvoie les erreurs à l’agent, qui corrige avant de passer au fichier suivant. Durée : quelques secondes. Elle attrape les erreurs locales : import interdit, type faux, convention de nommage. Les auteurs de SWE-agent ont intégré le même mécanisme à leur agent : un linter tourne après chaque édition et rejette celles qui introduisent une erreur, ce qui limite les erreurs en cascade.
Boucle lente, scope global. Suites de tests complètes, CI, régression visuelle, avant la merge. Durée : plusieurs minutes. Elle attrape les effets croisés : une modification correcte dans le module A qui casse un comportement du module B.
Tout mettre dans la boucle lente laisse l’agent empiler trente fichiers sur une erreur commise au premier. Tout mettre dans la boucle rapide est impossible : une suite end-to-end de vingt minutes ne tourne pas à chaque sauvegarde. Chaque vérification va dans la boucle la plus rapide capable de l’exécuter.
Brownfield : le cliquet
Sur un projet neuf, une règle activée dès le premier commit ne coûte rien. Sur une codebase existante, la même règle remonte huit cents violations le jour de son activation. Personne ne les corrige, la règle reste désactivée, et l’agent en ajoute. Google en a fait l’expérience avec FindBugs : 84 % des bugs signalés hors du workflow des développeurs n’ont jamais été corrigés (Sadowski et al., 2018).
Le cliquet enregistre le nombre actuel de violations, par règle et par fichier, comme référence. La CI échoue si ce nombre augmente. Quand il baisse, la référence est mise à jour. La dette existante est tolérée, sa croissance non.
Outils existants : la baseline de PHPStan (PHP), Betterer (TypeScript). Le mécanisme tient aussi en quelques dizaines de lignes de script autour de n’importe quel linter qui compte ses erreurs.
L’agent n’a pas besoin de connaître l’historique du projet ni de distinguer code mort et code vivant : il ne peut pas ajouter de violation. Chaque violation qu’il corrige au passage abaisse la référence.
La machine vérifie les règles, l’humain relit l’intention
Les guardrails ne rendent pas l’agent déterministe. Ils rendent déterministe ce qui sort de la boucle : le code passe ou ne passe pas.
Architecture, conventions et régressions sont vérifiées par des outils, à chaque modification et avant chaque merge. La review humaine porte sur ce qu’aucun outil ne juge : ce que le code est censé faire, et les règles métier.
Cette répartition répond aussi à la perte de connaissance décrite en introduction. Les règles d’architecture ne vivent plus seulement dans la mémoire des développeurs qui relisaient : elles sont écrites dans la configuration du linter et dans les tests, où un nouvel arrivant les lit comme l’agent les subit. La review d’intention garde l’humain au contact de ce qui change dans le produit, c’est-à-dire là où la connaissance de l’équipe a le plus de valeur.
Références
- GitHub, « Introducing GitHub Copilot: your AI pair programmer », 29 juin 2021 : https://github.blog/news-insights/product-news/introducing-github-copilot-ai-pair-programmer/
- Anthropic, « Claude 3.7 Sonnet and Claude Code », 24 février 2025 : https://www.anthropic.com/news/claude-3-7-sonnet
- OpenAI, « Introducing Codex », mai 2025 : https://openai.com/index/introducing-codex/
- SmartBear, « Best Practices for Code Review » (étude Cisco, 2 500 reviews) : https://smartbear.com/learn/code-review/best-practices-for-peer-code-review/
- Bacchelli et Bird, « Expectations, Outcomes, and Challenges of Modern Code Review », ICSE 2013 : https://www.microsoft.com/en-us/research/publication/expectations-outcomes-and-challenges-of-modern-code-review/
- Becker et al. (METR), « Measuring the Impact of Early-2025 AI on Experienced Open-Source Developer Productivity », juillet 2025 : https://arxiv.org/abs/2507.09089
- Sonar, « State of Code Developer Survey », janvier 2026 (lien à ajouter)
- DORA, « Accelerate State of DevOps Report 2024 » : https://dora.dev/research/2024/dora-report/
- Laban et al., « LLMs Get Lost In Multi-Turn Conversation », mai 2025 : https://arxiv.org/abs/2505.06120
- Ford, Parsons, Kua, Sadalage, « Building Evolutionary Architectures », O’Reilly : https://books.google.com/books/about/Building_Evolutionary_Architectures.html?id=CGudEAAAQBAJ
- OpenAI, « Harness engineering: leveraging Codex in an agent-first world », février 2026 : https://openai.com/index/harness-engineering/
- Andrej Karpathy, tweet de novembre 2025 sur la vérifiabilité : https://x.com/karpathy/status/1990116666194456651
- Anthropic, documentation des hooks Claude Code : https://code.claude.com/docs/en/hooks
- Yang et al., « SWE-agent: Agent-Computer Interfaces Enable Automated Software Engineering », 2024 : https://arxiv.org/abs/2405.15793
- Sadowski et al., « Lessons from Building Static Analysis Tools at Google », Communications of the ACM, 2018 : https://cacm.acm.org/research/lessons-from-building-static-analysis-tools-at-google/
- PHPStan, « The Baseline » : https://phpstan.org/user-guide/baseline
- Betterer : https://phenomnomnominal.github.io/betterer/