La même PR, deux reviews différentes

Un développeur de mon réseau avait configuré Claude Code comme reviewer CI pour son code. « Demande juste à Claude de vérifier la PR », m’a-t-il dit. « Il attrape des choses que je laisserais passer. » Je lui ai demandé de faire passer la même PR deux fois dans Claude.

La première review disait que la gestion des erreurs semblait complète. La seconde la jugeait insuffisante et suggérait trois changements. Il a fixé son écran pendant cinq minutes en se demandant quel Claude avait raison.

Aucun n’avait raison. Aucun n’avait tort. Le LLM faisait des suppositions probabilistes, il n’appliquait pas des règles déterministes. Et c’est le problème fondamental de l’usage de l’IA pour la vérification : la vérification demande deux propriétés que les LLM n’ont pas. Le déterminisme : la même entrée produit toujours la même sortie. L’exhaustivité : tous les modes d’échec sont attrapés, à chaque fois.

Le problème du déterminisme

Faites passer le même code deux fois dans Claude Code et vous pouvez obtenir deux reviews différentes. Température, fenêtre de contexte, formulation du prompt, tout introduit de la variance. Pour le brainstorming, la variance est une qualité. Pour la vérification, c’est un bug. On ne construit pas un logiciel fiable sur des gates qualité probabilistes.

Les vérifications déterministes n’ont pas ce problème. tsc --noEmit produit toujours les mêmes erreurs. ESLint avec la même config remonte toujours les mêmes problèmes. Ces outils appliquent des règles, pas des probabilités. Ils sont ennuyeux. C’est pour ça qu’ils marchent.

La pile de garde-fous O(1)

Voici à quoi ressemble notre pile de pré-commit. Chaque vérification est déterministe. Chaque vérification s’exécute en millisecondes. Aucune ne se soucie de savoir si le code a été écrit par un humain ou par Claude Code :

# Pre-commit (< 1 second total)
TypeScript strict mode      # tsc --noEmit
ESLint boundary rules       # module isolation
Import restrictions         # dependency direction
dependency-cruiser          # graph analysis
Unit tests                  # contract verification

# CI (< 30 seconds)
Full test suite
Bundle size checks
Fresh clone launch test

La métrique clé, c’est O(1) par rapport à la taille de la codebase. Le type checking est incrémental. Le linting fonctionne fichier par fichier. dependency-cruiser analyse le graphe d’import de façon linéaire. Rien ne ralentit quand votre app vibe codée grandit. Les reviews Claude Code deviennent plus lentes et moins fiables à mesure que votre codebase dépasse la fenêtre de contexte.

Ce que les vérifications déterministes attrapent vraiment

La semaine dernière, dependency-cruiser a attrapé une PR dans laquelle un composant d’écran importait directement une implémentation de service au lieu du barrel. La PR compilait très bien. Les tests passaient. Cursor avait généré l’import automatiquement. Mais cela violait notre règle d’architecture : seul le composition root importe les implémentations.

Une review LLM aurait peut-être détecté ce problème. Ou peut-être pas, parce que la PR était grosse et que l’import était perdu au milieu du fichier. dependency-cruiser, lui, ne le rate jamais parce qu’il ne lit pas le code : il analyse un graphe.

// .dependency-cruiser.cjs
// 8 lines. 100ms. Catches this every time, forever.
{
  name: 'no-deep-service-imports',
  comment: 'Only service barrels are public.',
  severity: 'error',
  from: { pathNot: '^src/services/' },
  to: {
    path: '^src/services/[^/]+/',
    pathNot: '^src/services/[^/]+/index\.ts$',
  }
}

Huit lignes. Moins de cent millisecondes. Sur chaque PR. Pour toujours. Une review Claude Code coûte des tokens, prend plusieurs secondes et peut quand même passer à côté. Le calcul est sans appel.

Là où l’IA a vraiment sa place

Je ne suis pas anti-IA. J’utilise Cursor et Claude Code tous les jours, pour rédiger du code, explorer des approches, écrire des tests, déboguer. Mais je ne leur donne pas un rôle de vérification. La vérification doit être déterministe. Elle doit être ennuyeuse. Elle doit produire exactement le même résultat à chaque fois.

Les garde-fous doivent être invisibles et inévitables. Ils doivent attraper les problèmes sans que personne ait à penser à les lancer. C’est ce que donnent les vérifications déterministes : un filet de sécurité qui ne dort jamais, ne se fatigue jamais et ne perd jamais le contexte quand votre codebase grandit.

L’Autotomy Expo Starter Pack embarque TypeScript strict mode, les règles d’architecture ESLint, la configuration dependency-cruiser et des hooks de pré-commit, déjà câblés. Vous gardez la vitesse de Cursor pour générer. Vous obtenez la précision d’une machine pour vérifier. C’est comme ça qu’on vibe code sans casser la prod.