Réécriture en Rust par IA de Bun : manuel de validation pour la migration de millions de lignes de code

Un manuel de validation inspiré par la pratique assistée par IA de Bun lors de sa migration de Zig vers Rust, couvrant les contrats comportementaux, les agents de codage isolés, les tests différentiels, les tests fuzz, la revue du code unsafe, les métriques de progression et la publication sécurisée.

发布于 2026年7月12日generalGEO 评分: 08 次阅读
L'image illustre le contenu relatif à la réécriture en Rust par IA de Bun. Le fond est sombre, avec une tête de personnage de dessin animé à gauche et une icône d'engrenage Rust à droite. Au centre, le texte en grands caractères « Bun's AI-Powered Rust Rewrite » où « AI-Powered » est en violet et « Rust Rewrite » en bleu. En dessous, deux extraits de code : le code JavaScript à gauche et le code Rust à droite, montrant des exemples de fonctions traitant des requêtes. L'image fait écho au contenu du document présentant la migration assistée par IA de Bun de Zig vers Rust, illustrant visuellement l'application de l'IA dans la réécriture en Rust.

Réécriture par IA en Rust chez Bun : Un manuel de vérification pour les migrations de millions de lignes

Introduction

Le titre est difficile à ignorer : Bun aurait migré en 11 jours une implémentation majeure de Zig vers Rust en utilisant un workflow dynamique Claude Code. Les récits publiés décrivent des milliers de commits, jusqu'à 64 agents Claude, environ 780 000 lignes de Rust, deux relecteurs adversaires pour chaque unité d'implémentation, et une progression allant d'un code qui ne compilait pas à un port capable de passer la suite de tests et d'être livré.

La mauvaise leçon est que les réécritures de langage sont devenues des tâches en un clic. La leçon utile est que le débit d'implémentation et le débit de vérification sont désormais des problèmes d'ingénierie distincts.

Les agents IA peuvent générer du code plus rapidement qu'une équipe humaine ne peut le lire. Une fois cela arrivé, la revue de pull request conventionnelle ne peut plus servir de mécanisme de sécurité principal. Les équipes ont besoin d'un système qui convertit un changement probabiliste massif en petites affirmations étayées par des preuves vérifiables par machine.

Le rapport de production ultérieur de Bun a rendu cela exceptionnellement concret. L'équipe a signalé 19 régressions connues, toutes corrigées par la suite ; 11 cycles de révision de sécurité ; du fuzzing continu guidé par couverture sur les parseurs ; et environ 27 000 lignes de Rust dans des blocs unsafe sur un total d'environ 780 000 lignes. Ces faits n'affaiblissent pas l'histoire de la migration. Ils montrent à quoi ressemble un travail de migration sérieux une fois la démo impressionnante terminée.

Ce guide transforme cette expérience en un manuel de vérification réutilisable. L'objectif n'est pas de copier l'échelle de Bun. Il s'agit de fournir une méthode pour toute migration — ports de langage, remplacements de framework, modernisation d'API, conversions de bases de données, ou refontes à l'échelle du dépôt — où les agents de codage IA peuvent écrire plus de code que l'équipe ne peut en inspecter de manière responsable ligne par ligne.

Points clés à retenir

  • La réécriture de Bun montre que les agents IA peuvent compresser le temps d'implémentation. Elle ne montre pas que le temps de vérification peut être supprimé.
  • L'actif transférable est le système de migration : des contrats de comportement écrits, des cartes de risques, des pilotes réduits, des travailleurs isolés, des relecteurs indépendants, des portes déterministes, et des commits récupérables.
  • Les compilateurs et les suites de tests héritées détectent différentes classes de défaillances. Aucun des deux ne détecte toutes les divergences sémantiques inter-langages, les différences de mode release, les régressions de performance, ou les limites unsafe.
  • Les gros diffs nécessitent une revue orientée preuves. Les humains devraient inspecter les contrats, les points chauds de risque, les contre-exemples, les lacunes de test, et les décisions de déploiement plutôt que de prétendre que chaque ligne générée reçoit un examen égal.
  • Les équipes peuvent adopter le même schéma sans tenter une réécriture d'un million de lignes : exiger des agents qu'ils prouvent le comportement une tranche à la fois, puis n'accorder une autonomie plus large qu'après des résultats mesurés.

Ce que Bun a réellement fait — et ce que le titre omet

Le récit d'ingénierie a commencé avant la génération de code à grande échelle.

Jarred Sumner aurait passé environ trois heures à créer PORTING.md, qui cartographiait les motifs Zig récurrents vers Rust. Un workflow séparé a analysé les champs de structure, proposé des durées de vie Rust, envoyé ces choix à deux relecteurs adversaires, et sérialisé les résultats dans LIFETIMES.tsv. Ces artefacts ont également été examinés manuellement.

La première

L'essai pilote a porté sur trois fichiers, et non sur l'ensemble du dépôt. Pour chaque fichier :

  1. Un agent a implémenté la version Rust.
  2. Deux nouveaux agents ont examiné l'équivalence comportementale et la conformité avec la documentation de migration.
  3. Un autre agent a appliqué les corrections approuvées.

Ce n'est qu'après ce pilote que le travail s'est étendu à 1 448 fichiers Zig.

Le premier déploiement à grande échelle a échoué. Les agents partageaient un espace de travail et utilisaient des commandes telles que git stash, git stash pop et git reset --hard. Leurs modifications interféraient les unes avec les autres. Le flux de travail a ensuite été modifié pour interdire les commandes de coordination risquées et utiliser quatre répertoires de travail, chacun contenant 16 agents.

Ce détail importe plus que le taux de génération de lignes maximal. La programmation parallèle est un problème de systèmes distribués. L'état partagé, les conflits d'écriture, les opérations globales coûteuses, la propriété et la récupération nécessitent tous des règles explicites.

Le code généré n'a pas fonctionné immédiatement. Bun a utilisé les erreurs du compilateur comme file d'attente et a progressé d'une crate à la fois. À un moment donné, environ 16 000 erreurs du compilateur ont été attribuées aux agents. La boucle utilisait un correcteur, deux réviseurs et un agent d'application, tout en limitant la fréquence des commandes coûteuses telles que cargo check et les opérations Git.

Il ne s'agissait pas d'une traduction magique. C'était une convergence par étapes, pilotée par un retour d'information déterministe.

L'annonce du flux de travail dynamique d'Anthropic indiquait que 99,8 % de la suite existante réussissait au moment de la rédaction initiale, tout en précisant explicitement que le port n'était pas encore en production. L'article ultérieur de Bun couvrait le travail qui a suivi : audits de sécurité, fuzzing, régressions en production, corrections sémantiques et réduction du code non sécurisé.

Lus ensemble, les sources décrivent deux jalons différents :

  • Implémentation suffisamment complète pour être fusionnée
  • Preuves suffisamment complètes pour fonctionner en toute sécurité

Termes à connaître : Port, Oracle, Test Différentiel et Surface Non Sécurisée

Ces définitions sont importantes car une équipe ne peut pas vérifier une migration tant qu'elle ne s'est pas mise d'accord sur ce que les preuves doivent démontrer. Elles séparent également la déclaration de confiance d'un agent d'un résultat vérifiable de manière externe.

Port

Un port réimplémente un logiciel dans un nouveau langage, environnement d'exécution, plateforme ou cadre, tout en préservant un ensemble défini de comportements.

« Préserver le comportement » nécessite une limite. Un port peut préserver les API publiques et les sorties tout en modifiant intentionnellement l'architecture interne, les caractéristiques de performance, les messages d'erreur ou les cas limites non pris en charge.

Contrat de Comportement

Un contrat de comportement est une liste explicite de propriétés que la nouvelle implémentation doit préserver.

Il peut inclure :

  • Entrées et sorties
  • Comportement en cas d'erreur
  • Ordre
  • Effets secondaires
  • Sémantique de concurrence
  • Limites de ressources
  • Plateformes prises en charge
  • Budgets de performance
  • Exigences d'observabilité

Le code existant contient un comportement, mais tous les comportements existants ne sont pas intentionnels. Le contrat sépare les exigences des accidents historiques.

Oracle de Test

Un oracle de test détermine si une sortie est correcte.

Une assertion de test unitaire est un oracle. Une implémentation de référence, une spécification de protocole, un fichier de référence, un invariant de base de données ou une règle rédigée par un humain peuvent également servir d'oracle.

Les conseils d'Anthropic sur les

Le codage scientifique souligne que le travail autonome nécessite des références, des objectifs mesurables ou des suites de tests afin que les agents puissent déterminer s'ils progressent.

Tests différentiels

Les tests différentiels envoient les mêmes entrées aux implémentations ancienne et nouvelle, puis comparent les résultats observables.

Cette méthode est particulièrement utile lorsque l'implémentation ancienne est fiable mais qu'aucune spécification formelle complète n'existe. Un accord ne prouve pas que les deux implémentations sont correctes, mais un désaccord crée une file d'attente d'investigation précise.

Tests métamorphiques

Les tests métamorphiques vérifient les relations entre plusieurs exécutions lorsqu'il est difficile d'écrire des résultats attendus exacts.

Les exemples incluent :

  • La sérialisation et l'analyse d'une valeur devraient la préserver.
  • Le réordonnancement d'entrées indépendantes ne devrait pas modifier un résultat ensembliste.
  • L'exécution deux fois d'une migration idempotente ne devrait pas changer l'état lors de la deuxième exécution.
  • La réutilisation de la même clé d'idempotence ne devrait pas produire un effet secondaire en double.

Surface non sécurisée

La surface non sécurisée est le code où les garanties normales du langage cible sont affaiblies ou contournées.

En Rust, unsafe peut être nécessaire aux interfaces FFI avec C ou C++, à l'intérieur d'allocateurs personnalisés, ou pour l'intégration d'exécution de bas niveau. Le nombre brut n'est pas un verdict. L'équipe a besoin de propriété, d'invariants, de tests et d'un plan explicite pour chaque frontière non sécurisée.

Défaut échappé

Un défaut échappé est un bogue induit par la migration découvert après le point de contrôle qui aurait dû le détecter — après la fusion, le déploiement progressif, les tests de version candidate ou le déploiement en production.

Les défauts échappés sont un retour d'information sur le système de vérification, pas seulement sur l'implémentation.

La chaîne causale : Pourquoi une génération plus rapide nécessite une vérification plus forte

Le parallélisme des agents change l'économie de l'implémentation. Si 64 travailleurs traduisent des fichiers en même temps, le temps de génération de code peut diminuer considérablement. Le graphe de dépendances, la sémantique du langage cible et l'environnement de test partagé ne disparaissent pas. Le débit déplace simplement le goulot d'étranglement en aval.

Goulot d'étranglement 1 : Intégration

Des fichiers individuellement raisonnables peuvent échouer lorsqu'ils sont compilés ensemble.

Les quelque 16 000 erreurs de compilation et les dépendances cycliques de crates de Bun illustrent l'écart entre la traduction locale et la cohérence globale. Le compilateur est un excellent oracle déterministe pour les types, la propriété, les durées de vie, les noms et certaines propriétés de flux de contrôle. Il n'est pas un oracle pour le comportement du produit.

Goulot d'étranglement 2 : Équivalence sémantique

Bun a documenté des bogues où le code semblait presque identique entre les langages mais se comportait différemment.

Les exemples incluaient :

  • Des effets secondaires placés dans debug_assert! de Rust disparaissant dans les builds de release, tandis qu'une assertion Zig comparable évaluait toujours ses arguments.
  • Une expression unwrap_or trop impatiente déclenchant un comportement qui aurait dû rester paresseux.
  • Des sémantiques de tranches d'octets et de limites différant entre les implémentations.
  • Des entrées UTF-16 de longueur impaire exposant un crash.

Ce sont exactement les échecs qu'une revue superficielle manque parce que le code traduit semble plausible.

Goulot d'étranglement 3 : Corrélation de revue

Si le même modèle écrit et révise un changement en utilisant le même contexte et les mêmes hypothèses, il peut reproduire les

Erreur originale.

La documentation des meilleures pratiques de Claude Code d'Anthropic recommande d'utiliser un contexte d'évaluation frais. L'évaluateur voit la différence et la norme sans hériter du raisonnement de l'auteur. L'indépendance ne garantit pas l'exactitude, mais elle réduit le biais de contexte partagé.

Goulot d'étranglement 4 : Preuve opérationnelle

Les tests peuvent réussir alors que la latence double, l'utilisation de la mémoire augmente, une cible de système d'exploitation se brise ou l'observabilité disparaît.

Plus le changement est important, plus il est probable que l'équipe découvre une exigence violée seulement après le déploiement. C'est pourquoi un plan de migration doit inclure des canaris, un rollback, une comparaison de télémétrie et un processus qui convertit chaque défaut échappé en une nouvelle règle contractuelle ou un nouveau test.

La conclusion causale est simple :

L'IA n'élimine pas le coût de la migration. Elle déplace le coût de la frappe vers la spécification, la conception du harnais, l'examen des preuves et le contrôle du déploiement.

Une équipe qui ignore ce changement peut finir de générer du code rapidement, puis passer des mois à déterminer si la réécriture fonctionne réellement.

Une architecture de vérification pour les migrations pilotées par l'IA

L'architecture comporte quatre plans.

1. Plan contractuel

Le plan contractuel stocke :

  • Le comportement public
  • Les promesses de compatibilité
  • Les modifications intentionnelles
  • La matrice de plateformes prises en charge
  • Les budgets de performance
  • Les contraintes de sécurité
  • Les exigences d'observabilité

Les humains maintiennent ce plan, et le référentiel en versionne les modifications.

2. Plan d'exécution

Le plan d'exécution contient des agents d'implémentation isolés.

Chaque agent reçoit :

  • Une unité de migration
  • Les fichiers sources pertinents
  • Le contrat approuvé
  • La carte sémantique
  • Des outils à portée étroite
  • Des vérifications ciblées

L'agent ne peut pas modifier le contrat ni les tests globaux. Il modifie uniquement son périmètre assigné et retourne à la fois un commit et une preuve.

3. Plan de vérification

Le plan de vérification est indépendant de l'implémentation.

Il peut :

  • Compiler le candidat
  • Exécuter des tests ciblés et globaux
  • Effectuer des vérifications différentielles ancien-nouveau
  • Fuzzer les analyseurs et les limites de protocole
  • Analyser le code sensible à la sécurité
  • Benchmarker des charges de travail représentatives
  • Demander à de nouveaux évaluateurs de rechercher des contre-exemples

Les agents de vérification peuvent proposer des tests, mais l'IC déterministe décide si une passerelle est franchie.

4. Plan de publication

Le plan de publication contrôle l'intégration et l'exposition en production.

Il :

  • Fusionne dans l'ordre des dépendances
  • Produit des artefacts reproductibles
  • Identifie les builds avec des versions ou des hachages immuables
  • Exécute du trafic fantôme lorsque c'est possible
  • Étend les canaris progressivement
  • Surveille les indicateurs de niveau de service
  • Préserve un chemin de rollback testé

We0 AI peut se situer entre ces plans en tant que couche d'orchestration et de preuve. Les équipes peuvent utiliser des tâches pour attribuer des tranches de migration, isoler les arbres de travail, attacher des contrats, collecter les résultats des tests et exiger une révision avant que le travail n'avance.

La frontière importante est que l'orchestration coordonne les preuves. Elle ne transforme pas la déclaration de succès d'un agent en autorisation de publication.

Exemple de scénario : Migration d'un service de paiement de Python vers Go

Considérez un service de paiement Python de 120 000 lignes en cours de migration vers Go. L'objectif commercial est de réduire

latence de queue et simplifier le déploiement.

Une invite dangereuse serait :

Réécrivez ce service en Go et faites passer tous les tests.

Cette invite laisse indéfinies la sémantique de transaction, le comportement des erreurs, la précision monétaire, l'idempotence et le déploiement.

Étape 1 : Rédiger le contrat

Pour chaque point de terminaison, l'équipe enregistre :

  • Les schémas de requête et de réponse
  • Les règles d'autorisation
  • Le comportement de la clé d'idempotence
  • L'arrondi des devises
  • La sémantique de relance
  • Les transactions en base de données
  • L'ordre des événements
  • Les codes d'erreur
  • Les exigences de télémétrie

Elle marque également les changements intentionnels, comme la suppression d'un en-tête de débogage spécifique à Python. L'équipe définit la plateforme prise en charge et la matrice de dépendances, puis fixe des budgets de latence p95 et p99 ainsi qu'un plafond de mémoire maximale.

Étape 2 : Choisir trois tranches pilotes

L'équipe sélectionne :

  1. Un module pur de formatage de devises
  2. Un référentiel d'idempotence avec des effets secondaires en base de données
  3. Un point de terminaison HTTP en lecture seule

Le premier teste la traduction mécanique. Le second teste les transactions et la concurrence. Le troisième teste la compatibilité HTTP.

Un agent d'implémentation gère chaque tranche. Les nouveaux réviseurs ne reçoivent que le contrat, l'ancienne source, le diff proposé et les commandes de validation.

Étape 3 : Utiliser l'ancien service comme oracle différentiel

Un corpus nettoyé de requêtes historiques est rejoué sur les deux versions.

Les réponses sont normalisées uniquement là où le contrat autorise des différences, puis comparées. Pour les chemins d'écriture, les deux implémentations s'exécutent sur des instantanés de base de données jetables. Les lignes résultantes et les événements émis sont comparés.

Des tests métamorphiques effectuent ensuite :

  • La répétition de la même clé d'idempotence
  • La modification de l'ordre inoffensif des clés JSON
  • L'introduction de variations de temporisation de relance
  • L'exercice de valeurs monétaires limites

Étape 4 : Mettre en place une ombre et un canari pour le nouveau service

Avant d'activer les écritures en production, le service Go reçoit un trafic ombre avec les écritures désactivées ou redirigées vers un récepteur isolé.

L'équipe compare :

  • Les distributions de latence
  • Les classifications d'erreurs
  • Les appels de dépendances
  • Les formes de traces
  • L'utilisation de la mémoire
  • Le comportement des événements

L'équipe envoie ensuite un trafic canari à 1 % provenant d'une cohorte de commerçants à faible risque.

L'expansion nécessite :

  • Aucune divergence financière inexpliquée
  • Une parité du taux d'erreur
  • Une latence dans le budget convenu
  • Un exercice de rollback réussi

L'implémentation peut toujours avancer rapidement. La sécurité vient de la transformation de « réécrire le service » en affirmations observables.

Cet exemple montre également pourquoi l'expertise du domaine reste essentielle. Les agents peuvent traduire du code, mais les experts en paiement savent que les événements en double, les différences d'arrondi et le comportement de relance sont des exigences commerciales.

Phase 0 : Définir le contrat de migration et les conditions d'arrêt

Avant qu'un agent ne modifie du code, décidez ce qui compte comme étant le même produit.

Inventaire :

  • API publiques
  • Comportement de l'interface en ligne de commande
  • Formats de fichiers
  • Effets en base de données
  • Variables d'environnement
  • Télémétrie
  • Messages d'erreur visibles par l'utilisateur
  • Plateformes prises en charge
  • Caractéristiques de performance

Marquez chaque propriété comme l'une des suivantes :

  • Conserver
  • Modifier intentionnellement
  • Déprécier
  • Inconnu

Les inconnus ne sont pas une permission de deviner. Ils deviennent des tâches de découverte.

Exécutez l'ancien système, recherchez dans les problèmes et les journaux de modifications, inspectez les traces de production, ou demandez aux mainteneurs. L'arbre source pré-migration de Bun

reorganisation a préservé l'historique Git grâce à des commits de déplacement uniquement, faisant de la traçabilité une exigence intentionnelle plutôt qu'un dommage collatéral.

Définissez des conditions d'arrêt strictes. Arrêtez le déploiement en éventail lorsque :

  • Les taux de discordance des pilotes dépassent le seuil.
  • Les travailleurs modifient à plusieurs reprises des tests globaux protégés.
  • La file d'attente des erreurs du compilateur croît plus vite qu'elle ne se résout.
  • Les performances cibles ne respectent pas le budget.
  • Un artefact de restauration ne peut pas être construit.
  • Les preuves sont incomplètes ou illisibles.

L'arrêt protège le projet de l'escalade des coûts irrécupérables.

Le contrat doit être contrôlé séparément de l'exécution. Un agent ne doit pas « corriger » un test défaillant en affaiblissant l'exigence. Les modifications du contrat nécessitent un amendement examiné par un humain expliquant pourquoi l'ancien comportement est obsolète ou incorrect.

Phase 1 : Construire une carte sémantique avant la génération à grande échelle

Créez des correspondances explicites pour les modèles source-cible courants, subtils ou dangereux.

Couvrez des domaines tels que :

  • Les règles de possession et de durée de vie
  • La nullabilité
  • Les exceptions et la gestion des erreurs
  • Le débordement d'entiers
  • Les calculs de temps
  • L'encodage des chaînes
  • Les primitives de concurrence
  • La possession de l'allocateur
  • L'interface de fonction étrangère (FFI)
  • Le comportement débogage versus version
  • Le code spécifique à la plateforme

Le PORTING.md et le LIFETIMES.tsv de Bun ont servi à cet effet.

Leur valeur ne se limitait pas à de meilleures invites. Ils ont donné à des centaines de travailleurs une stratégie sémantique commune. Sans une telle carte, chaque agent invente sa propre approche de traduction, et l'incohérence devient un problème d'intégration.

Demandez à des agents indépendants d'attaquer la carte :

  • Donnez à un réviseur la sémantique de la langue source.
  • Donnez à un autre les risques de la langue cible.
  • Donnez à un troisième des exemples de code représentatifs.
  • Exigez des contre-exemples concrets.

Les humains doivent inspecter les règles les plus risquées, en particulier celles impliquant la possession de mémoire, la concurrence, les limites de sécurité, la persistance et le comportement uniquement en version.

Versionnez la carte. Chaque nouveau désalignement découvert doit mettre à jour les règles, identifier les unités de migration affectées et déclencher une revalidation ciblée.

La carte sémantique est une spécification vivante, pas une invite collée une fois au début.

Phase 2 : Concevoir des pilotes délibérément difficiles

Ne choisissez pas uniquement les fichiers les plus faciles.

Un pilote utile comprend trois formes :

  1. Une unité simple et représentative
  2. Une unité fortement dépendante
  3. Un point chaud sémantique

Bun a utilisé trois fichiers pour valider la boucle implémenter-examiner-corriger avant de traduire 1 448 fichiers. Le nombre exact importe moins que l'éventail des modes de défaillance couverts.

Mesurez le processus du pilote, pas seulement son résultat :

  • Les travailleurs ont-ils respecté la propriété des fichiers ?
  • Les commits étaient-ils atomiques ?
  • Les réviseurs ont-ils trouvé de véritables défauts ou principalement produit du bruit ?
  • Le correcteur a-t-il pu appliquer les suggestions sans violer le contrat ?
  • Les preuves étaient-elles encore lisibles ?
  • Combien de contexte et de calcul chaque unité acceptée a-t-elle consommé ?

Introduisez délibérément des défauts. Ajoutez une différence subtile de mode version, un montage de cas limite ou un seuil de performance et confirmez que le système de vérification le détecte.

Un harnais qui n'a passé que des exemples propres n'a pas encore été testé.

Le déploiement en éventail ne devrait commencer que lorsque le pilote produit des preuves stables et reproductibles. Si les invites, les modèles ou les politiques d'outils changent ensuite substantiellement, relancez le petit pilote. Workflow

la configuration est du code de production et mérite des tests de régression.

Phase 3 : Diffusion avec isolement, propriété et commits atomiques

Créez des unités de migration alignées sur le graphe de dépendances.

Le partitionnement au niveau des fichiers est pratique, mais peut constituer une mauvaise frontière lorsque le comportement traverse les modules. Attribuez un rédacteur à chaque unité et rendez la propriété lisible par machine. Les travailleurs peuvent lire les dépendances mais ne peuvent modifier que leur périmètre, sauf s'ils demandent une modification coordonnée.

Utilisez des arbres de travail séparés, des conteneurs ou des machines virtuelles éphémères lorsque c'est possible.

L'échec de l'espace de travail partagé de Bun montre pourquoi. Restreignez les commandes Git destructrices et les commandes de construction globales coûteuses pour les travailleurs feuilles. Laissez un coordinateur effectuer l'intégration ordonnée.

Des identifiants à courte durée de vie et des listes d'autorisation réseau réduisent l'impact de l'injection de prompt ou de l'exfiltration de dépendances. Les recommandations d'isolement d'Anthropic décrivent les limites du système de fichiers et du réseau comme des fondations pour une autonomie plus sûre.

Chaque unité acceptée doit produire un commit atomique contenant :

  • Identifiant de la source
  • Règles contractuelles applicables
  • Commandes exécutées
  • Résultats des tests et vérifications
  • Résultats des relecteurs
  • Exceptions approuvées

Git devient à la fois un mécanisme de coordination et de récupération.

Les recommandations d'Anthropic pour les workflows de longue durée préconisent des commits significatifs et des tests avant chaque commit, car un historique récupérable empêche une longue exécution d'agent de devenir un artefact opaque.

N'optimisez pas pour les lignes par minute. Optimisez pour les unités vérifiées par heure.

Un débit de génération élevé combiné à une file d'intégration croissante est un progrès négatif.

Phase 4 : Traiter les erreurs du compilateur et les tests comme des files d'attente, pas comme des preuves

La sortie du compilateur crée un travail structuré.

Regroupez les erreurs par unité de propriété ou couche de dépendance, supprimez les cascades de doublons et corrigez les causes profondes avant les symptômes superficiels.

Interdisez les raccourcis, sauf si le contrat les autorise explicitement, y compris :

  • Stubs vides
  • Résultats ignorés
  • Attributs allow larges
  • Assertions désactivées
  • Implémentations factices
  • Tests modifiés uniquement pour faire passer le candidat

Exécutez les tests en cercles élargis :

  1. Tests unitaires pour le module modifié
  2. Tests contractuels aux limites publiques
  3. Tests d'intégration à travers les dépendances
  4. Suites multiplateformes
  5. Tests de régression complets

Conservez la sortie des échecs comme artefact. Une exécution finale verte sans historique peut cacher si les travailleurs ont affaibli à plusieurs reprises les vérifications en cours de route.

Lorsque c'est possible, séparez la rédaction des tests de l'implémentation.

Un agent peut dériver des cas limites du contrat et de l'ancienne implémentation, tandis qu'un autre écrit le port. Verrouillez les tests de compatibilité approuvés afin que les travailleurs d'implémentation ne puissent pas les modifier. Les nouveaux relecteurs doivent se demander si le code réussit pour la raison prévue.

Les régressions de production de Bun démontrent l'écart entre une suite verte et l'exhaustivité sémantique.

Une défaillance HMR uniquement en release provenait d'un effet secondaire dans debug_assert!. Un crash UTF-16 de longueur impaire reflétait un comportement de découpage différent. Chaque défaut échappé doit devenir à la fois un test de régression permanent et une nouvelle règle de carte sémantique.

Phase 5 : Ajouter des tests différentiels, du fuzzing et des budgets de performance

Exécutez les anciennes et nouvelles implémentations contre le même corpus.

Comparez :

  • Codes de sortie

  • Sorties normalisées

  • Catégories d’erreurs

  • Effets secondaires

  • État de la base de données

  • Événements émis

  • Traces

Construire des générateurs de valeurs limites pour :

  • Entrées vides
  • Tailles maximales
  • Encodages malformés
  • Instants autour de l’epoch Unix
  • Compétitions concurrentielles
  • Chemins spécifiques à la plateforme
  • Épuisement des ressources

Fuzzer en continu les parseurs et les frontières des protocoles.

Bun a rapporté que ses fuzzers guidés par couverture ont exécuté le code des parseurs environ 100 milliards de fois et généré environ 15 demandes de correctifs. Le nombre absolu dépend de la charge de travail. Le schéma transférable consiste à relier la découverte de plantages à des tests reproductibles, des correctifs proposés par des agents et des demandes de tirage examinées par des humains.

Lorsque les utilisateurs dépendent de la performance, la performance fait partie du comportement.

Benchmark :

  • Démarrage à froid
  • Débit
  • Latence p50
  • Latence p95
  • Latence p99
  • Mémoire maximale
  • Taille du binaire
  • Temps de construction
  • CPU sous charges de travail représentatives

Comparer les distributions plutôt que les moyennes. Fixer des budgets avant la migration afin que l’équipe ne puisse pas justifier des régressions après avoir fortement investi dans la réécriture.

Effectuer également des tests de longue durée. Les fuites mémoire, les fuites de descripteurs, la croissance des files d’attente, la fragmentation de l’allocateur et les compétitions rares peuvent nécessiter des heures ou des jours pour apparaître.

Un langage offrant des garanties plus solides en matière de sécurité mémoire peut éliminer des classes entières de bogues tout en introduisant des comportements différents en matière d’allocation, d’ordonnancement ou de performance.

Examiner séparément le code non sécurisé, les FFI et les frontières de sécurité

Traiter chacun des éléments suivants comme une classe d’examen distincte :

  • Blocs unsafe
  • Appels FFI
  • Pointeurs bruts
  • Allocateurs personnalisés
  • Frontières cryptographiques
  • Parseurs
  • Déserialiseurs
  • Vérifications de permissions
  • Logique d’authentification
  • Frontières de persistance

Au moment du rapport source, Bun a décrit environ 27 000 lignes dans des blocs unsafe sur environ 780 000 lignes de Rust, dont une grande partie liée à l’intégration avec le C et le C++.

Cette surface nécessite plus qu’une simple revue de code ordinaire.

Exiger un commentaire d’invariant près de chaque frontière non sécurisée :

  • Qu’est-ce qui doit être vrai ?
  • Qui établit l’invariant ?
  • Combien de temps le pointeur reste-t-il valide ?
  • Quel thread possède la valeur ?
  • Quel test exerce la condition ?

Regrouper les motifs unsafe répétés derrière des wrappers révisés. Suivre les lignes et blocs unsafe par propriétaire plutôt que de considérer le total comme une métrique de vanité.

Utiliser :

  • Analyse statique
  • Sanitizers
  • Audits de dépendances
  • Fuzzing
  • Revue manuelle de sécurité

Les 11 cycles de revue de sécurité de Bun sont la preuve d’un durcissement continu, et non l’absence de défauts.

La revue automatisée de sécurité doit compléter la revue de domaine, en particulier autour de l’authentification, de l’évasion de bac à sable, des secrets et des changements dans la chaîne d’approvisionnement.

Examiner le mécanisme de migration lui-même. Les agents exécutent le contenu du dépôt, les scripts de construction et les sorties d’outils. Une dépendance compromise ou une instruction cachée dans le code source peut influencer l’exécution.

L’isolation du système de fichiers, les restrictions réseau, les jetons limités et les vérifications CI immuables réduisent ce risque.

Publier par étapes et pratiquer le rollback avant d’en avoir besoin

La fusion n’est pas la publication.

Construire des artefacts versionnés à partir de commits connus, d’ensembles d’outils, de verrous de dépendances et de manifestes de preuves. Garder l’ancienne implémentation constructible.

Si les anciens et nouveaux binaires peuvent coexister, ajouter un commutateur d’exécution ou une couche de routage.

plutôt que de remplacer définitivement le chemin.

Commencez par une exécution en mode shadow lorsque les effets de bord peuvent être isolés.

Procédez ensuite par canari en utilisant :

  • Utilisateurs internes
  • Locataires à faible risque
  • Plateforme
  • Région
  • Pourcentage de trafic

Définissez des seuils de rollback automatique pour :

  • Défauts de conformité
  • Taux de plantage
  • Latence
  • Mémoire
  • Catégories d’erreurs
  • Signaux de support

Les humains doivent conserver la capacité d’interrompre l’expansion même lorsque les seuils automatisés ne sont pas atteints.

Pratiquez le rollback.

Confirmez que :

  • L’ancien artefact démarre correctement.
  • Les schémas restent compatibles.
  • Le travail en file d’attente peut être drainé.
  • L’observabilité identifie l’implémentation ayant servi chaque requête.
  • Le temps de rollback mesuré répond à l’objectif opérationnel.

Une documentation de rollback qui n’a jamais été exécutée n’est qu’une hypothèse.

Après chaque défaut échappé, mettez à jour le contrat, le plan sémantique, le corpus de tests et le modèle de risques.

Les 19 régressions connues de Bun sont utiles car elles exposent des risques de traduction récurrents. Une migration est achevée lorsque la nouvelle implémentation est opérationnelle et que l’équipe en a tiré des enseignements — pas lorsque le diff généré est fusionné.

Politique de migration IA réutilisable et manifeste de preuve

Le YAML suivant est conçu comme un artefact d’équipe réutilisable. Adaptez les commandes, les seuils et les responsables au dépôt.

We0 AI ou un autre système d’orchestration peut attacher cette politique aux tâches de migration et exiger le manifeste de preuve avant la revue.

ai_migration:
  name: payments-python-to-go
  contract: docs/MIGRATION_CONTRACT.md
  semantic_map: docs/PORTING_RULES.md
  old_reference: artifacts/payments-python@sha256:OLD
  new_candidate: artifacts/payments-go@sha256:NEW

  worker_policy:
    isolation: ephemeral_worktree
    one_writer_per_unit: true
    forbidden_commands:
      - "git reset --hard"
      - "git stash"
      - "git push --force"
    editable_paths: ["cmd/", "internal/", "tests/migration/"]
    protected_paths: ["tests/contracts/", "docs/MIGRATION_CONTRACT.md"]

  required_gates:
    compile: "go build ./..."
    unit: "go test ./..."
    contracts: "./scripts/run-contract-tests.sh"
    differential: "./scripts/compare-old-new.sh --corpus fixtures/replay"
    fuzz: "./scripts/fuzz.sh --hours 24 --unique-crashes 0"
    security: "./scripts/security-scan.sh --severity high"
    performance:
      p99_latency_regression_pct: 5
      peak_memory_regression_pct: 10
    platforms: [linux-amd64, linux-arm64]

  independent_review:
    fresh_context: true
    reviewers_per_unit: 2
    require_counterexample_search: true

  rollout:
    shadow_hours: 48
    canary_percentages: [1, 5, 20, 50, 100]
    rollback_artifact_required: true
    rollback_drill_required: true

  evidence_manifest:
    include:
      - contract_version
      - source_and_target_commits
      - changed_units
      - commands_and_exit_codes
      - differential_mismatches
      - fuzzing_summary
      - benchmark_distributions
      - unsafe_or_ffi_inventory
      - reviewer_findings
      - approved_exceptions
      - rollback_drill_result

Cette politique empêche délibérément les travailleurs d’implémentation de modifier le contrat ou les tests de contrat approuvés.

Elle exige :

  • Des artefacts de référence
  • Une revue indépendante
  • Des critères quantitatifs

limites de performance

  • Preuve de déploiement
  • Un plan de retour en arrière testé

Des exceptions sont possibles, mais elles doivent être documentées et approuvées, non cachées dans une invite.

Mesurer les progrès vérifiés, pas le volume généré

Les lignes de code, le nombre d'agents et les jours écoulés sont des métriques de capacité intéressantes. Elles ne mesurent pas le succès du produit.

Utilisez un tableau de bord de migration équilibré.

Débit unitaire vérifié

Suivez les unités de migration qui :

  • Compilent
  • Passent des tests contractuels ciblés
  • Reçoivent une révision indépendante
  • S'intègrent sans régression

Mesurez les unités acceptées par unité de temps.

Résolution des écarts

Suivez les différences découvertes et déterminez si chacune est :

  • Expliquée
  • Corrigée
  • Approuvée comme intentionnelle
  • Toujours non résolue

Défauts échappés

Suivez les défauts qui passent une barrière qui aurait dû les attraper.

Chaque défaut échappé doit identifier une règle contractuelle, un test, un oracle, une étape de révision ou un seuil de déploiement manquant.

Attention humaine

Mesurez le temps que les humains consacrent à :

  • Définir des contrats
  • Résoudre l'ambiguïté
  • Examiner le code à haut risque
  • Enquêter sur les écarts
  • Opérer le déploiement

L'IA peut réduire le temps de mise en œuvre tout en améliorant la qualité des spécifications. C'est un bon compromis, pas un échec d'automatisation.

Coût de calcul et d'outillage

Mesurez le coût total du modèle, du calcul et de l'outillage par unité acceptée.

Les workflows dynamiques peuvent consommer plus de jetons que les sessions ordinaires. Le parallélisme est justifié lorsqu'il réduit le temps d'attente pour un travail à haute valeur sans créer un arriéré de vérification plus important.

Maintenabilité après migration

Suivez :

  • Le temps de démarrage
  • La vitesse de compilation
  • Le taux d'échec des modifications
  • La latence de révision
  • La densité de défauts
  • La propriété des modules non sécurisés
  • La facilité de débogage
  • La qualité de la documentation opérationnelle

Un portage qui est livré rapidement mais reste opaque pour l'équipe a déplacé la dette plutôt que de l'éliminer.

Comment une équipe peut commencer sans réécrire un million de lignes

Choisissez une migration délimitée avec une implémentation de référence fonctionnelle, telle que :

  • Un changement de version de SDK
  • Un sous-système de framework
  • Une commande CLI
  • Un point de terminaison de service

Rédigez un contrat de comportement d'une page et trois cas pilotes axés sur les risques.

Utilisez des tâches d'agent distinctes pour l'implémentation et la révision afin que leurs contextes restent indépendants.

Avant l'implémentation :

  1. Verrouillez les contrôles d'acceptation.
  2. Exigez que l'implémenteur retourne un commit et une preuve, pas une affirmation en prose.
  3. Demandez au réviseur de trouver des contre-exemples et d'identifier les tests manquants.
  4. Exécutez les contrôles dans l'IC en dehors du modèle.
  5. Étendez-vous uniquement à la couche de dépendance suivante après le succès du pilote.

Conservez un enregistrement complet :

  • Invite
  • Modèle
  • Portée de l'outil
  • Commit source
  • Commit cible
  • Chemins modifiés
  • Contrôles
  • Échecs
  • Résultats du réviseur
  • Exceptions
  • Coût
  • Décision finale

Cet enregistrement permet à l'équipe de comparer les versions de l'outillage et d'enquêter sur les défauts sans deviner ce que l'agent a vu.

Utilisez une règle d'adoption simple :

L'autonomie doit être gagnée.

Un workflow qui produit de manière répétée des unités vérifiées peut recevoir une portée de fichier plus large ou un temps d'exécution non supervisé plus long. Il ne reçoit pas automatiquement la permission de déploiement.

La capacité, la preuve et l'autorité restent séparées.

Limites : Ce que le cas Bun ne prouve pas

Bun est un projet inhabituel.

Son créateur a dirigé le

migration, had deep knowledge of the codebase, and held direct architectural authority. The old implementation had a large test suite, Rust provided strong compiler feedback, and the project could use substantial parallel compute.

Most teams will not share all of those advantages.

The case was also presented through Anthropic, and the source article says the work used a prerelease Claude Fable 5 model. It is valuable primary evidence, but it is not an independent vendor comparison.

Claims about how long a human team would have needed are counterfactual estimates. Teams should not make procurement decisions from one successful migration.

The 19 reported regressions are known regressions, not a guarantee of the complete count. Fuzzing executions and security-review rounds measure effort, not the absence of defects.

The strongest defensible conclusion is modest:

Large AI-driven migrations are feasible when paired with strong deterministic feedback and expert orchestration, but their risk remains an engineering problem after code generation is complete.

That conclusion is still meaningful. Teams can attempt modernization projects that were previously delayed by cost, provided they budget for specification, verification, and controlled rollout at the same scale as implementation.

Practical Migration Checklist

  • Define preserved, changed, deprecated, and unknown behaviors.
  • Inventory platform, performance, telemetry, error, and side-effect contracts.
  • Build a semantic map for risky source-to-target patterns.
  • Protect contracts and approved tests from implementation workers.
  • Run difficult pilot units before repository-wide fan-out.
  • Isolate writers and restrict destructive Git and network operations.
  • Require atomic commits with commands, outputs, and contract references.
  • Use fresh-context adversarial reviewers for high-risk units.
  • Run compiler, unit, contract, integration, and cross-platform gates.
  • Compare old and new implementations on representative corpora.
  • Add metamorphic, fuzz, sanitizer, and performance checks.
  • Inventory unsafe, FFI, authentication, parser, and persistence boundaries.
  • Preserve a reproducible rollback artifact and run a rollback drill.
  • Roll out through shadow and canary stages with automatic stop thresholds.
  • Convert every escaped defect into a contract or verification improvement.
  • Measure verified units, mismatches, human attention, cost, and maintainability.

FAQ

What did Bun rewrite in Rust?

Bun migrated a major implementation that had previously been written in Zig into Rust. The published account describes roughly 780,000 lines of Rust and a highly parallel AI-assisted workflow, followed by extensive testing, security review, fuzzing, and production hardening.

Did AI complete Bun’s Rust rewrite without human review?

No. Human-authored migration rules, manual artifact review, isolated workflows, compiler feedback, independent agent reviewers, security review, fuzzing, and production rollout controls all played important roles. The case is better understood as AI-accelerated engineering than unattended code conversion.

Why are existing tests not enough for a

migration de langage ?

Les tests existants ne couvrent généralement qu'une partie du comportement observé. Ils peuvent omettre des sémantiques propres à la version finale, des différences de plateforme, des régressions de performance, des limites liées à la sécurité, des changements de télémétrie ou des cas limites qui n'ont jamais été encodés dans la suite de tests.

Qu'est-ce que le test différentiel dans une migration de code ?

Le test différentiel exécute les implémentations ancienne et nouvelle avec les mêmes entrées et compare leurs sorties observables ainsi que leurs effets secondaires. Il est particulièrement utile lorsque l'ancien système est fiable mais qu'aucune spécification formelle complète n'existe.

Pourquoi les agents d'implémentation et de relecture devraient-ils utiliser des contextes distincts ?

Un relecteur novice est moins susceptible d'hériter des hypothèses et des erreurs de raisonnement de l'agent auteur. Le relecteur peut se concentrer sur le contrat, le diff, les preuves et les contre-exemples, plutôt que de défendre le chemin d'implémentation qui a produit le changement.

Comment les équipes devraient-elles relire le code Rust unsafe lors d'une migration ?

Chaque bloc unsafe ou interface FFI doit avoir un propriétaire désigné, des invariants documentés, des tests ciblés, et une explication claire de la validité des pointeurs, de leur durée de vie et de la propriété des threads. L'analyse statique, les sanitizers, le fuzzing, la revue des dépendances et la revue manuelle de sécurité doivent être appliqués séparément de la relecture de code ordinaire.

Quels indicateurs une migration assistée par IA devrait-elle suivre ?

Suivez le débit unitaire vérifié, le rapprochement des divergences, les défauts échappés, l'attention humaine, le coût de calcul, la santé du déploiement et la maintenabilité après migration. Les lignes générées et le nombre d'agents sont des indicateurs de capacité, non une preuve de correction.

Une petite équipe peut-elle utiliser ce guide sans exécuter des dizaines d'agents ?

Oui. Commencez par un composant délimité, un contrat de comportement écrit, trois projets pilotes axés sur les risques, des contextes d'implémentation et de relecture distincts, des barrières CI déterministes et un chemin de retour arrière testé. Ne passez à l'échelle du flux de travail qu'après avoir produit des résultats vérifiables de manière répétée.

Outils connexes

  • Bun : Une boîte à outils tout-en-un pour JavaScript et TypeScript dont la migration vers Rust constitue l'étude de cas principale de ce guide.
  • Rust : Un langage de programmation système offrant de fortes garanties de sécurité à la compilation et des limites unsafe explicites.
  • Claude Code : L'environnement de codage agentique d'Anthropic, utilisé dans le flux de travail dynamique décrit par la source.
  • GitHub Actions : Une plateforme CI/CD adaptée aux barrières de compilation, de test, de sécurité, de benchmarking et de preuve déterministes.
  • cargo-fuzz : Un outil de fuzzing standard pour les projets Rust basé sur libFuzzer.
  • Miri : Un interpréteur Rust capable de détecter certaines formes de comportement indéfini dans le code unsafe.

Liens connexes

  • Bun : Réécrire Bun en Rust : Le compte rendu officiel de Bun sur la réécriture, le durcissement en production, le fuzzing et les régressions connues.
  • Dépôt source de Bun : Le dépôt officiel de Bun contenant l'implémentation en Rust, les problèmes, les tests et l'historique de migration.
  • [Anthropic : Introduction aux flux de travail dynamiques](https://claude.

com/blog/introducing-dynamic-workflows-in-claude-code) : Description par Anthropic du flux de travail multi-agent utilisé lors de la migration de Bun.

Résumé

La réécriture de Bun en Rust démontre que les agents de codage IA peuvent considérablement compresser le temps d'implémentation, mais elle montre aussi pourquoi la vérification doit devenir un système d'ingénierie de premier ordre. Les contrats, les cartes sémantiques, les workers isolés, l'examen indépendant, les tests différentiels, le fuzzing, les budgets de performance et le déploiement progressif sont ce qui transforme le code généré en preuve de migration crédible.

La leçon pratique ne consiste pas à copier le nombre d'agents ou de lignes de code. Il s'agit de décomposer une migration en assertions bornées, d'exiger une preuve déterministe pour chaque assertion, et d'étendre l'autonomie uniquement après que le workflow a produit des résultats fiables de manière répétée.

Une réécriture assistée par IA de grande envergure n'est complète que lorsque le nouveau système est vérifié, opérable, récupérable et compris—et non lorsque le code généré a été fusionné.