Back to all posts

1,3 million de lignes, 630 PR par semaine : comment nous gardons saine une base de code vibe-coded

1,3 million de lignes, 630 PR par semaine : comment nous gardons saine une base de code vibe-coded

En juillet 2026, Robert C. Martin a écrit qu'il ne lisait plus le code produit par ses agents de codage.

La déclaration a beaucoup fait réagir. Le reste de son message compte davantage pour comprendre sa façon de travailler. Martin entoure les agents de tests unitaires, de tests d'acceptation en Gherkin, de procédures de QA, de tests de mutation, de contrôles de couverture et de métriques de qualité. Le code gagne sa confiance en traversant ce système.

Il avait avancé un point similaire quelques mois plus tôt. Plutôt que d'inspecter l'implémentation, il regarde la couverture de tests, la structure des dépendances, la complexité cyclomatique, la taille des modules et les résultats des tests de mutation. Quand certains y ont vu un abandon pur et simple de la revue, il a précisé : « Je relis énormément — simplement pas le code. »

Ses commentaires décrivent un problème pratique du développement logiciel à forte composante IA. Les agents de codage peuvent produire des changements plus vite que les humains ne peuvent les lire. Dès que le volume de code généré dépasse la capacité de relecture de l'équipe, l'inspection ligne à ligne ne peut plus être la seule source de confiance.

Nous affrontons le même problème chez vm0 depuis huit mois. L'essentiel de l'implémentation de notre dépôt est écrit par des agents — du vibe coding, selon le raccourci courant — tandis que six ingénieurs restent responsables de ce que ce code fait en production.

La version courte

vm0 est une base de code vibe-coded : les agents écrivent l'essentiel de l'implémentation, et six ingénieurs répondent de ce qu'elle fait en production. Au bout de huit mois, le dépôt compte 1 329 170 lignes et 630 pull requests ont été fusionnées en une seule semaine. Cinq mécanismes portent la charge de qualité qu'une relecture ligne à ligne ne peut plus porter seule.

  • Environnements convergents. Ingénieurs et agents travaillent dans le même dev container, et chaque pull request peut obtenir sa propre branche de base de données. Une commande qui a fonctionné pour un agent fonctionne pour une personne.
  • Contraintes exécutables. TypeScript strict, environ 135 modules de contrat d'API typés, Oxlint, ESLint et des règles d'architecture, avec une CI qui n'accepte aucun avertissement. Une règle vérifiable mécaniquement n'est pas laissée à la relecture.
  • Tests aux frontières. Un trophée de tests plutôt qu'une pyramide : tests d'intégration à travers les frontières publiques des modules, PostgreSQL et migrations réels, mocks uniquement aux systèmes externes. Le code de test représente environ 36 % du dépôt.
  • Boucles de retour complètes. Les agents démarrent l'application et la base, exécutent les migrations et pilotent un vrai navigateur, puis rapportent les commandes exécutées, le chemin testé et des captures. La pull request médiane est fusionnée en 53 minutes environ.
  • Nettoyage continu. Knip supprime le code mort de façon déterministe, des workflows quotidiens éliminent l'AI slop qu'aucun linter ne sait nommer, et un motif qui revient assez souvent devient une règle de lint ou une contrainte de type.

Ce que veulent vraiment dire vibe coding et agentic coding

Le vibe coding consiste à demander du code à un LLM, exécuter ce qu'il produit, demander des modifications et ne prêter aucune attention au code généré. La définition de Martin Fowler est volontairement étroite, et il insiste sur l'idée d'« oublier que le code existe ». Cela convient aux prototypes, aux logiciels jetables et aux petits outils à faibles conséquences.

L'agentic coding, que Fowler appelle programmation agentique, est ce que font les équipes qui comptent maintenir le résultat. Un agent lit le dépôt, modifie des fichiers, exécute des tests et travaille seul pendant une période prolongée, tandis que les personnes gardent la responsabilité de la structure et du comportement et examinent les preuves produites : résultats de tests, signaux de qualité, previews et comportement en production.

La différence ne tient pas à la quantité de code écrite par le modèle, mais à l'endroit où va l'attention humaine.

Vibe codingAgentic coding
Autonomie de l'agentPrompt, exécution, nouveau promptLit le dépôt, modifie, teste, itère
Qui lit le codePersonneLes humains lisent ce qui porte un risque
Ce qui est vérifiéSi le résultat a l'air correctTypes, contrats, tests, previews, signaux de production
Usage adaptéPrototypes et outils jetablesLogiciel avec un horizon de maintenance
Échec typiqueDu code que personne ne comprendUne vérification trop faible pour le volume

Les agents qui modifient un dépôt ne sont qu'une branche d'un mouvement plus large ; nous avons traité le versant non-développeur à part.

Nous appelons souvent vm0 un projet vibe-coded parce que l'expression est devenue le raccourci courant pour un logiciel écrit principalement par l'IA. Dans les termes de Fowler, cela relève plutôt de l'agentic coding. Nos ingénieurs tapent moins d'implémentation qu'avant, tout en restant responsables de l'architecture, du coût de maintenance et du comportement en production.

À mesure que la génération de code s'est accélérée, une part croissante de cette responsabilité s'est déplacée vers l'environnement de développement, le système de types, la suite de tests et des workflows de maintenance automatisés.

Huit mois de croissance dans une base de code vibe-coded

Le dépôt vm0 a été créé en novembre 2025. Au moment de notre dernier rapport hebdomadaire d'échelle d'ingénierie, il avait environ huit mois et demi.

Le dépôt contenait :

MétriqueValeur
Lignes logiques non vides1 329 170
Lignes de production850 913
Lignes de test478 257
Fichiers source5 549
Fichiers de test1 327
Paquets44
Commits sur la branche principale14 005

Ces chiffres proviennent de notre rapport hebdomadaire d'échelle d'ingénierie pour la semaine du 20 au 26 juillet 2026, mesurés directement dans le monorepo.

Le code de test représentait environ 36 % de la base de code mesurée. C'est une part du volume de code, non un chiffre de couverture, mais cela donne une idée de la quantité d'implémentation accumulée autour de la vérification.

Sur trois semaines pleines récentes, six ingénieurs ont réalisé respectivement 541, 640 et 631 commits. Pendant la semaine du 20 au 26 juillet, GitHub a enregistré 630 pull requests fusionnées. Six ingénieurs en ont écrit 556, l'automatisation des releases les 74 restantes.

Le délai médian entre l'ouverture d'une pull request et sa fusion était d'environ 53 minutes. Le 90e centile se situait autour de 7,4 heures.

À ce rythme de changement, la relecture humaine reste utile mais ne peut pas porter tout le système qualité. Il nous faut des signaux indépendants à plusieurs points du cycle de vie d'un changement.

Notre approche actuelle s'articule autour de cinq thèmes récurrents : environnements convergents, contraintes exécutables, tests centrés sur les frontières, boucles de retour complètes et nettoyage continu.

Faire converger l'environnement de développement avec des dev containers

Beaucoup de pannes difficiles à reproduire viennent d'un état qui n'apparaît jamais dans une pull request.

Une développeuse peut avoir une variable d'environnement non documentée, un outil installé globalement, un vieux fichier de configuration, ou une base de données qui tourne depuis des mois. Les humains s'habituent à ces détails. Les agents, eux, ne les voient généralement pas.

Nous avons progressivement cessé de traiter la machine hôte comme l'environnement de développement standard. Ingénieurs et agents travaillent dans un dev container. L'image de développement embarque la chaîne d'outils du projet, PostgreSQL, pgvector, Chromium et des utilitaires d'automatisation de navigateur.

La CI s'exécute sur des images de chaîne d'outils versionnées, construites à partir de la même famille de Dockerfile multi-étapes. Les images de développement et de CI servent des objectifs différents, et la production a sa propre forme de déploiement. La propriété utile est la convergence : versions d'outils, dépendances et hypothèses d'exécution sont explicites et versionnées.

Cela nous donne une attente simple. Les commandes exécutées par un agent doivent être reproductibles par un ingénieur dans le même conteneur de développement. Les vérifications qui passent pendant le développement doivent s'exécuter en CI sous une chaîne d'outils très proche.

Nous appliquons une idée voisine aux données. Chaque aperçu de pull request peut disposer de sa propre branche de base de données et exécuter de vraies migrations et étapes de seed. Un agent peut créer des données, les modifier et répéter des tests destructifs sans emprunter la base d'une développeuse ni hériter de l'état d'une autre pull request.

Les changements d'environnement transitent par le dépôt. Mises à jour d'outils, versions de navigateur et extensions de base de données sont relues et propagées comme le code applicatif.

Rendre les standards d'ingénierie exécutables dans les types et les règles de lint

Les standards écrits aident les humains à comprendre les décisions de conception. Ils garantissent beaucoup moins que chaque changement suive ces décisions, surtout pendant de longues sessions d'agent.

Nous plaçons les règles stables dans le système de types, les linters et la CI dès que la règle peut être exprimée de façon fiable.

vm0 utilise des réglages TypeScript stricts, dont strict et noUncheckedIndexedAccess. Certains paquets activent des vérifications supplémentaires pour les valeurs inutilisées et les retours implicites.

L'API repose sur une couche de contrats REST typée et schema-first, construite avec la machinerie de types de tRPC et des schémas Zod. Drizzle relie l'accès à la base de données aux types TypeScript. Au moment de cette revue, le dépôt comptait environ 135 modules de contrat.

Ces choix n'attrapent pas les mauvaises décisions produit. Ils font en revanche remonter tôt la dérive des interfaces. Quand un champ ou une réponse change, les appelants concernés échouent généralement dès l'analyse statique. L'erreur obtenue est le plus souvent assez précise pour qu'un agent s'en serve à l'itération suivante.

Le linting couvre un second groupe de règles. La plateforme exécute Oxlint, des vérifications conscientes des types et ESLint, ainsi que des règles d'architecture propres au projet. La CI n'accepte aucun avertissement. Les avertissements que l'on peut laisser indéfiniment deviennent du bruit de fond, et le bruit de fond est facile à ignorer, pour les humains comme pour les agents.

Quand un problème se répète, nous réfléchissons à l'endroit où la vérification doit vivre :

  1. Le système de types peut-il l'exprimer ?
  2. Un linter ou un outil structurel peut-il le détecter avec précision ?
  3. Faut-il un jugement sémantique à l'échelle du dépôt ?

Les deux premiers donnent un retour rapide et déterministe à chaque changement. Le troisième groupe est traité par les workflows récurrents décrits plus loin.

Restreindre les motifs propices aux erreurs dans le code généré par l'IA

Certaines fonctionnalités du langage ont des usages légitimes et apparaissent aussi fréquemment dans du code fragile généré par des agents.

try/catch peut brouiller une frontière d'erreur. Quand un agent rencontre un échec, ajouter un bloc catch et un repli est un moyen facile de garder le chemin courant en vie tout en perdant l'erreur d'origine. Mélanger .then() et .catch() de Promise avec async/await disperse le flux de contrôle entre plusieurs styles.

Le useEffect de React crée un problème analogue dans la gestion d'état. Il sert souvent à copier de l'état, synchroniser deux sources de vérité, ou encoder une dépendance d'ordre difficile à voir depuis le modèle de données.

La plateforme web centrale restreint ces motifs par défaut. Une exception justifiée peut subsister, accompagnée d'une explication explicite.

Le code de production de la plateforme web centrale ne contient actuellement aucun useEffect. Nous utilisons ccstate et d'autres motifs sans effets pour modéliser dépendances et effets de bord de façon plus explicite. Un petit nombre d'appels useEffect de production subsiste ailleurs dans le monorepo, surtout dans le code d'UI partagée et de bureau : la portée de l'affirmation compte.

Ces règles sont nées d'échecs récurrents dans ce dépôt. Quand un motif crée à répétition le même problème de maintenance, nous le faisons passer d'une consigne de relecture à une contrainte exécutable.

Tester aux frontières des modules : un trophée de tests, pas une pyramide

vm0 ne suit pas une pyramide de tests classique. Notre guide de test décrit un trophée de tests : l'analyse statique à la base, les tests d'intégration comme couche dominante, et un petit nombre de tests de bout en bout pour les parcours utilisateurs critiques.

Les tests unitaires sont relativement rares. Nous les employons de façon ciblée pour la logique sensible à la sécurité, les algorithmes et les machines à états. L'essentiel du comportement métier est testé à travers la frontière publique d'un module.

Les tests d'API appellent la vraie application via ses contrats. Les données de test sont préparées via les points de terminaison de production quand c'est praticable, et les assertions portent sur le comportement public. Les tests évitent d'aller directement dans un service interne ou de modifier des tables de la base, car cela les couplerait à l'implémentation du moment.

L'infrastructure interne reste réelle partout où le coût est raisonnable :

  • PostgreSQL et pgvector
  • les migrations de base de données
  • le système de fichiers
  • les services internes
  • des mocks aux frontières des systèmes externes

Ces tests d'intégration s'exécutent plus lentement que des tests unitaires fortement isolés et exigent un environnement plus complet. En échange, ils réduisent l'écart entre « le test est passé » et « l'application sait effectuer cette opération avec une vraie base de données ».

Les tests de frontière laissent de la place aux gros refactors internes. Un agent peut réorganiser des modules, scinder un service ou changer la couche d'accès aux données pendant que le comportement public reste protégé.

Uncle Bob privilégie un autre dosage, avec un usage massif de tests unitaires, de Gherkin et de tests de mutation. Le principe partagé est la vérification indépendante. Le processus qui a généré le code ne devrait pas être la seule source affirmant que ce code fonctionne.

Donner aux agents de code une boucle de retour complète

Nos premières exécutions d'agents de codage se terminaient souvent par un rapport familier : le code a été modifié et TypeScript passe ; merci de lancer l'application et de vérifier la page.

Cela laisse la moitié de la boucle de développement à l'ingénieur. Quelqu'un doit encore préparer une base de données, lancer les services, ouvrir un navigateur, créer des données, observer l'échec et le redécrire à l'agent.

Les agents disposent désormais d'assez d'environnement de développement pour en faire davantage. Ils peuvent démarrer l'application et la base de données, exécuter les migrations, créer des données de test, ouvrir un aperçu de pull request et mener de vraies interactions dans le navigateur.

La vérification navigateur attrape une catégorie de problèmes que les vérifications de types et les tests d'API couvrent mal : navigation cassée, états de chargement qui ne se terminent jamais, erreurs de permission qui n'apparaissent que dans un parcours complet, et régressions visuelles.

À la fin d'une exécution, l'agent rapporte les commandes exécutées, le chemin testé et ce qu'il a observé. Pour les changements d'interface, il peut joindre des captures d'écran. Un ingénieur peut examiner ces preuves avant de décider s'il ouvre lui-même l'aperçu.

Une capture d'écran n'est pas un test et ne prouve pas l'absence d'autres défauts. Elle réduit le coût de reconstitution du contexte de l'agent. Pour un petit changement d'interface, des étapes reproductibles et une capture finale sont bien plus utiles qu'un message affirmant que le problème « devrait être corrigé ».

La qualité du travail d'un agent dépend fortement du retour qu'il peut obtenir sans attendre un humain.

Garder les branches courtes avec le trunk-based development

Une génération de code rapide peut produire un large stock de branches.

Les branches de fonctionnalité de longue durée accumulent conflits de fusion, travail dupliqué et contexte périmé. À mesure que les pull requests grossissent, la relecture devient plus difficile et plus lente. Nous pratiquons le développement basé sur le tronc pour garder des branches courtes et intégrer en continu autour de main.

Les règles de notre branche principale exigent :

  • des pull requests pour les changements
  • un historique linéaire et des merges en squash
  • une file de fusion
  • des vérifications Turbo, Rust et sécurité
  • aucun contournement de routine des barrières obligatoires

L'automatisation emprunte le même chemin. Un agent peut créer une pull request, et certaines tâches de maintenance à faible risque peuvent activer la fusion automatique, mais le changement passe quand même par la CI et la file de fusion.

La taille et la durée de vie des pull requests expliquent en partie comment 630 d'entre elles ont pu être fusionnées en une semaine. Un petit changement porte moins de contexte, se vérifie plus facilement et entre moins souvent en conflit avec le travail produit ou une autre réparation automatisée.

Knip, ou le ramasse-miettes du dépôt : supprimer le code mort

La génération de code ajoute naturellement des fichiers et des abstractions. La suppression demande souvent un prompt à part.

Après un refactor, d'anciens fichiers peuvent rester dans le dépôt. Retirer une fonctionnalité peut laisser derrière elle des exports, des dépendances et des points d'entrée. Ces résidus cassent rarement des tests, mais rendent la base de code plus difficile à parcourir avec le temps.

Nous utilisons Knip pour repérer fichiers, exports, dépendances et points d'entrée inutilisés. TypeScript peut confirmer que le code est valide ; Knip demande s'il participe encore au système.

Ce résidu a un coût supplémentaire pour les agents de codage. Le dépôt est l'une de leurs principales sources de contexte. Un helper obsolète ou une implémentation abandonnée peut ressembler à un motif approuvé pour le prochain agent qui le lira.

Supprimer le code mort améliore donc aussi les entrées disponibles pour les exécutions futures. Knip traite la part déterministe de ce travail assez vite pour devenir un contrôle qualité régulier.

Workflows récurrents de nettoyage de l'« AI slop »

Knip et ESLint ont des limites nettes. Beaucoup de formes de dégradation exigent du contexte projet et un jugement sémantique.

Nous employons « AI slop » comme étiquette pratique pour ce résidu : replis inutiles, abstractions dupliquées, tests qui contournent une frontière publique, ou branches défensives pour des états impossibles. Chaque cas peut sembler anodin. Cumulés, ils rendent le dépôt plus difficile à comprendre et donnent de mauvais exemples aux futurs agents.

Plusieurs workflows récurrents sur vm0 balaient ces motifs.

Un nettoyage quotidien d'AI slop cherche les nouveaux résidus et sélectionne un petit ensemble de corrections à forte confiance et faible risque. D'autres workflows inspectent les tests d'API qui plongent dans les services internes, les antipatterns React et ccstate, et la dette technique traitable sans danger.

Chaque workflow garde des changements étroits. Il ouvre une pull request, puis s'en remet aux vérifications de types, règles de lint, tests et file de fusion habituels. Une pull request configurée pour la fusion automatique doit franchir les mêmes barrières.

Workflow automatisé de maintenance du dépôt, du scan jusqu'à la CI et la fusion, avec réparation en cas d'échec

Ces workflows ne cherchent pas à solder toute la dette technique en une passe. Un petit lot quotidien se vérifie plus facilement et perturbe moins qu'un grand nettoyage tous les quelques mois.

Quand un workflow récurrent trouve le même motif assez souvent, nous envisageons de déplacer la vérification vers ESLint, Knip ou le système de types. Le workflow sémantique sert de lieu d'observation et d'affinage de la règle avant d'en faire une vérification déterministe moins coûteuse.

Ces workflows vm0 récurrents s'exécutent selon un calendrier.

Transformer les tests instables en réparations automatiques

Un autre groupe de workflows part des échecs de GitHub Actions.

Quand un test échoue sur la branche principale ou dans la file de fusion, un workflow lit les logs, cherche des indices d'instabilité et examine les nouvelles tentatives, le timing et les facteurs d'environnement. Si les éléments soutiennent une réparation précise, il met à jour le test ou l'implémentation, ouvre une pull request et relance tout le parcours de CI.

Passer à la seconde tentative ne rend pas l'échec initial inoffensif. Les équipes qui s'appuient sur le bouton « réessayer » perdent peu à peu confiance dans les builds rouges. Dès lors, les vérifications en échec deviennent une autre forme de bruit de fond.

Un workflow de réparation automatisé transforme un échec intermittent en un changement de code traçable. Diagnostic, correctif et vérification restent visibles dans la pull request. Les ingénieurs peuvent examiner les changements les plus risqués, tandis que les correctifs étroits et bien étayés peuvent avancer dans la file de fusion.

Notre système qualité comporte aujourd'hui trois grandes couches :

ÉtapeMécanismesPréoccupations typiques
Pendant l'écritureTypeScript, contrats, Drizzle, ESLinterreurs de types, dérive d'interfaces, motifs de code connus
Avant la fusionKnip, tests d'intégration, bases réelles, aperçus, file de fusioncode mort, comportement des modules, résultats d'exécution complets
Après la fusionworkflows vm0 planifiés et pilotés par événementsAI slop, antipatterns sémantiques, tests instables, dérive architecturale

Les couches se nourrissent mutuellement. Les problèmes trouvés par les workflows peuvent devenir des règles statiques. Les échecs découverts en CI ou en production peuvent devenir des tests et de nouvelles consignes d'ingénierie.

Faire tourner des agents en continu a un coût, et nous avons écrit séparément sur la manière de le réduire.

Où va l'attention humaine dans la revue de code généré par l'IA

Les ingénieurs de vm0 lisent toujours du code, en particulier pour les changements d'architecture, le travail sensible à la sécurité, les paiements et les migrations de données. Nous n'avons pas érigé « ne jamais lire le code » en règle d'équipe.

Ce qui a changé, c'est la répartition de l'attention. Lire du code est un signal parmi les contrats, les frontières de test, le comportement des aperçus, les captures d'écran, les métriques de qualité et les diagnostics de workflows.

Plusieurs décisions réclament encore un jugement expérimenté :

  • si l'exigence est complète
  • où placer les frontières de modules
  • quels échecs sont récupérables
  • quel impact métier un défaut pourrait produire
  • si un modèle de sécurité est approprié
  • quel nouveau motif d'échec les règles actuelles ne couvrent pas

Les ingénieurs entretiennent aussi l'environnement autour des agents. Quand un problème se répète, nous décidons d'ajouter une contrainte de types, une règle de lint, un test ou un workflow récurrent. Le système de développement est devenu à part entière un artefact d'ingénierie important.

Un code lisible compte toujours. Le prochain lecteur peut être un ingénieur ou un autre agent. Un code emmêlé consomme plus de contexte, élargit la portée des changements futurs et rend la vérification moins fiable.

Un déplacement comparable a eu lieu côté design, où le design-as-code a fait entrer les décisions visuelles dans le même dépôt et le même circuit de revue.

La sécurité et les changements qui n'accélèrent pas

La vitesse n'est pas répartie uniformément. vm0 garde une courte liste de changements qui avancent à leur propre rythme : travail sensible à la sécurité, paiements, migrations de données et décisions d'architecture. Un ingénieur les lit ligne à ligne, quel que soit l'auteur.

Le risque de sécurité du code généré par l'IA tient, d'après notre expérience, moins à des vulnérabilités exotiques qu'à du code plausible que personne n'assume. Les contrôles qui comptent sont ordinaires, à condition d'être appliqués avec constance :

  • Les tests unitaires, que nous utilisons peu par ailleurs, servent délibérément pour la logique sensible à la sécurité, les algorithmes et les machines à états.
  • Les tests ne mockent qu'aux frontières des systèmes externes. L'infrastructure interne reste réelle, de sorte qu'un changement qui casse un contrat interne échoue en CI plutôt qu'en production.
  • Les agents travaillent dans le dev container contre une branche de base de données par pull request, pas sur la machine d'un développeur ni sur une base partagée.
  • La merge queue et les checks obligatoires n'ont pas de contournement de routine, y compris pour une pull request ouverte par un agent et marquée pour fusion automatique.
  • try/catch est restreint par défaut, pour éviter qu'une erreur soit absorbée par un fallback ajouté par un agent afin de garder le chemin courant fonctionnel.

La gestion des identifiants est un problème de conception distinct, avec sa propre réponse : nous avons décrit le modèle de broker qui garde les jetons hors de portée d'un agent dans un article dédié.

Rien de tout cela ne rend le code généré sûr en soi. Cela réduit l'ensemble des changements où une décision humaine est le seul contrôle, et rend cet ensemble explicite.

Ce que ces chiffres ne montrent pas

Le rapport hebdomadaire démontre l'échelle du dépôt et la vitesse de livraison. Il ne démontre pas, à lui seul, la fiabilité en production.

Évaluer l'effet sur la qualité à l'exécution demande de la disponibilité, des taux d'erreur en production, un nombre d'incidents, un taux d'échec des changements, une fréquence de rollback et un temps moyen de rétablissement. Une CI verte décrit une partie du processus de livraison.

Nous continuons à assembler ces mesures de résultat. Les pratiques d'ingénierie expliquent comment un système gère le risque ; les données de production montrent l'efficacité réelle de cette gestion.

Questions fréquentes

Qu'est-ce que le vibe coding ? Le vibe coding consiste à demander du code à un LLM, exécuter ce qu'il renvoie, demander des modifications et ne pas lire le code généré. La définition de Fowler est étroite à dessein : il s'agit d'« oublier que le code existe ». Cela convient aux prototypes, aux logiciels jetables et aux outils à faibles conséquences.

Qu'est-ce que l'agentic coding ? L'agentic coding est une forme de développement assisté par IA au long cours, où un agent lit un dépôt, modifie des fichiers, exécute des tests et itère seul pendant une période prolongée. Les personnes restent responsables de l'architecture et du comportement, et examinent les preuves produites plutôt que chaque ligne écrite.

Quelle est la différence entre vibe coding et agentic coding ? L'attention, pas la paternité du code. En vibe coding, le code n'est jamais inspecté. En agentic coding, l'agent travaille seul pendant que les ingénieurs examinent les preuves autour : résultats de tests, signaux de qualité, previews et comportement en production. vm0 est souvent décrit comme vibe-coded ; dans les termes de Fowler, c'est de l'agentic coding.

Qu'est-ce que l'AI slop ? L'AI slop est le résidu que laisse le code généré par l'IA : fallbacks inutiles, abstractions dupliquées, tests qui contournent une frontière publique, branches défensives pour des états impossibles. Chaque cas paraît anodin. Cumulés, ils rendent le dépôt plus difficile à comprendre et donnent de mauvais exemples à l'agent suivant.

Comment relire du code généré par l'IA à 630 pull requests par semaine ? Pas ligne à ligne. Chez vm0, la relecture humaine va là où le jugement est nécessaire : architecture, travail sensible à la sécurité, paiements, migrations de données. Le reste est porté par des mécanismes : types stricts et contrats, tests d'intégration aux frontières des modules, bases de données réelles dans les previews par pull request, vérification navigateur, Knip et une merge queue sans contournement de routine.

Quelles sont les bonnes pratiques du vibe coding à grande échelle ? Cinq tiennent chez vm0 depuis huit mois : faire converger l'environnement de développement pour que agents et humains exécutent les mêmes commandes ; rendre les standards exécutables dans les types, les linters et la CI plutôt que dans des documents ; tester aux frontières des modules contre une infrastructure réelle ; donner aux agents une boucle de retour complète, navigateur inclus ; et nettoyer en continu au lieu de procéder par grandes passes occasionnelles.

Quels sont les risques de sécurité du code généré par l'IA ? Le risque courant n'est pas une vulnérabilité exotique mais du code plausible que personne n'assume. vm0 maintient en relecture humaine le travail sensible à la sécurité, les paiements et les migrations de données, utilise délibérément des tests unitaires pour cette logique, garde l'infrastructure interne réelle dans les tests, restreint les motifs comme try/catch qui absorbent les erreurs, et n'autorise aucun contournement de routine des checks obligatoires.

Le code généré par l'IA crée-t-il de la dette technique ? Il en crée une forme précise : du code qui compile encore et passe les tests mais ne participe plus au système, plus un résidu sémantique qu'aucun linter ne sait nommer. Knip supprime la partie déterministe. Des workflows récurrents traitent le reste par petits lots quotidiens, et un motif qui revient assez souvent devient une règle de lint ou une contrainte de type.

Quelle part du code de vm0 est écrite par l'IA ? L'essentiel de l'implémentation. Durant la semaine du 20 au 26 juillet 2026, six ingénieurs ont signé 556 des 630 pull requests fusionnées, l'automatisation de release s'occupant du reste, et les agents ont écrit la majeure partie du code contenu dans ces pull requests. Ce que gardent les ingénieurs, c'est l'architecture, les contraintes et le comportement en production.

Qu'est-ce qu'un trophée de tests, et pourquoi pas une pyramide ? Un trophée de tests place l'analyse statique à la base, les tests d'intégration comme couche dominante et quelques tests end-to-end au sommet. vm0 l'utilise parce que des tests écrits à travers la frontière publique d'un module continuent de protéger le comportement pendant qu'un agent réorganise l'implémentation en dessous, ce qu'une large couche de tests unitaires ne permet pas.

Comment trouver du code mort dans un dépôt écrit par l'IA ? La génération de code ajoute des fichiers et des abstractions ; la suppression demande généralement une instruction séparée. vm0 exécute Knip comme contrôle régulier pour repérer fichiers, exports, dépendances et points d'entrée inutilisés. TypeScript confirme que le code est valide ; Knip demande s'il participe encore au système, et c'est la question qui compte pour le code mort.

Le code vibe-coded est-il sûr en production ? Cela dépend de ce qui le vérifie, pas de qui l'a tapé. Les signaux que nous exigeons n'ont pas changé : types et contrats, tests via des frontières publiques, infrastructure réelle et une pipeline qui doit être verte. Les chiffres de cet article décrivent l'échelle du dépôt et la vitesse de livraison ; la disponibilité, les taux d'erreur et le change-failure rate répondent à la question de la production, et nous les rassemblons encore.

Huit mois plus tard

Huit mois, c'est trop tôt pour proclamer une méthode définitive. Les modèles, les outils d'agents et le dépôt continuent d'évoluer, et nos règles et workflows évoluent avec eux.

Une bascule est déjà nette. À mesure que la génération de code s'est accélérée, l'environnement, les contraintes, les tests et le système de retour ont pris en charge une plus grande part du fardeau qualité. Les ingénieurs passent moins de temps à taper de l'implémentation et davantage à définir des comportements, concevoir des frontières et améliorer la vérification.

La base de code de vm0 va continuer de croître. Knip retire le résidu déterministe. Les règles statiques bloquent les motifs d'échec que nous comprenons déjà. Les tests d'intégration protègent le comportement des modules. Les workflows récurrents traitent la dégradation que nous ne savons pas encore exprimer mécaniquement.

Le code compte toujours. Nous utilisons désormais davantage de preuves exécutables par la machine pour décider si un changement a sa place sur la branche principale, et si son implémentation doit rester dans le dépôt.

Stay in the loop

// Get the latest insights on AI teammates and collaboration.

SubscribeJoin Discord