Riscrittura in Rust guidata dall'IA di Bun: manuale di verifica per la migrazione di milioni di righe di codice
Un manuale di verifica ispirato dalla pratica assistita dall'IA di Bun nella migrazione da Zig a Rust, che copre contratti comportamentali, agenti di codifica isolati, test differenziali, fuzzy testing, revisione del codice unsafe, metriche di progresso e rilascio sicuro.

La Riscrittura in Rust basata sull'IA di Bun: Un Playbook di Verifica per Migrazioni su Milioni di Righe
Introduzione
Il titolo è difficile da ignorare: Bun avrebbe migrato un'implementazione importante da Zig a Rust in 11 giorni utilizzando un flusso di lavoro dinamico con Claude Code. I resoconti pubblicati descrivono migliaia di commit, fino a 64 agenti Claude, circa 780.000 righe di Rust, due revisori avversari per ogni unità di implementazione e un percorso che va dal codice che non compilava a un port che poteva superare la suite di test ed essere distribuito.
La lezione sbagliata è che le riscritture linguistiche siano diventate attività con un solo clic. La lezione utile è che la produttività di implementazione e la produttività di verifica sono ora problemi di ingegneria separati.
Gli agenti IA possono generare codice più velocemente di quanto un team umano possa leggerlo. Quando ciò accade, la revisione convenzionale delle pull request non può più fungere da meccanismo di sicurezza primario. I team hanno bisogno di un sistema che converta un cambiamento probabilistico massiccio in piccole rivendicazioni supportate da prove verificabili a macchina.
Il rapporto di produzione successivo di Bun ha reso tutto ciò insolitamente concreto. Il team ha segnalato 19 regressioni note, tutte successivamente corrette; 11 round di revisione della sicurezza; fuzzing continuo guidato dalla copertura su tutti i parser; e circa 27.000 righe di Rust all'interno di blocchi unsafe su un totale di circa 780.000 righe. Questi fatti non indeboliscono la storia della migrazione. Mostrano come appare un serio lavoro di migrazione dopo che la demo impressionante è finita.
Questa guida trasforma quell'esperienza in un playbook di verifica riutilizzabile. L'obiettivo non è copiare la scala di Bun. È fornire un metodo per qualsiasi migrazione—port linguistici, sostituzioni di framework, modernizzazione di API, conversioni di database o refactor a livello di repository—dove gli agenti di codifica IA possono scrivere più codice di quanto il team possa ispezionare responsabilmente riga per riga.
Punti Chiave
- La riscrittura di Bun mostra che gli agenti IA possono comprimere i tempi di implementazione. Non mostra che i tempi di verifica possano essere eliminati.
- Il bene trasferibile è il sistema di migrazione: contratti comportamentali scritti, mappe dei rischi, piccoli piloti, worker isolati, revisori indipendenti, cancelli deterministici e commit recuperabili.
- I compilatori e le suite di test legacy individuano diverse classi di fallimenti. Nessuno dei due coglie ogni discrepanza semantica cross-linguaggio, differenza in modalità release, regressione delle prestazioni o confine unsafe.
- I grandi diff richiedono una revisione orientata alle prove. Gli umani dovrebbero ispezionare contratti, hotspot di rischio, controesempi, gap nei test e decisioni di rollout, piuttosto che fingere che ogni riga generata riceva la stessa attenzione.
- I team possono adottare lo stesso schema senza tentare una riscrittura da un milione di righe: richiedere agli agenti di provare il comportamento un pezzo alla volta, poi concedere maggiore autonomia solo dopo risultati misurati.
Cosa Ha Fatto Davvero Bun—e Cosa Omette il Titolo
Il racconto ingegneristico è iniziato prima della generazione di codice su larga scala.
Jarred Sumner avrebbe impiegato circa tre ore per creare PORTING.md, che mappava i pattern ricorrenti di Zig a Rust. Un flusso di lavoro separato analizzava i campi delle strutture, proponeva tempi di vita in Rust, inviava queste scelte a due revisori avversari e serializzava i risultati in LIFETIMES.tsv. Questi artefatti sono stati anche revisionati manualmente.
Il primo
Lo studio di implementazione ha riguardato tre file, non l'intero repository. Per ogni file:
- Un agente ha implementato la versione in Rust.
- Due nuovi agenti hanno verificato l'equivalenza comportamentale e la conformità alla documentazione di migrazione.
- Un altro agente ha applicato le correzioni approvate.
Solo dopo questa fase pilota il lavoro si è esteso a 1.448 file Zig.
Il primo tentativo su larga scala è fallito. Gli agenti condividevano un'area di lavoro e utilizzavano comandi come git stash, git stash pop e git reset --hard. Le loro modifiche interferivano tra loro. Il flusso di lavoro è stato quindi modificato per proibire comandi di coordinamento non sicuri e utilizzare quattro worktree, ciascuno con 16 agenti.
Questo dettaglio è più importante del tasso di generazione di righe massimo. La programmazione parallela è un problema di sistemi distribuiti. Stato condiviso, scrittori in conflitto, operazioni globali costose, proprietà e ripristino richiedono tutte regole esplicite.
Il codice generato non ha funzionato immediatamente. Bun ha utilizzato gli errori del compilatore come una coda e ha proceduto un crate alla volta. A un certo punto, circa 16.000 errori del compilatore sono stati assegnati agli agenti. Il ciclo utilizzava un correttore, due revisori e un agente applicativo, limitando la frequenza di esecuzione di comandi costosi come cargo check e le operazioni Git.
Non si è trattato di una traduzione magica. È stata una convergenza graduale guidata da feedback deterministico.
L'annuncio del flusso di lavoro dinamico di Anthropic ha riportato che il 99,8% della suite esistente superava i test al momento della stesura iniziale, sottolineando esplicitamente che la conversione non era ancora in produzione. Il successivo articolo di Bun ha coperto il lavoro successivo: revisioni della sicurezza, fuzzing, regressioni di produzione, correzioni semantiche e riduzione del codice unsafe.
Leggendoli insieme, le fonti descrivono due diverse tappe fondamentali:
- Implementazione sufficientemente completa per essere unita
- Evidenze sufficientemente complete per essere eseguite in sicurezza
Termini da Conoscere: Port, Oracolo, Test Differenziale e Superficie Unsafe
Queste definizioni sono importanti perché un team non può verificare una migrazione finché non concorda su ciò che le evidenze devono dimostrare. Esse separano inoltre la dichiarazione di fiducia di un agente da un risultato verificabile esternamente.
Port
Un port reimplementa un software in un nuovo linguaggio, runtime, piattaforma o framework, preservando un insieme definito di comportamenti.
"Preservare il comportamento" necessita di un confine. Un port può preservare API pubbliche e output, mentre modifica intenzionalmente l'architettura interna, le caratteristiche prestazionali, i messaggi di errore o i casi limite non supportati.
Contratto Comportamentale
Un contratto comportamentale è un elenco esplicito di proprietà che la nuova implementazione deve preservare.
Può includere:
- Input e output
- Comportamento degli errori
- Ordinamento
- Effetti collaterali
- Semantica di concorrenza
- Limiti delle risorse
- Piattaforme supportate
- Budget di prestazioni
- Requisiti di osservabilità
Il codice esistente contiene comportamento, ma non ogni comportamento esistente è intenzionale. Il contratto separa i requisiti dagli incidenti storici.
Oracolo di Test
Un oracolo di test determina se un output è corretto.
Un'asserzione di test unitario è un oracolo. Anche un'implementazione di riferimento, una specifica di protocollo, un file golden, un invariante di database o una regola scritta da umani possono fungere da oracolo.
La guida di Anthropic per esecuzioni di lunga durata
La programmazione scientifica sottolinea che il lavoro autonomo necessita di riferimenti, obiettivi misurabili o suite di test, in modo che gli agenti possano determinare se stanno facendo progressi.
Test Differenziale
Il test differenziale invia gli stessi input alle implementazioni vecchia e nuova, quindi confronta i risultati osservabili.
È particolarmente utile quando l'implementazione vecchia è attendibile ma non esiste una specifica formale completa. L'accordo non dimostra che entrambe le implementazioni siano corrette, ma il disaccordo crea una coda di indagine precisa.
Test Metamorfico
Il test metamorfico verifica le relazioni tra esecuzioni multiple quando è difficile scrivere output attesi esatti.
Gli esempi includono:
- Serializzare e analizzare un valore dovrebbe preservarlo.
- Riordinare input indipendenti non dovrebbe modificare un risultato di tipo set.
- Eseguire due volte una migrazione idempotente non dovrebbe modificare lo stato alla seconda esecuzione.
- Ripetere la stessa chiave di idempotenza non dovrebbe produrre un effetto collaterale duplicato.
Superficie Non Sicura
La superficie non sicura è il codice in cui le normali garanzie del linguaggio target vengono indebolite o bypassate.
In Rust, unsafe può essere necessario ai confini dell'FFI con C o C++, all'interno di allocatori personalizzati o per l'integrazione runtime di basso livello. Il conteggio grezzo non è un verdetto. Il team ha bisogno di proprietà, invarianti, test e un piano esplicito per ogni confine non sicuro.
Difetto Sfuggito
Un difetto sfuggito è un bug indotto dalla migrazione scoperto dopo il gate che avrebbe dovuto rilevarlo — dopo il merge, il deploy canary, i test della release candidata o il rollout in produzione.
I difetti sfuggiti sono feedback sul sistema di verifica, non solo sull'implementazione.
La Catena Causale: Perché una Generazione Più Veloce Richiede una Verifica Più Forte
Il parallelismo degli agenti cambia l'economia dell'implementazione. Se 64 lavoratori traducono file contemporaneamente, il tempo di generazione del codice può ridursi drasticamente. Il grafo delle dipendenze, la semantica del linguaggio target e l'ambiente di test condiviso non scompaiono. La produttività sposta semplicemente il collo di bottiglia a valle.
Collo di Bottiglia 1: Integrazione
File individualmente ragionevoli possono fallire quando compilati insieme.
I circa 16.000 errori del compilatore di Bun e le dipendenze cicliche dei crate illustrano il divario tra traduzione locale e coerenza globale. Il compilatore è un eccellente oracolo deterministico per tipi, proprietà, durate, nomi e alcune proprietà del flusso di controllo. Non è un oracolo per il comportamento del prodotto.
Collo di Bottiglia 2: Equivalenza Semantica
Bun ha documentato bug in cui il codice appariva quasi identico nelle diverse lingue ma si comportava diversamente.
Gli esempi includevano:
- Effetti collaterali inseriti in
debug_assert!di Rust che scompaiono nelle build di rilascio, mentre un'asserzione Zig comparabile valutava ancora i suoi argomenti. - Un'espressione
unwrap_orimpaziente che innescava un comportamento che avrebbe dovuto rimanere pigro. - Semantica di byte-slice e limite che differiva tra le implementazioni.
- Input UTF-16 di lunghezza dispari che esponevano un crash.
Questi sono esattamente i fallimenti che una revisione superficiale perde perché il codice tradotto sembra plausibile.
Collo di Bottiglia 3: Correlazione della Revisione
Se lo stesso modello scrive e revisiona una modifica usando lo stesso contesto e le stesse ipotesi, potrebbe riprodurre lo
errore originale.
La documentazione delle buone pratiche di Claude Code di Anthropic raccomanda di utilizzare un contesto di revisione nuovo. Il revisore vede il diff e lo standard senza ereditare il ragionamento dell'autore. L'indipendenza non garantisce la correttezza, ma riduce il bias del contesto condiviso.
Collo di bottiglia 4: Evidenza operativa
I test possono essere superati mentre la latenza raddoppia, l'uso della memoria cresce, un sistema operativo bersaglio si rompe o l'osservabilità scompare.
Più grande è la modifica, maggiore è la probabilità che il team scopra un requisito violato solo dopo il deployment. Ecco perché un piano di migrazione deve includere canary, rollback, confronto della telemetria e un processo che converta ogni difetto sfuggito in una nuova regola contrattuale o test.
La conclusione causale è semplice:
L'IA non elimina il costo della migrazione. Sposta il costo dalla digitazione verso specifica, progettazione dell'harness, revisione delle evidenze e controllo del deployment.
Un team che ignora questo cambiamento potrebbe finire di generare codice rapidamente e poi trascorrere mesi a determinare se la riscrittura funzioni effettivamente.
Un'architettura di verifica per migrazioni guidate dall'IA
L'architettura ha quattro piani.
1. Piano contrattuale
Il piano contrattuale memorizza:
- Comportamento pubblico
- Promesse di compatibilità
- Modifiche intenzionali
- Matrice delle piattaforme supportate
- Budget di prestazioni
- Vincoli di sicurezza
- Requisiti di osservabilità
Gli umani mantengono questo piano e il repository lo versiona.
2. Piano di esecuzione
Il piano di esecuzione contiene agenti di implementazione isolati.
Ogni agente riceve:
- Un'unità di migrazione
- File sorgente pertinenti
- Il contratto approvato
- La mappa semantica
- Strumenti con ambito ristretto
- Controlli mirati
L'agente non può modificare il contratto o i test globali. Modifica solo il proprio ambito assegnato e restituisce sia un commit che evidenze.
3. Piano di verifica
Il piano di verifica è indipendente dall'implementazione.
Può:
- Compilare il candidato
- Eseguire test mirati e globali
- Eseguire controlli differenziali tra vecchio e nuovo
- Fuzzare parser e confini di protocollo
- Scansionare codice sensibile alla sicurezza
- Eseguire benchmark su carichi rappresentativi
- Chiedere a nuovi revisori di cercare controesempi
Gli agenti di verifica possono proporre test, ma la CI deterministica decide se un gate viene superato.
4. Piano di rilascio
Il piano di rilascio controlla l'integrazione e l'esposizione in produzione.
Esso:
- Unisce in ordine di dipendenza
- Produce artefatti riproducibili
- Identifica build con versioni immutabili o hash
- Esegue traffico shadow dove possibile
- Espande gradualmente i canary
- Monitora gli indicatori di livello di servizio
- Preserva un percorso di rollback testato
L'IA può posizionarsi tra questi piani come livello di orchestrazione ed evidenza. I team possono utilizzare attività per assegnare porzioni di migrazione, isolare worktree, allegare contratti, raccogliere output di test e richiedere revisione prima che il lavoro avanzi.
Il confine importante è che l'orchestrazione coordina le evidenze. Non trasforma l'affermazione di successo di un agente in permesso di rilascio.
Scenario di esempio: Migrazione di un servizio di pagamento da Python a Go
Considera un servizio di pagamento Python di 120.000 righe in fase di migrazione a Go. L'obiettivo aziendale è ridurre...
latenza di coda e semplificare la distribuzione.
Un prompt pericoloso sarebbe:
Riscrivi questo servizio in Go e fai passare tutti i test.
Questo prompt lascia indefiniti la semantica delle transazioni, il comportamento degli errori, la precisione monetaria, l'idempotenza e il rollout.
Fase 1: Scrivere il Contratto
Per ogni endpoint, il team registra:
- Schemi delle richieste e delle risposte
- Regole di autorizzazione
- Comportamento della chiave di idempotenza
- Arrotondamento delle valute
- Semantica dei tentativi
- Transazioni del database
- Ordinamento degli eventi
- Codici di errore
- Requisiti di telemetria
Segna anche le modifiche intenzionali, come la rimozione di un header di debug specifico di Python. Il team definisce la piattaforma supportata e la matrice delle dipendenze, quindi stabilisce i budget di latenza p95 e p99 e un limite massimo di memoria.
Fase 2: Scegliere Tre Slice Pilota
Il team seleziona:
- Un modulo puro di formattazione delle valute
- Un repository di idempotenza con effetti collaterali sul database
- Un endpoint HTTP di sola lettura
Il primo testa la traduzione meccanica. Il secondo testa le transazioni e la concorrenza. Il terzo testa la compatibilità HTTP.
Un agente di implementazione gestisce ogni slice. I nuovi revisori ricevono solo il contratto, il vecchio codice sorgente, il diff proposto e i comandi di validazione.
Fase 3: Utilizzare il Vecchio Servizio come Oracolo Differenziale
Un corpus sanitizzato di richieste storiche viene rieseguito contro entrambe le versioni.
Le risposte vengono normalizzate solo dove il contratto consente differenze, quindi confrontate. Per i percorsi di scrittura, entrambe le implementazioni vengono eseguite su snapshot di database usa e getta. Le righe risultanti e gli eventi emessi vengono confrontati.
I test metamorfici quindi:
- Ripetono la stessa chiave di idempotenza
- Cambiano l'ordinamento innocuo delle chiavi JSON
- Introducono variazioni nei tempi di ripetizione
- Esplorano valori monetari limite
Fase 4: Shadow e Canary del Nuovo Servizio
Prima che le scritture in produzione siano abilitate, il servizio Go riceve traffico shadow con scritture disabilitate o reindirizzate a un sink isolato.
Il team confronta:
- Distribuzioni della latenza
- Classificazioni degli errori
- Chiamate alle dipendenze
- Forme delle tracce
- Utilizzo della memoria
- Comportamento degli eventi
Il team invia quindi traffico canary all'1% da un gruppo di commercianti a basso rischio.
L'espansione richiede:
- Zero discrepanze finanziarie inspiegabili
- Parità del tasso di errore
- Latenza entro il budget concordato
- Un drill di rollback riuscito
L'implementazione può comunque procedere rapidamente. La sicurezza deriva dal trasformare "riscrivere il servizio" in affermazioni osservabili.
Questo esempio mostra anche perché la competenza nel dominio rimane essenziale. Gli agenti possono tradurre codice, ma gli esperti di pagamenti sanno che eventi duplicati, differenze di arrotondamento e comportamento dei tentativi sono requisiti aziendali.
Fase 0: Definire il Contratto di Migrazione e le Condizioni di Arresto
Prima che qualsiasi agente modifichi il codice, decidi cosa conta come lo stesso prodotto.
Inventario:
- API pubbliche
- Comportamento della CLI
- Formati di file
- Effetti sul database
- Variabili d'ambiente
- Telemetria
- Messaggi di errore visibili all'utente
- Piattaforme supportate
- Caratteristiche delle prestazioni
Classifica ogni proprietà come una delle seguenti:
- Preservare
- Modificare intenzionalmente
- Deprecare
- Sconosciuta
Le sconosciute non sono un permesso per indovinare. Diventano compiti di scoperta.
Esegui il vecchio sistema, cerca problemi e changelog, ispeziona le tracce di produzione o chiedi ai manutentori. L'albero del codice sorgente pre-migrazione di Bun
La riorganizzazione ha preservato la cronologia Git tramite commit costituiti esclusivamente da spostamenti, rendendo la provenienza un requisito intenzionale anziché un danno collaterale.
Definire condizioni di arresto rigide. Interrompere la diffusione quando:
- I tassi di disallineamento del pilota superano la soglia.
- I lavoratori modificano ripetutamente test globali protetti.
- La coda degli errori del compilatore cresce più velocemente di quanto venga chiusa.
- Le prestazioni dell'obiettivo non rispettano il budget.
- Un artefatto di rollback non può essere costruito.
- Le evidenze sono incomplete o illeggibili.
L'arresto protegge il progetto dall'escalation dei costi irrecuperabili.
Il contratto deve essere controllato separatamente dall'esecuzione. Un agente non deve "riparare" un test fallito indebolendo il requisito. Le modifiche al contratto richiedono un emendamento revisionato da un essere umano che spieghi perché il vecchio comportamento è obsoleto o errato.
Fase 1: Costruire una mappa semantica prima della generazione su larga scala
Creare mappature esplicite per pattern comuni, sottili o pericolosi da sorgente a destinazione.
Coprire aree come:
- Regole di proprietà e durata
- Nullabilità
- Eccezioni e gestione degli errori
- Overflow di interi
- Calcoli temporali
- Codifica delle stringhe
- Primitive di concorrenza
- Proprietà dell'allocatore
- FFI
- Comportamento debug vs. rilascio
- Codice specifico della piattaforma
PORTING.md e LIFETIMES.tsv di Bun hanno servito a questo scopo.
Il loro valore non si limitava a prompt migliori. Hanno fornito a centinaia di lavoratori una strategia semantica condivisa. Senza una tale mappa, ogni agente inventa il proprio approccio di traduzione e l'incoerenza diventa un problema di integrazione.
Chiedere ad agenti indipendenti di attaccare la mappa:
- Dare a un revisore la semantica della lingua sorgente.
- Dare a un altro i rischi della lingua di destinazione.
- Dare a un terzo esempi di codice rappresentativi.
- Richiedere controesempi concreti.
Gli esseri umani dovrebbero ispezionare le regole a più alto rischio, specialmente quelle che coinvolgono proprietà della memoria, concorrenza, confini di sicurezza, persistenza e comportamento solo in rilascio.
Versionare la mappa. Ogni disallineamento appena scoperto dovrebbe aggiornare le regole, identificare le unità di migrazione interessate e innescare una riconvalida mirata.
La mappa semantica è una specifica vivente, non un prompt incollato una volta all'inizio.
Fase 2: Progettare piloti deliberatamente difficili
Non scegliere solo i file più facili.
Un pilota utile include tre forme:
- Un'unità semplice e rappresentativa
- Un'unità con molte dipendenze
- Un hotspot semantico
Bun ha usato tre file per convalidare il ciclo implementazione-revisione-correzione prima di tradurre 1.448 file. Il numero esatto conta meno della gamma di modalità di guasto coperte.
Misurare il processo del pilota, non solo il suo output:
- I lavoratori hanno rispettato la proprietà dei file?
- I commit erano atomici?
- I revisori hanno trovato difetti reali o hanno prodotto principalmente rumore?
- Il correttore è stato in grado di applicare i suggerimenti senza violare il contratto?
- Le evidenze erano ancora leggibili?
- Quanto contesto e calcolo ha consumato ogni unità accettata?
Introdurre guasti deliberatamente. Aggiungere una sottile differenza in modalità rilascio, un arnese per casi limite, o una soglia di prestazione e confermare che il sistema di verifica lo rilevi.
Un'infrastruttura che ha superato solo esempi puliti non è stata ancora testata.
La diffusione dovrebbe iniziare solo quando il pilota produce evidenze stabili e ripetibili. Se in seguito i prompt, i modelli o le policy degli strumenti cambiano sostanzialmente, rieseguire il piccolo pilota. Flusso di lavoro
la configurazione è codice di produzione e merita test di regressione.
Fase 3: Espansione con Isolamento, Proprietà e Commit Atomici
Creare unità di migrazione allineate al grafico delle dipendenze.
La partizione a livello di file è comoda, ma può essere il confine sbagliato quando il comportamento attraversa i moduli. Assegnare uno scrittore per ogni unità e rendere la proprietà leggibile dalla macchina. I lavoratori possono leggere le dipendenze ma possono modificare solo il proprio ambito, a meno che non richiedano una modifica coordinata.
Utilizzare worktree separati, contenitori o macchine virtuali effimere dove pratico.
Il fallimento del workspace condiviso di Bun mostra il motivo. Limitare i comandi Git distruttivi e i comandi di build globali costosi per i lavoratori foglia. Lasciare che un coordinatore esegua l'integrazione ordinata.
Credenziali di breve durata e liste di autorizzazione di rete riducono l'impatto di injection di prompt o esfiltrazione di dipendenze. Le linee guida di Anthropic sul sandboxing descrivono i confini del filesystem e della rete come basi per un'autonomia più sicura.
Ogni unità accettata deve produrre un commit atomico contenente:
- Identificatore della sorgente
- Regole contrattuali applicabili
- Comandi eseguiti
- Output di test e verifica
- Risultati del revisore
- Eccezioni approvate
Git diventa sia un meccanismo di coordinamento che di recupero.
Le linee guida di Anthropic per flussi di lavoro di lunga durata raccomandano commit significativi e test prima di ogni commit, perché una storia recuperabile impedisce che una lunga esecuzione dell'agente diventi un artefatto opaco.
Non ottimizzare per righe al minuto. Ottimizza per unità verificate all'ora.
Un'elevata produttività di generazione combinata con una coda di integrazione in crescita è un progresso negativo.
Fase 4: Tratta gli Errori del Compilatore e i Test come Code, non come Prove
L'output del compilatore crea lavoro strutturato.
Raggruppa gli errori per unità di proprietà o livello di dipendenza, rimuovi le cascate duplicate e correggi le cause principali prima dei sintomi foglia.
Vieta le scorciatoie a meno che il contratto non le permetta esplicitamente, inclusi:
- Stub vuoti
- Risultati ignorati
- Attributi
allowgenerici - Asserzioni disabilitate
- Implementazioni placeholder
- Test modificati solo per far passare il candidato
Esegui i test in cerchi sempre più ampi:
- Test unitari per il modulo modificato
- Test contrattuali ai confini pubblici
- Test di integrazione attraverso le dipendenze
- Suite multipiattaforma
- Test di regressione completi
Conserva l'output fallito come artefatto. Un'esecuzione finale verde senza storia può nascondere se i lavoratori hanno ripetutamente indebolito i controlli lungo il percorso.
Dove possibile, separa la stesura dei test dall'implementazione.
Un agente può derivare casi limite dal contratto e dall'implementazione vecchia, mentre un altro scrive la portabilità. Blocca i test di compatibilità approvati in modo che i lavoratori dell'implementazione non possano modificarli. I nuovi revisori dovrebbero chiedersi se il codice passa per il motivo previsto.
Le regressioni di produzione di Bun dimostrano il divario tra una suite verde e la completezza semantica.
Un guasto HMR solo in rilascio è derivato da un effetto collaterale dentro debug_assert!. Un crash di lunghezza dispari UTF-16 ha riflesso un comportamento diverso delle slice. Ogni difetto sfuggito dovrebbe diventare sia un test di regressione permanente che una nuova regola della mappa semantica.
Fase 5: Aggiungi Test Differenziali, Fuzzing e Budget di Prestazioni
Esegui le implementazioni vecchia e nuova sullo stesso corpus.
Confronta:
Codici di uscita
Output normalizzato
Categorie di errore
Effetti collaterali
Stato del database
Eventi emessi
Tracce
Crea generatori di valori limite per:
- Input vuoti
- Dimensioni massime
- Codifiche malformate
- Tempi intorno all'epoca Unix
- Race condition concorrenti
- Percorsi specifici della piattaforma
- Esaurimento delle risorse
Esegui continuamente fuzzing su parser e confini di protocollo.
Bun ha riportato che i suoi fuzzer basati sulla copertura hanno eseguito il codice dei parser circa 100 miliardi di volte e generato circa 15 richieste pull di correzione. Il numero assoluto dipende dal carico di lavoro. Il pattern trasferibile è collegare la scoperta dei crash a test riproducibili, correzioni proposte dall'agente e richieste pull revisionate da umani.
Quando gli utenti dipendono dalle prestazioni, le prestazioni fanno parte del comportamento.
Benchmark:
- Avvio a freddo
- Throughput
- Latenza p50
- Latenza p95
- Latenza p99
- Memoria di picco
- Dimensione del binario
- Tempo di compilazione
- CPU sotto carichi di lavoro rappresentativi
Confronta le distribuzioni anziché le medie. Imposta budget prima della migrazione in modo che il team non possa giustificare regressioni dopo aver investito pesantemente nella riscrittura.
Esegui anche test di resistenza. Perdite di memoria, perdite di descrittori, crescita delle code, frammentazione dell'allocatore e race condition rare potrebbero richiedere ore o giorni per emergere.
Un linguaggio con garanzie di sicurezza della memoria più forti può eliminare intere classi di bug, pur introducendo comportamenti diversi relativi ad allocazione, scheduling o prestazioni.
Rivedi Separatamente Codice Unsafe, FFI e Confini di Sicurezza
Tratta ciascuno dei seguenti come una classe di revisione separata:
- Blocchi
unsafe - Chiamate FFI
- Puntatori grezzi
- Allocatori personalizzati
- Confini crittografici
- Parser
- Deserializzatori
- Controlli di autorizzazione
- Logica di autenticazione
- Confini di persistenza
Al momento del report originale, Bun ha descritto circa 27.000 righe all'interno di blocchi unsafe su circa 780.000 righe di Rust, molte delle quali relative all'integrazione con C e C++.
Quella superficie necessita di più di una normale revisione del codice.
Richiedi un commento invariante vicino a ogni confine unsafe:
- Cosa deve essere vero?
- Chi stabilisce l'invariante?
- Per quanto tempo il puntatore rimane valido?
- Quale thread possiede il valore?
- Quale test esercita la condizione?
Raggruppa pattern unsafe ripetuti dietro wrapper revisionati. Tieni traccia delle righe e dei blocchi unsafe per proprietario, senza trattare il totale come una metrica vanitosa.
Utilizza:
- Analisi statica
- Sanitizer
- Audit delle dipendenze
- Fuzzing
- Revisione manuale della sicurezza
Gli 11 cicli di revisione della sicurezza di Bun sono prova di un continuo rafforzamento, non prova che non ci fossero difetti.
La revisione automatica della sicurezza dovrebbe integrare la revisione di dominio, specialmente per autenticazione, sandbox escape, segreti e cambiamenti nella supply chain.
Rivedi il meccanismo di migrazione stesso. Gli agenti eseguono contenuti del repository, script di build e output degli strumenti. Una dipendenza compromessa o un'istruzione nascosta nel codice sorgente può influenzare l'esecuzione.
L'isolamento del filesystem, le restrizioni di rete, i token con ambito limitato e i controlli CI immutabili riducono questo rischio.
Rilascia in Fasi e Pratica il Rollback Prima di Averne Bisogno
Il merge non è il rilascio.
Crea artefatti versionati a partire da commit noti, toolchain, lock delle dipendenze e manifesti di evidenza. Mantieni compilabile l'implementazione vecchia.
Se i binari vecchio e nuovo possono coesistere, aggiungi un interruttore runtime o un livello di instradamento.
piuttosto che sostituire irreversibilmente il percorso.
Iniziare con l'esecuzione in ombra quando gli effetti collaterali possono essere isolati.
Procedere poi con il canary mediante:
- Utenti interni
- Tenant a basso rischio
- Piattaforma
- Regione
- Percentuale di traffico
Definire soglie di rollback automatico per:
- Discrepanze di correttezza
- Tasso di crash
- Latenza
- Memoria
- Categorie di errore
- Segnali di supporto
Gli esseri umani devono mantenere la capacità di fermare l'espansione anche quando le soglie automatiche non sono state attivate.
Praticare il rollback.
Confermare che:
- Il vecchio artefatto si avvii correttamente.
- Gli schemi rimangano compatibili.
- Il lavoro in coda possa essere completato.
- L'osservabilità identifichi quale implementazione ha servito ogni richiesta.
- Il tempo di rollback misurato soddisfi l'obiettivo operativo.
La documentazione di rollback che non è mai stata eseguita è solo un'ipotesi.
Dopo ogni difetto sfuggito, aggiornare il contratto, la mappa semantica, il corpus di test e il modello di rischio.
Le 19 regressioni note di Bun sono utili perché espongono rischi di traduzione ricorrenti. Una migrazione è completa quando la nuova implementazione è operativa e il team ha imparato da essa, non quando il diff generato viene unito.
Criteri di migrazione AI riutilizzabili e manifesto delle prove
Il seguente YAML è progettato come un artefatto di team riutilizzabile. Adattare comandi, soglie e responsabili al repository.
We0 AI o un altro sistema di orchestrazione può allegare questi criteri alle attività di migrazione e richiedere il manifesto delle prove prima della revisione.
ai_migration:
nome: pagamenti-python-a-go
contratto: docs/CONTRATTO_MIGRAZIONE.md
mappa_semantica: docs/REGOLE_PORTING.md
vecchio_riferimento: artefatti/pagamenti-python@sha256:VECCHIO
nuovo_candidato: artefatti/pagamenti-go@sha256:NUOVO
politica_operatore:
isolamento: albero_di_lavoro_effimero
uno_scrittore_per_unita: true
comandi_vietati:
- "git reset --hard"
- "git stash"
- "git push --force"
percorsi_modificabili: ["cmd/", "internal/", "test/migrazione/"]
percorsi_protetti: ["test/contratti/", "docs/CONTRATTO_MIGRAZIONE.md"]
cancelli_richiesti:
compilazione: "go build ./..."
unità: "go test ./..."
contratti: "./script/esegui-test-contratto.sh"
differenziale: "./script/confronta-vecchio-nuovo.sh --corpus fixture/ripeti"
fuzzing: "./script/fuzzing.sh --ore 24 --crash_unici 0"
sicurezza: "./script/scan-sicurezza.sh --gravità alta"
prestazioni:
p99_latenza_regressione_pct: 5
picco_memoria_regressione_pct: 10
piattaforme: [linux-amd64, linux-arm64]
revisione_indipendente:
contesto_fresco: true
revisori_per_unita: 2
richiedi_ricerca_controesempio: true
rollout:
ore_ombra: 48
percentuali_canary: [1, 5, 20, 50, 100]
artefatto_rollback_richiesto: true
esercitazione_rollback_richiesta: true
manifesto_prove:
includi:
- versione_contratto
- commit_sorgente_e_destinazione
- unità_modificate
- comandi_e_codici_di_uscita
- discrepanze_differenziali
- riepilogo_fuzzing
- distribuzioni_benchmark
- inventario_non_sicuro_o_ffi
- risultati_revisori
- eccezioni_approvate
- risultato_esercitazione_rollback
Questi criteri impediscono deliberatamente agli operatori di implementazione di modificare il contratto o i test contrattuali approvati.
Richiedono:
- Artefatti di riferimento
- Revisione indipendente
- Quantitativo
Limiti delle Prestazioni
- Evidenza del rollout
- Un percorso di rollback testato
Sono possibili eccezioni, ma devono essere documentate e approvate, non nascoste all'interno di un prompt.
Misurare il Progresso Verificato, Non il Volume Generato
Linee di codice, numero di agenti e giorni trascorsi sono metriche di capacità interessanti. Non misurano il successo del prodotto.
Utilizzare una scorecard di migrazione equilibrata.
Throughput di Unità Verificate
Tracciare le unità di migrazione che:
- Compilano
- Superano i controlli contrattuali mirati
- Ricevono una revisione indipendente
- Si integrano senza regressioni
Misurare le unità accettate per unità di tempo.
Chiusura delle Discrepanze
Tracciare le differenze scoperte e se ciascuna è:
- Spiegata
- Risolta
- Approvata come intenzionale
- Ancora irrisolta
Difetti Sfuggiti
Tracciare i difetti che superano un gate che avrebbe dovuto intercettarli.
Ogni difetto sfuggito dovrebbe identificare una regola contrattuale, un test, un oracolo, un passaggio di revisione o una soglia di rollout mancanti.
Attenzione Umana
Misurare il tempo che gli umani dedicano a:
- Definire i contratti
- Risolvere ambiguità
- Revisionare codice ad alto rischio
- Investigare le discrepanze
- Gestire il deployment
L'IA può ridurre il tempo di implementazione aumentando al contempo la qualità delle specifiche. Questo è un buon compromesso, non un fallimento dell'automazione.
Costo di Calcolo e Strumenti
Misurare il costo totale di modello, calcolo e strumenti per unità accettata.
I flussi di lavoro dinamici possono consumare più token delle sessioni ordinarie. Il parallelismo è giustificato quando riduce i tempi di attesa per lavoro ad alto valore senza creare un arretrato di verifica più grande.
Manutenibilità Post-Migrazione
Tracciare:
- Tempo di avvio
- Velocità di build
- Tasso di fallimento delle modifiche
- Latenza di revisione
- Densità dei difetti
- Proprietà dei moduli non sicuri
- Facilità di debug
- Qualità della documentazione operativa
Una migrazione che viene rilasciata rapidamente ma rimane opaca per il team ha spostato il debito, non lo ha rimosso.
Come un Team Può Iniziare Senza una Riscrittura da un Milione di Righe
Scegliere una migrazione delimitata con un'implementazione di riferimento funzionante, come ad esempio:
- Un cambio di versione di un SDK
- Un sottosistema del framework
- Un comando CLI
- Un endpoint di servizio
Scrivere un contratto comportamentale di una pagina e tre casi pilota incentrati sul rischio.
Utilizzare compiti separati per l'implementazione e la revisione, in modo che i loro contesti rimangano indipendenti.
Prima dell'implementazione:
- Bloccare i controlli di accettazione.
- Richiedere che l'implementatore restituisca un commit e delle evidenze, non un'affermazione in prosa.
- Chiedere al revisore di trovare controesempi e identificare test mancanti.
- Eseguire i controlli nella CI al di fuori del modello.
- Espandere solo al successivo livello di dipendenza dopo il successo del pilota.
Mantenere un registro completo dell'esecuzione:
- Prompt
- Modello
- Ambito degli strumenti
- Commit sorgente
- Commit di destinazione
- Percorsi modificati
- Controlli
- Fallimenti
- Risultati del revisore
- Eccezioni
- Costo
- Decisione finale
Questo registro consente al team di confrontare le versioni dell'harness e investigare i difetti senza dover indovinare cosa ha visto l'agente.
Utilizzare una semplice regola di adozione:
L'autonomia deve essere guadagnata.
Un flusso di lavoro che produce ripetutamente unità verificate può ricevere un ambito di file più ampio o un runtime senza supervisione più lungo. Non riceve automaticamente il permesso di deployment.
Capacità, evidenza e autorità rimangono separate.
Limitazioni: Cosa il Caso Bun Non Dimostra
Bun è un progetto insolito.
Il suo creatore ha guidato il
migrazione, aveva una conoscenza approfondita del codebase e deteneva un'autorità architetturale diretta. La vecchia implementazione aveva un'ampia suite di test, Rust forniva un forte feedback dal compilatore e il progetto poteva utilizzare una potenza di calcolo parallela sostanziale.
La maggior parte dei team non condividerà tutti questi vantaggi.
Il caso è stato presentato anche tramite Anthropic, e l'articolo originale afferma che il lavoro ha utilizzato un modello prerelease Claude Fable 5. Si tratta di una prova primaria preziosa, ma non è un confronto indipendente tra fornitori.
Le affermazioni su quanto tempo avrebbe avuto bisogno un team umano sono stime controfattuali. I team non dovrebbero prendere decisioni di procurement basandosi su una singola migrazione di successo.
Le 19 regressioni segnalate sono regressioni note, non una garanzia del conteggio completo. Le esecuzioni di fuzzing e i cicli di revisione della sicurezza misurano lo sforzo, non l'assenza di difetti.
La conclusione più solida e difendibile è modesta:
Le migrazioni su larga scala guidate dall'IA sono fattibili se abbinate a un forte feedback deterministico e a una orchestrazione esperta, ma il loro rischio rimane un problema ingegneristico dopo il completamento della generazione del codice.
Questa conclusione è comunque significativa. I team possono tentare progetti di modernizzazione precedentemente ritardati per motivi di costo, a condizione che prevedano un budget per specifica, verifica e distribuzione controllata alla stessa scala dell'implementazione.
Checklist Pratica per la Migrazione
- Definire i comportamenti preservati, modificati, deprecati e sconosciuti.
- Fare un inventario dei contratti di piattaforma, performance, telemetria, errori ed effetti collaterali.
- Costruire una mappa semantica per i pattern rischiosi da sorgente a destinazione.
- Proteggere contratti e test approvati dagli addetti all'implementazione.
- Eseguire unità pilota difficili prima dell'espansione a tutto il repository.
- Isolare gli scrittori e limitare le operazioni Git e di rete distruttive.
- Richiedere commit atomici con comandi, output e riferimenti ai contratti.
- Utilizzare revisori avversari con contesto fresco per le unità ad alto rischio.
- Eseguire gate di compilatore, unità, contratto, integrazione e multipiattaforma.
- Confrontare implementazioni vecchie e nuove su corpora rappresentativi.
- Aggiungere controlli metamorfici, fuzz, sanitizer e di performance.
- Fare l'inventario dei confini di
unsafe, FFI, autenticazione, parser e persistenza. - Preservare un artefatto di rollback riproducibile ed eseguire una simulazione di rollback.
- Distribuire attraverso fasi shadow e canary con soglie di arresto automatico.
- Convertire ogni difetto sfuggito in un miglioramento del contratto o della verifica.
- Misurare unità verificate, discrepanze, attenzione umana, costo e manutenibilità.
FAQ
Cosa ha riscritto Bun in Rust?
Bun ha migrato un'implementazione importante che era stata precedentemente scritta in Zig in Rust. Il resoconto pubblicato descrive circa 780.000 righe di Rust e un flusso di lavoro altamente parallelo assistito dall'IA, seguito da test estesi, revisione della sicurezza, fuzzing e rafforzamento della produzione.
L'IA ha completato la riscrittura in Rust di Bun senza revisione umana?
No. Regole di migrazione scritte da umani, revisione manuale degli artefatti, flussi di lavoro isolati, feedback del compilatore, revisori agenti indipendenti, revisione della sicurezza, fuzzing e controlli di distribuzione in produzione hanno tutti giocato ruoli importanti. Il caso è meglio compreso come ingegneria accelerata dall'IA piuttosto che come conversione di codice incustodita.
Perché i test esistenti non sono sufficienti per una
migrazione del linguaggio?
I test esistenti di solito coprono solo una parte del comportamento osservato. Potrebbero non rilevare semantiche esclusive del rilascio, differenze tra piattaforme, regressioni delle prestazioni, confini non sicuri, modifiche alla telemetria o casi limite mai codificati nella suite.
Cos'è il test differenziale in una migrazione del codice?
Il test differenziale esegue le implementazioni vecchia e nuova con gli stessi input e confronta i loro output osservabili e gli effetti collaterali. È particolarmente utile quando il vecchio sistema è affidabile ma non esiste una specifica formale completa.
Perché i contesti di implementazione e revisione dovrebbero essere separati?
Un revisore nuovo ha meno probabilità di ereditare le ipotesi e gli errori di ragionamento dell'autore. Il revisore può concentrarsi sul contratto, il diff, le prove e i controesempi, piuttosto che difendere il percorso di implementazione che ha prodotto la modifica.
Come dovrebbero i team revisionare il codice Rust unsafe durante la migrazione?
Ogni blocco unsafe o confine FFI dovrebbe avere un proprietario nominato, invarianti documentate, test mirati e una chiara spiegazione della validità dei puntatori, della durata e della proprietà dei thread. L'analisi statica, i sanitizer, il fuzzing, la revisione delle dipendenze e la revisione manuale della sicurezza dovrebbero essere applicati separatamente dalla revisione del codice ordinaria.
Quali metriche dovrebbe tracciare una migrazione assistita dall'IA?
Traccia il throughput delle unità verificate, la chiusura delle discrepanze, i difetti sfuggiti, l'attenzione umana, il costo computazionale, lo stato del rollout e la manutenibilità post-migrazione. Le righe generate e il numero di agenti sono metriche di capacità, non prove di correttezza.
Un piccolo team può usare questo manuale senza eseguire decine di agenti?
Sì. Inizia con un componente limitato, un contratto di comportamento scritto, tre piloti focalizzati sul rischio, contesti di implementazione e revisione separati, cancelli CI deterministici e un percorso di rollback testato. Scala il flusso di lavoro solo dopo che produce ripetutamente risultati verificabili.
Strumenti correlati
- Bun: Un toolkit tutto-in-uno per JavaScript e TypeScript la cui migrazione a Rust fornisce il caso di studio principale per questo manuale.
- Rust: Un linguaggio di programmazione di sistema con forti garanzie di sicurezza a tempo di compilazione e confini
unsafeespliciti. - Claude Code: L'ambiente di codifica agentico di Anthropic, utilizzato nel flusso di lavoro dinamico descritto dal materiale sorgente.
- GitHub Actions: Una piattaforma CI/CD adatta per cancelli deterministici di compilazione, test, sicurezza, benchmark e prove.
- cargo-fuzz: Un tool di fuzzing standard per progetti Rust basato su libFuzzer.
- Miri: Un interprete Rust in grado di rilevare alcune forme di comportamento indefinito nel codice unsafe.
Link correlati
- Bun: Riscrivere Bun in Rust: Il resoconto ufficiale di Bun sulla riscrittura, l'indurimento in produzione, il fuzzing e le regressioni note.
- Repository sorgente di Bun: Il repository ufficiale di Bun contenente l'implementazione Rust, i problemi, i test e la cronologia della migrazione.
- [Anthropic: Introduzione ai flussi di lavoro dinamici](https://claude.
)blog/introducing-dynamic-workflows-in-claude-code): Descrizione di Anthropic del flusso di lavoro multi-agente utilizzato durante la migrazione di Bun.
- Claude Code Best Practices: Guida ufficiale su struttura delle attività, contesti di revisione freschi, test e flussi di lavoro di codifica a lungo termine.
- Claude Code Sandboxing: Spiegazione di Anthropic sull'isolamento del filesystem e della rete per una codifica autonoma più sicura.
- The Rustonomicon: Meet Safe and Unsafe: Guida ufficiale di Rust sul confine tra codice sicuro e non sicuro.
- GitHub CODEOWNERS Documentation: Documentazione di GitHub per la proprietà leggibile dalla macchina e i flussi di lavoro di revisione obbligatoria.
Riepilogo
La riscrittura di Bun in Rust dimostra che gli agenti di codifica AI possono comprimere drasticamente i tempi di implementazione, ma mostra anche perché la verifica deve diventare un sistema ingegneristico di prima classe. Contratti, mappe semantiche, lavoratori isolati, revisioni indipendenti, test differenziali, fuzzing, budget di prestazioni e distribuzione graduale sono ciò che trasforma il codice generato in una prova di migrazione credibile.
La lezione pratica non è copiare il numero di agenti o righe di codice. È suddividere una migrazione in affermazioni delimitate, richiedere prove deterministiche per ciascuna affermazione ed espandere l'autonomia solo dopo che il flusso di lavoro produce ripetutamente risultati affidabili.
Una grande riscrittura assistita dall'IA è completa solo quando il nuovo sistema è verificato, operabile, recuperabile e compreso, non quando il codice generato è stato unito.