Il s'est noté lui-même : PASS
Le check de vérification intégré à Claude Code, /verify, a renvoyé un PASS sur une fonctionnalité qui était cassée. C'est le résultat d'un banc de 116 sessions Claude Code sur un dépôt réel, où chaque "terminé" a été noté après coup par des tests d'acceptation que l'agent n'a jamais vus.
Boris Cherny, qui a créé Claude Code, dit que la vérification est la chose la plus importante qu'on puisse lui donner. Le check intégré ne se lance que sur demande depuis Claude Code v2.1.215 : soit vous tapez /verify, soit il ne se lance pas. Sur ce banc, il a dit PASS dans 24 runs sur 24, et l'un de ces runs avait livré une fonctionnalité cassée. Ce qui a vraiment attrapé le bug est couvert plus bas, avec le dispositif qui a coûté deux fois et demi plus cher et n'a rien changé.
Le banc d'essai : 116 runs, des tests jamais vus
Un faux "terminé" est une session qui se termine en prétendant que le travail est fini alors qu'un test d'acceptation caché, ou la suite du dépôt lui-même, échoue. Le banc mesure la fréquence de ce phénomène sous six configurations de vérification.
Le doute derrière tout ça vient du propre tracker d'issues de Claude Code : l'issue #96416, déposée le 2026-09-23, décrit une review qui a listé 19 préoccupations, en a vérifié 5 et a quand même conclu "accept as is".
| Paramètre | Valeur |
|---|---|
| Dépôt | msiemens/tinydb (base de données de documents Python), commit 18d73a1 |
| Suite de tests du dépôt | 226 tests |
| Demandes de fonctionnalité | 6, chacune énonçant 5 exigences |
| Tests d'acceptation cachés | un par exigence énoncée, écrit avant tout run, jamais montré à l'agent |
| Modèles | Opus 5.5, Sonnet 5, Haiku 4.5 |
| Claude Code | 2.1.283, headless (claude -p), plafond de 60 tours |
| Sessions | 112 runs de tâche + 4 runs /verify inter-modèles = 116 |
| Dépense | $66.29 en équivalent API |
Les six configurations vont de Claude Code seul (juste la demande) à un second modèle qui vérifie le travail à l'arrêt :
| Configuration | Ce qu'elle ajoute |
|---|---|
| A plain | rien |
| B /verify | le /verify intégré tapé comme second tour |
| C verify skill | un skill de projet écrit selon le workflow d'Anthropic |
| D Stop hook | un script qui bloque l'arrêt tant que la suite est rouge et demande des preuves par exigence |
| E tests first | une règle CLAUDE.md : un test qui échoue par exigence avant tout code |
| F Opus verifier | un Stop hook qui lance /verify avec Opus sur le changement |
Des demandes claires sur une bibliothèque bien testée, c'est le cas facile. Opus 5.5 seul a réussi ses 12 runs sur 12, et il a lancé la suite de tests par lui-même dans 11 d'entre eux.
Le /verify intégré : PASS, à chaque fois, 2,5x
/verify est le skill de vérification livré avec Claude Code. Il lance le changement, lit le diff et écrit un verdict étape par étape. Depuis la v2.1.215, il n'est déclenché que par l'utilisateur, donc sur le banc il a été tapé après chaque tâche comme un second tour.
Il a renvoyé un verdict PASS dans 24 runs sur 24 à travers les trois modèles, y compris le changement cassé de Haiku. Sur Opus 5.5, il n'a changé aucun résultat et a coûté 2,5 fois plus cher :
| Opus 5.5, par tâche | Plain | Avec /verify |
|---|---|---|
| Coût | $0.39 | $0.96 |
| Temps réel | 75 s | 125 s |
| Résultats changés | 0 sur 12 |
Pour être honnête, /verify a trouvé un vrai bug : sur une tâche d'Opus, il a signalé un problème de réutilisation après fermeture déjà présent dans la bibliothèque, pas causé par le changement qu'il vérifiait. Sur un travail déjà correct, c'est un second avis coûteux.
Skill ou hook : celui qui se fait sauter
Un skill est une procédure markdown que Claude peut ouvrir quand il juge que c'est pertinent. Le billet de blog d'Anthropic sur les boucles de vérification décrit une recette en six étapes : repérer le suivi manuel qu'on fait le plus souvent, essayer d'abord le /verify intégré, écrire la procédure en anglais courant, en faire un skill, puis l'invoquer sur une nouvelle tâche et itérer. Le skill du banc, verify-change, a été construit exactement de cette façon et dit à Claude de prouver chaque exigence sur le vrai code avant de dire que c'est terminé.
Un skill est une suggestion, et c'est Claude qui décide de l'ouvrir ou non :
| Modèle | Sessions ayant ouvert le skill |
|---|---|
| Opus 5.5 | 8 sur 12 |
| Sonnet 5 | 2 sur 6 |
| Haiku 4.5 | 0 sur 6 |
| Total | 10 sur 24 |
Le seul faux "terminé" de Sonnet vient d'une session où le skill ne s'est jamais ouvert : elle s'est terminée avec deux de ses propres nouveaux tests en échec.
Un Stop hook est un script que Claude Code exécute chaque fois que l'agent essaie de terminer. Il peut refuser l'arrêt et renvoyer l'agent au travail avec une raison. Le hook du banc lance la suite de tests, bloque tant qu'elle est rouge, et au premier arrêt demande une ligne de preuve par exigence. Il s'est déclenché à chaque session. Sur Opus, il a coûté 20% de plus, $0.47 contre $0.39 par tâche (94 s contre 75 s). Dans ce banc, il n'a jamais rencontré de suite en échec au moment de l'arrêt, donc il n'avait rien à attraper : un hook se déclenche toujours, mais il ne vérifie que ce qu'on lui a dit de vérifier.
L'angle mort : 11 sur 11 ratés
La tâche qui a échoué demandait des champs uniques sur une table : deux utilisateurs ne peuvent pas partager un email, et toute mise à jour qui laisserait deux documents avec la même valeur unique doit lever DuplicateKeyError.
Haiku 4.5 a testé le déplacement d'un utilisateur vers l'email d'un autre utilisateur, et cela a été correctement refusé. Il n'a jamais testé une mise à jour qui correspond à plusieurs documents et écrit le même nouvel email sur tous. Ce cas est passé sans erreur dans 11 sessions Haiku sur 11, dans chaque configuration avec le même modèle : plain, /verify, le skill, le Stop hook et tests first.
Le propre /verify de Haiku a coché le cas qu'il avait essayé et écrit PASS. Le test caché a rapporté DID NOT RAISE DuplicateKeyError. Sonnet 5, invité à lancer /verify sur le même changement, a lui aussi renvoyé PASS. Opus et Sonnet ont tous deux écrit cette fonctionnalité correctement de leur côté, donc c'est un modèle sur une tâche, mais un check écrit par le même modèle partage son angle mort.
Le contrôle externe : Opus dit FAIL
Le même /verify, sur le même changement de Haiku, mais lancé par Opus 5.5, a renvoyé FAIL dans 3 runs sur 3, en nommant à chaque fois le cas manqué : une mise à jour qui correspond à plusieurs documents écrit la même valeur sur tous, sans erreur. L'attrape est venue d'un modèle différent, pas de l'auteur ni de son propre check.
Câblé comme Stop hook (configuration F), Opus vérifie le travail de Haiku à chaque fois que Haiku essaie de terminer. Les résultats :
| T6, par run | Haiku + vérificateur Opus | Opus 5.5 seul |
|---|---|---|
| Bug corrigé / faux "terminé" | corrigé dans 3 sur 3 | 0 faux "terminé" |
| Tours | plafond de 60 tours atteint à chaque run | |
| Coût | $1.36 avec le vérificateur inclus | $0.76 |
Le contrôle externe fonctionne. Sur cette tâche, il a coûté plus cher que le modèle le plus fort écrivant la fonctionnalité seul.
Ce qu'il faut retenir, et ce que ça coûte
Arrêtez de laisser le modèle qui a écrit un changement être le seul à le vérifier.
| Règle | Pourquoi | Coût sur ce banc |
|---|---|---|
| Garder un Stop hook pour tout ce qu'un script peut vérifier | il se déclenche à chaque session | environ 20% de plus sur Opus |
| Faire venir le vrai contrôle de l'extérieur de l'auteur : un modèle plus fort à la porte, ou vos propres tests écrits depuis la demande | le même modèle a raté son propre bug 11 fois sur 11 | $1.36 par tâche pour Haiku + vérificateur Opus |
Sur une demande claire avec Opus, sauter le /verify |
0 résultat changé | 2,5x le coût, 125 s contre 75 s |
Les limites : une petite bibliothèque, six demandes claires, un à trois runs par cellule, des sessions headless, et des tests cachés qui ne vérifient que ce que chaque demande énonce. Sur un travail plus désordonné, les chiffres bougeront.
AIDive