La vitesse de l’AI sans safety stack finit en fragilité
Le vrai danger du code généré par AI n’est pas qu’il soit toujours faux.
Le vrai danger, c’est qu’il est souvent suffisamment plausible pour être mergé.
C’est précisément ce qui le rend risqué. Le code visiblement cassé est arrêté. Le code qui semble correct, passe quelques happy-path tests et affaiblit discrètement une boundary importante est celui qui atteint la production.
Si votre workflow se résume à prompt, paste, review, merge, chaque gain de vitesse en génération élargit l’écart entre la vitesse de changement du système et le niveau de confiance que vous pouvez avoir dans ce changement.
La solution n’est pas davantage d’héroïsme en code review. La solution est une safety stack en couches, capable de capter des classes de défaillances différentes à des moments différents.
Couche 1: Prevention avec types, schemas et contracts
Le bug le moins cher est celui que le programme ne peut même pas représenter.
C’est pour cela que la première couche est la prevention.
À ce niveau, vous réduisez la surface avant même que le comportement runtime n’entre en jeu:
- Branded types et phantom types empêchent de mélanger des valeurs structurellement proches mais sémantiquement différentes.
- Runtime schemas comme Zod protègent les frontières où des données non typées entrent dans le système.
- Contracts définissent preconditions, postconditions et invariants autour des chemins les plus critiques.
Avec AI-generated code, cette couche devient encore plus importante, parce que les modèles produisent volontiers des implémentations superficiellement cohérentes qui commettent malgré tout des category mistakes. Si vos types et schemas sont faibles, le modèle a trop d’espace pour être seulement “presque correct”.
Couche 2: Verification avec property-based tests
Les example tests sont utiles, mais trop faciles à overfitter, pour les humains comme pour les modèles.
Un modèle peut générer une fonction et son happy-path test correspondant. Dans un pull request, cela donne une impression de productivité. En pratique, le comportement reste sous-spécifié.
Property-based testing change la question. Au lieu de demander si une fonction marche sur trois exemples, on demande ce qui doit rester vrai sur des classes entières d’inputs.
Les meilleurs points de départ sont souvent:
- round trips
- idempotence
- invariants d’ordre
- monotonie
- comportement d’erreur correct sur invalid input
Ici, l’AI aide plutôt bien. Les modèles savent proposer un first draft de properties à partir d’une signature ou d’un doc comment. L’humain continue de review, mais le problème de la page blanche diminue fortement.
Couche 3: Assessment avec mutation testing
La coverage n’est pas une métrique de qualité. C’est une métrique d’exécution.
Mutation testing pose la question qui compte vraiment: si le code changeait d’une manière fautive mais plausible, vos tests le remarqueraient-ils?
C’est pour cela que mutation testing se place au-dessus des contracts et des property tests. Il ne les remplace pas. Il mesure s’ils ont vraiment des dents.
Cette couche est particulièrement importante à l’ère de l’AI, car les modèles peuvent produire des suites de tests impressionnantes visuellement, qui exécutent beaucoup de lignes mais valident peu de choses. Mutation testing rend cette fausse confiance visible.
L’approche pratique n’est pas d’exécuter une full mutation analysis partout, tout le temps. L’approche pratique est:
- commencer par les modules critiques
- utiliser incremental mutation testing sur le code modifié
- faire une triage agressive des survivors
- relever les thresholds au fur et à mesure que la suite mûrit
À l’ère AI, mutation testing est l’antidote contre la fausse confiance.
Couche 4: Runtime containment et recovery
Même une bonne stack de vérification ne capturera pas tout.
C’est pour cela que la couche externe est le runtime containment.
On y retrouve crash-only design, deadlines, circuit breakers, leases et capability-based boundaries. Quand quelque chose passe au travers, le système doit échouer de manière contrôlée au lieu de transformer un mauvais chemin en incident en cascade.
Pour beaucoup d’équipes, cette couche commence modestement:
- timeouts explicites sur les appels externes
- idempotency keys sur les endpoints mutateurs
- circuit breakers devant les dépendances instables
- capability surfaces étroites pour les opérations sensibles
L’objectif n’est pas la perfection. L’objectif est un blast radius limité.
Pourquoi les couches fonctionnent mieux ensemble
Chaque couche capture une classe de défaillance différente.
Types et contracts préviennent les invalid states évidents. Property-based tests vérifient la sémantique. Mutation testing vérifie si les tests ont une réelle puissance. Runtime containment gère ce qui s’échappe malgré tout.
Voilà l’idée essentielle: vous n’avez pas besoin d’une technique parfaite. Vous avez besoin de plusieurs techniques imparfaites qui échouent indépendamment les unes des autres.
À quoi ressemble un rollout pragmatique
La plupart des équipes ne devraient pas tout activer d’un coup.
L’ordre le plus raisonnable est souvent:
- durcir les boundaries TypeScript ou Rust
- ajouter des runtime schemas aux inputs externes
- introduire des contracts sur les fonctions critiques
- écrire des property tests pour serializers, reducers et validators
- activer incremental mutation testing sur les modules à haut risque
- ajouter du runtime containment là où les dépendances cassent le plus souvent
Cet ordre fonctionne parce que chaque couche renforce la suivante. De meilleurs schemas donnent de meilleures properties. De meilleures properties améliorent les mutation scores. Le feedback de mutation testing montre où contracts et profondeur de test restent faibles.
Le vrai shift de l’ingénierie à l’ère AI
Les équipes gagnantes ne seront pas celles qui génèrent le plus de code. Ce seront celles qui peuvent absorber davantage de code généré sans perdre en confiance.
C’est exactement ce que résout cette safety stack.
Elle transforme l’AI d’un speed amplifier en reliability amplifier. Le modèle aide à générer implémentations, tests, contracts et rules. La stack s’assure que ces artefacts sont contrôlés par des systèmes déterministes, plutôt que validés uniquement parce qu’ils “ont l’air bien”.
Si vous êtes sérieux sur l’usage de l’AI en production engineering, c’est ce niveau qu’il faut viser. Pas une checklist de review supplémentaire. Pas un prompt de plus disant “be careful”.
Mais un système en couches où chaque changement généré doit survivre à prevention, verification, assessment et containment.
C’est ainsi que du code rapide devient du code digne de confiance.