Quand l'IA dit "c'est fait", le dispositif qui refuse de la croire
Les agents de codage IA disent que le travail est terminé alors qu'il ne l'est pas. Ils annoncent des tests réussis sans les avoir lancés, un bug corrigé sans l'avoir reproduit. L'histoire du garde-fou de vérification qu'un développeur solo, qui écrit presque tout son code avec l'IA, a mis en place pour n'accepter le "terminé" que sur preuves, jamais sur parole.
L'essentiel
La plus dangereuse habitude d'un agent IA, c'est d'annoncer terminé un travail qui ne l'est pas. La solution n'est pas que l'humain doute à chaque fois, mais d'ancrer dans le système un poste de contrôle qui n'accepte le "terminé" que sur preuves. Le hook qui bloque la fin de tour, les types de preuve (sortie de commande, diff, reproduction, vérification croisée), et pourquoi c'est le muscle clé de l'ère de l'IA.
Sur cette page
En travaillant avec des agents de codage IA, il y a une phrase qui me trompe plus souvent que toutes les autres. "C'est fait."
L'agent la sort beaucoup trop facilement. Sans avoir réellement lancé les tests, il dit "les tests devraient passer" ; sans avoir reproduit le bug, il dit "j'ai corrigé la cause". Quand on lit le code, ça a l'air plausible. Mais quand on lance vraiment les commandes, la moitié du temps ce n'est pas terminé. Après avoir vécu ça longtemps, j'en suis arrivé à une conclusion. Le problème n'est pas que l'IA ment, c'est que je décidais moi-même, à chaque fois, si je devais la croire ou non.
Ce n'est pas une question de confiance, mais de preuve
Je travaille seul et j'écris presque tout mon code avec l'IA. Du coup, je décide des dizaines de fois par jour "puis-je accepter ce changement". Au début, à chaque fois, je lisais le compte rendu de l'agent et, si un doute subsistait, je lançais moi-même les commandes pour vérifier. Le problème de cette méthode, c'est que la vérification repose sur moi. Un jour fatigué, un jour pressé, le jour où j'enchaîne le dixième travail similaire, je me dis "il a dit que c'était bon, alors ça doit l'être" et je laisse passer. Et l'accident vient toujours de ce que j'ai laissé passer comme ça.
Alors j'ai changé de direction. Au lieu que je doute à chaque fois, j'ai fait en sorte que le système exige des preuves. J'ai ancré dans le harnais un poste de contrôle qui empêche l'agent de terminer son tour sur la seule affirmation que "c'est fait". Le "terminé" est devenu non plus une déclaration, mais un contrôle à passer.
La racine de cette idée est simple. Plus l'IA produit du code à bas coût, plus le goulot d'étranglement se déplace de la production vers la vérification. Quand le coût de fabrication du code tend vers zéro, "vérifier que c'est correct" devient, relativement, la tâche la plus chère. Dans ce cas, cette tâche coûteuse ne doit pas dépendre de l'humeur du moment de l'humain : elle doit devenir une procédure imposée automatiquement.
Le hook qui bloque la fin de tour
Concrètement, j'utilise un hook qui s'intercale au moment de la fin de tour. Quand l'agent déclare son travail terminé et s'apprête à conclure son tour, juste avant, un contrôle se lance. Ce que ce contrôle exige tient en une phrase : "Produis la preuve que c'est fait."
Sans preuve, la fin de tour est refusée. L'agent est renvoyé en arrière, avec le message : "Tu n'as pas prouvé que c'était terminé, continue." L'agent lance alors, enfin, les tests, exécute les commandes, colle les sorties. Le plus drôle, c'est qu'au cours de ce processus, dans la moitié des cas, il dit de lui-même "ah, en fait ce n'est pas encore terminé" et finit réellement le travail qui restait. Ce n'était pas vraiment fini au moment où il avait dit que c'était fini.
L'essentiel, c'est que ce poste de contrôle est une machine, pas un humain. Que je sois fatigué ou pressé, le poste reste tout aussi exigeant. Ma discipline vacille, celle du hook non. J'ai fait de la vérification une infrastructure plutôt qu'une habitude.
Qu'est-ce qui est accepté comme preuve
Alors qu'est-ce que j'accepte comme "preuve" ? J'en utilise quatre types.
- La sortie de commande. Si les tests sont passés, il faut la sortie réelle du lanceur de tests. Pas un "ça va passer", mais le log d'une réussite. Si le build a fonctionné, le log de build ; si le lint est propre, la sortie du lint.
- Le diff. Ce qui a été modifié doit apparaître sous forme de diff. Pas un "j'ai corrigé cette fonction" en toutes lettres, mais les lignes modifiées telles quelles. C'est là qu'on filtre si l'étendue des changements correspond au compte rendu.
- La reproduction. Si un bug a été corrigé, il faut, en paire, la preuve qu'avant correction le bug se reproduisait réellement et la preuve qu'après correction il a disparu. Sans before/after, "c'est corrigé" n'est qu'une supposition.
- La vérification croisée. Pour les changements importants, je fais relire par un autre modèle. Codex regarde ce que Claude a écrit, et chacun pointe les angles morts de l'autre. On attrape bien plus de choses qu'avec un modèle qui juge son propre travail.
Le point commun de ces quatre types, c'est que ce sont tous des faits reproductibles. Pas des opinions, mais des sorties qu'on peut coller. C'est là qu'est la raison pour laquelle l'IA ne peut pas être le juge final. Définir le critère du "bon" et décider quelle sortie satisfait ce critère reste, au bout du compte, la part de l'humain. Simplement, au lieu de rendre ce verdict à la main à chaque fois, on fige la procédure de verdict dans du code.
Pourquoi c'est bon pour l'humain aussi
Après avoir dressé ce poste de contrôle, il y a eu un effet inattendu. Ce n'est pas seulement l'agent qui a gagné en discipline, moi aussi je me suis facilité la vie.
Avant, mon travail consistait à lire le compte rendu et à me demander "est-ce vraiment fait". Maintenant, c'est le hook qui fait ce travail. Au moment où le résultat m'arrive, la preuve y est déjà attachée. J'examine la preuve, je ne commence plus par vérifier s'il y en a une. La ligne de départ de mon jugement a avancé d'un cran.
Et c'est aussi une trace que je laisse au moi futur. Le pourquoi de la sûreté d'un changement reste consigné avec la sortie de commande de l'époque. Un mois plus tard, quand je me demande "pourquoi ai-je fait comme ça déjà", la justification est là, à côté du commit.
Le seul muscle nouveau à développer
On parle de toutes sortes de compétences pour travailler avec l'IA, mais ce qui m'est le plus resté, c'est ceci. Ne fais pas dépendre la vérification de toi-même, délègue-la au système.
L'art de bien rédiger un prompt vieillit dès que le modèle change. L'astuce qui marchait hier ne marche plus sur le nouveau modèle. En revanche, la discipline qui consiste à "n'accepter le terminé que sur preuves" est une couche au-dessus du modèle, alors elle ne vieillit pas. Quel que soit le modèle utilisé, quel que soit le nombre de générations franchies, le poste de contrôle qui exige des preuves garde toute son utilité. Au contraire, plus le modèle devient intelligent, plus il se trompe de façon plausible, et plus la valeur du poste de contrôle monte.
L'IA nous a déchargés du fardeau d'écrire le code. En échange, la tâche qu'elle nous laisse, c'est de décider "puis-je faire confiance à ceci". Si l'on veut rendre ce verdict à chaque fois à la seule force de la volonté humaine, on s'épuise et ça fuit. Mais si l'on fait en sorte qu'une machine exige des preuves, un poste de contrôle infatigable se tient là, exigeant, à ma place. Plus on confie de travail à l'IA, plus ce sur quoi il faut vraiment s'appliquer n'est pas "comment le lui confier" mais "comment vérifier son 'c'est fait'".
Articles similaires
- 💻 Dev
La remise que vous ne touchiez pas : pourquoi Spot et Graviton coûtent si peu
La facture AWS a dépassé le budget deux mois de suite. En cherchant quelle ressource couper, j'ai compris que le vrai levier n'était pas « combien on consomme » mais « comment on achète ». Pourquoi Spot et Graviton sont si peu chers, et pourquoi certains coûts qui ressemblent à du gaspillage (RDS Proxy) ne doivent surtout pas être coupés - l'histoire du « pourquoi » derrière chaque ligne de la facture.
- 💻 Dev
Les hooks d'arrêt tournaient deux fois - quand SIGTERM a deux maîtres
À chaque déploiement, Sentry recevait une erreur Prisma P2028. En corrigeant l'ordre d'arrêt, j'ai découvert qu'enableShutdownHooks de NestJS et une bibliothèque de graceful shutdown captaient toutes les deux SIGTERM, faisant tourner les hooks d'arrêt deux fois à chaque fois.
- 💻 Dev
« On n'a qu'à le désactiver en staging » - le vrai bug que cachait une alerte bruyante
Une alerte Google Play 404 qui tombait chaque jour en staging. Désactiver la source la fait taire, mais ce n'est pas la même chose que corriger le mode de défaillance. L'histoire d'un 404 - une erreur permanente qu'il ne sert à rien de réessayer - qui se retrouvait mélangé aux 5xx dans le même circuit de réessai.