Bun conclui migração de código de 11 dias impulsionada por IA do Zig para o Rust

iconMetaEra
Compartilhar
AI summary iconResumo
Bun anunciou um lançamento de projeto em maio de 2026, concluindo uma migração de código impulsionada por IA de Zig para Rust em 11 dias. O esforço envolveu mais de 1 milhão de linhas de código, 6.778 commits e 64 instâncias paralelas do Claude, custando US$ 165.000. O uso de memória caiu de 6,7 GB para 609 MB após 2.000 compilações, com ganhos de desempenho de 2 a 5%. O código agora inclui 13.000 palavras-chave unsafe e 19 regressões. A Anthropic agora possui o projeto. Esta atualização de notícias de IA + criptomoeda destaca uma mudança significativa na infraestrutura do projeto.
O projeto Bun concluiu, em maio de 2026, a migração significativa do Zig para o Rust, com mais de 1 milhão de linhas de código alteradas e 6.778 commits em 11 dias. A migração utilizou 64 instâncias do Claude trabalhando em paralelo, consumindo um custo de API de US$ 165.000. Após a migração, os vazamentos de memória foram resolvidos fundamentalmente: após 2.000 builds, a memória caiu de 6,7 GB para 609 MB de forma estável, com melhoria de desempenho de 2% a 5% e redução de cerca de 20% no tamanho do arquivo binário. No entanto, o código contém aproximadamente 13.000 palavras-chave unsafe — 178 vezes mais que projetos similares —, apresenta 19 problemas de regressão conhecidos e as 1 milhão de linhas alteradas não puderam ser revisadas linha a linha por humanos. Atualmente, o Bun foi adquirido pela Anthropic.

Autor e fonte do artigo: InfoQ

Em maio de 2026, o projeto Bun concluiu uma migração de código em larga escala, quase rara na história do desenvolvimento de software.

Essa migração começou em 3 de maio e foi oficialmente integrada à branch principal em 14 de maio, levando apenas 11 dias. Escrever o código levou apenas 6 dias, e todo o processo foi público. No entanto, Jarred Sumner levou quase um mês para escrever o blog post de resumo, muito mais tempo do que o necessário para escrever o código.

Este tempo de execução JavaScript originalmente continha 535.496 linhas de código Zig, sem incluir comentários; aproximadamente 20% do código foi escrito em C++ e incorporou várias bibliotecas C/C++. Esta reescrita para Rust, auxiliada por IA, envolveu mais de 1 milhão de alterações de código, 6.778 commits e a execução de cerca de 50 fluxos de trabalho dinâmicos no Claude Code.

De acordo com os dados divulgados por Sumner, esta reescrita consumiu 5,9 bilhões de tokens de entrada não armazenados em cache, 690 milhões de tokens de saída e 72 bilhões de leituras de tokens de entrada armazenados em cache, custando aproximadamente US$ 165.000 conforme a precificação da API.

Sumner disse que este é o limite atual da tecnologia disponível. Ele estimou que, se três engenheiros totalmente familiarizados com o código-base do Bun fizessem essa migração manualmente, levaria cerca de um ano, e durante esse período, a equipe quase não conseguiria avançar no desenvolvimento de novas funcionalidades, correções de bugs e correções de segurança.

Após esta reescrita, o Bun v1.3.14 será a última versão em Zig, e o Bun v1.4.0 será a primeira versão em Rust.

1 Resultado: da vazamento de memória de 6,7 GB para 609 MB estáveis

Bun começou como um projeto Zig com um escopo muito amplo: é ao mesmo tempo um transpilador JavaScript e TypeScript, um empacotador, um gerenciador de pacotes, um executor de testes, um resolvedor de módulos, um cliente HTTP e WebSocket, e também implementa a camada de API do Node.js. É exatamente essa amplitude de funcionalidades que levou o CLI do Bun a superar 22 milhões de downloads mensais e a receber o apoio de projetos e empresas como Vercel, Railway, DigitalOcean, Claude Code e OpenCode.

Mas essa mesma largura também trouxe alguns desafios para o Bun.

Especialmente no Bun v1.3.14, há um problema que vinha causando dor de cabeça há muito tempo: ao executar chamadas consecutivas de Bun.build(), a memória acumula-se continuamente e nunca é liberada. Cada construção vaza aproximadamente 3 MB, o que parece pouco, mas se você estiver executando um servidor de desenvolvimento onde cada requisição aciona uma construção, a memória será gradualmente consumida até o processo entrar em colapso.

Nos testes práticos, o uso de memória foi de 1,9 GB após 500 construções, 3,5 GB após 1.000, 5,1 GB após 1.500 e subiu para 6,7 GB após 2.000.

Isso é apenas a ponta do iceberg de muitos problemas de memória. Na lista de correções de bugs da v1.3.14, Sumner listou uma longa série de problemas:

Ao chamar .reset() no módulo zlib, se houver um .write() assíncrono ainda em execução no pool de threads, o processo entrará em colapso devido a "uso após liberação de heap"; no módulo http2, callbacks JavaScript aninhados desencadeiam uma rehashing da tabela de hash, tornando os ponteiros internos de fluxo inválidos; ao iterar, UDPSocket.sendMany() sofre escrita fora dos limites se o código do usuário alterar o estado de conexão do soquete por meio de callbacks valueOf ou toString; quando a alocação do buffer de saída falha em crypto.scrypt, o callback e o buffer de senha protegido nunca são liberados; ......

A característica comum desses bugs é muito clara — eles quase todos apontam para a mesma origem: a combinação de GC e gerenciamento manual de memória no mesmo software.

Motores modernos como JavaScriptCore (e V8) possuem regras extremamente rigorosas para tratamento de exceções e GC, enquanto Zig, como C, não gerencia memória automaticamente. Quando esses dois paradigmas coexistem no mesmo processo, cada alocação de memória precisa ser revisada linha por linha: onde esses bytes são liberados? Como garantir que sejam liberados apenas uma vez? Os exceções do JavaScript foram verificadas corretamente? Este ponteiro gerenciado pelo GC é visível para o scanner conservativo de pilha? É memória gerenciada por GC ou memória gerenciada manualmente?

Mais preocupante ainda é que a equipe não deixou de se esforçar. Eles já modificaram o compilador Zig, adicionaram suporte ao Address Sanitizer (ASAN), executam testes ASAN em cada commit no CI, constroem com ReleaseSafe no Windows, realizam testes de fuzzing 24/7 com o Fuzzilli e realizam inúmeros testes de vazamento de memória end-to-end. Mesmo assim, os relatórios de falhas continuam chegando em grande número.

“Nossa lista de correções de bugs é frustrante; estou cansado de dormir com medo de o Bun travar,” escreveu Sumner. Ele não culpa o Zig — outros usuários do Zig não enfrentam problemas com o Bun, pois combinar GC com gerenciamento manual de memória é uma exigência extremamente rara, quase nenhuma linguagem foi projetada para isso.

Já a versão Rust apresentou o seguinte resultado: ao executar 2000 vezes Bun.build(), a memória permaneceu estável em 609 MB.

Além da resolução fundamental do problema de vazamento de memória, a reescrita em Rust trouxe melhorias em vários outros aspectos.

Em termos de estabilidade, a v1.4.0 corrige 128 bugs reprodutíveis da v1.3.14, abordando problemas desde vazamentos de memória até falhas e mensagens de ajuda com erros de cor.

Em termos de tamanho, combinando a reescrita em Rust, alterações no ICU e o mesmo recuo de código, o Bun reduziu em cerca de 20% o tamanho dos arquivos binários no Linux e no Windows.

Em termos de desempenho, houve uma melhoria geral de 2% a 5%. O Bun.serve aumentou de 169.600 req/s para 177.700 req/s, e o node:http aumentou de 103.800 para 108.500. Em cenários práticos, o next build reduziu de 13,62 segundos para 13,03 segundos, e a compilação em lote do tsc reduziu de 0,94 segundo para 0,89 segundo.

Após o Claude Code ser lançado com base no Rust Bun, o tempo de inicialização no Linux caiu de 517 ms para 464 ms, uma melhoria de cerca de 10%.

2 Métodos: 64 Claude, 11 dias, 50 fluxos de trabalho

Como Sumner conseguiu isso pode ser a parte mais importante de se prestar atenção — porque o método que ele usou é diferente do tradicional "fazer a IA escrever código".

Sumner dividiu todo o processo em cerca de 50 fluxos de trabalho dinâmicos, cada um sendo um ciclo. Ele descreveu esse padrão em seu blog usando pseudocódigo:

Cada tarefa tem um contexto (por exemplo, um ticket no Jira ou uma issue no GitHub), o Claude escreve o código com base nesse contexto, e dois revisores (também o Claude) revisam o código, aplicando, por fim, os feedbacks. Após concluído, a próxima tarefa é iniciada.

Esse padrão se mantém ao longo de todo o processo de reescrita. Cada fluxo de trabalho é responsável por um objetivo específico:

  • Gerar um guia de portagem que mapeie os padrões e tipos do Zig para os padrões e tipos do Rust;
  • Mova mecanicamente cada arquivo .zig para um arquivo .rs, correspondendo ao PORTING.md e ao LIFETIMES.tsv;
  • Corrigir os erros de compilação de cada crate;
  • Faça os subcomandos como bun test ou bun build funcionarem;
  • Faça todos os testes do conjunto de testes do Bun passarem; realize várias rodadas de refatoração e limpeza em larga escala.

No pico, Sumner executava simultaneamente 4 fluxos de trabalho, cada um com 16 Claude, totalizando 64 Claude trabalhando em paralelo em 4 árvores de trabalho, enviando e empurrando arquivos individualmente. No pico máximo, o Claude escrevia cerca de 1.300 linhas de código por minuto.

Esse design de separação entre “implementador / revisor” é essencial. O Claude que escreve o código tem viés, assim como engenheiros humanos, e quer que o código seja aceito. Por isso, revisores e implementadores são totalmente separados — os revisores veem apenas as diferenças no código, sem acessar o raciocínio do implementador, e são explicitamente instruídos a “assumir que o código está errado”. Cada implementador é avaliado por mais de dois revisores adversariais, cujo único trabalho é encontrar bugs.

Escrever o código é apenas o primeiro passo. O código Zig é unidade única de compilação, enquanto o Rust precisa ser dividido em cerca de 100 crates para acelerar a compilação; dependências cíclicas causaram o cargo check gerar aproximadamente 16.000 erros de compilação de uma só vez. Para uma pessoa, isso seria um desastre, mas para 64 Claudes trabalhando em paralelo, é apenas uma fila de tarefas gerenciável. O fluxo de trabalho agrupa os erros por crate, executa o cargo check para cada crate, um Claude corrige, dois revisam e um aplica as alterações.

A seguir, execute bun --version e depois bun test. O fluxo de testes executa aleatoriamente 100 arquivos de teste, divididos em 4 árvores de trabalho. O conjunto de testes também inclui vários tipos: alguns testes executam por mais de um minuto, outros esgotam o número de conexões TCP do sistema, e alguns fazem fork de aproximadamente 10.000 processos. Sumner usou systemd-run para criar cgroups para limitar recursos, mas a máquina ainda sofreu várias falhas por falta de espaço em disco.

Dois dias depois, os testes falhos na plataforma Linux caíram de 972 para 23. Um dia e meio depois, o Linux estava totalmente verde. Cinco dias depois, todos os seis plataformas — Linux x64, Linux arm64, macOS x64, macOS arm64, Windows x64, Windows arm64 — passaram.

Em 14 de maio, o PR #30412 foi oficialmente mesclado, e todos os testes do conjunto foram aprovados, sem pular ou remover nenhum teste.

3 Preocupações: 13.000 códigos unsafe e não passíveis de revisão linha a linha

No entanto, Sumner também reconheceu que esse trabalho ainda não foi realmente concluído.

Até o momento, cerca de 4% do código Rust do Bun está dentro de blocos unsafe, com aproximadamente 13.000 palavras-chave unsafe distribuídas em cerca de 27.000 linhas de código, enquanto o código Rust total é de aproximadamente 780.000 linhas. Dos blocos unsafe, 78% possuem apenas uma linha, geralmente um ponteiro proveniente do C++ ou uma única chamada para uma biblioteca C.

Ele espera que a reestruturação subsequente reduza essa proporção. Mas alguém fez um cálculo: o uv possui cerca de 350 mil linhas de código e apenas 73 chamadas unsafe. Já o Bun tem 178 vezes mais chamadas unsafe que o uv. Essa diferença é difícil de explicar apenas com a necessidade de chamar bibliotecas C.

E posteriormente, comportamento indefinido também foi exposto em código Rust seguro. Isso é mais difícil de depurar do que em C++, pois você acredita que código seguro não pode ter problemas.

A equipe Bun depois alterou o PathString::init desse problema para uma função unsafe.

Sumner também reconheceu que esta reescrita introduziu 19 problemas de regressão conhecidos e afirmou que a maioria dos problemas de regressão surgiu de código com a mesma sintaxe, mas semântica diferente.

Por exemplo, esses dois trechos de código parecem muito semelhantes, mas se comportam de forma totalmente diferente. O assert do Zig é uma função, portanto seus parâmetros são executados em cada compilação. O debug_assert! do Rust é uma macro, portanto, nas versões de lançamento, toda a expressão (incluindo a chamada de função) é removida insert_stale.

Embora todos os problemas tenham sido corrigidos, isso não significa que o código de IA com milhões de linhas não tenha outros problemas.

Quem em sã consciência migraria sua aplicação de produção imediatamente após uma reescrita completa do tempo de execução? Achar que a versão 1.4 não introduziu novos bugs ou mudanças de comportamento é ingênuo.

Outro ponto que não pode ser ignorado é a revisão de código. Revisar 1 milhão de linhas de alterações é impossível para um ser humano fazer linha por linha — mesmo que se levasse um minuto por linha, seriam necessários 11,7 dias ininterruptos; já com a velocidade real de revisão de código (200 linhas por hora), levaria mais de dois anos para terminar.

Os revisores deste PR foram principalmente claude[bot] e coderabbitai[bot]. Sumner também admitiu que seu método de revisão era “verificar se o agente de revisão adversarial capturou corretamente as diferenças, garantindo que as diretrizes de conversão fossem seguidas, enquanto ele mesmo leu manualmente uma boa quantidade de código”. Mas ele não especificou quantas “boas quantidades” foram lidas.

Outro problema inevitável: o Bun foi adquirido pela Anthropic em dezembro de 2025, e a única ferramenta capaz de manter efetivamente esse repositório de código é o próprio Claude. Alguns na comunidade afirmam que isso já não pode ser considerado um projeto de código aberto no sentido tradicional — para enviar um PR ao Bun, você precisa assinar a Anthropic ou depender dos poucos membros centrais que já compreenderam o código gerado por IA.

Vale a pena 165 mil dólares por um ano de trabalho?

Sumner também revelou no blog que o custo da reescrita da API foi de aproximadamente US$ 165.000, equivalente ao trabalho de três engenheiros durante um ano. Esse número gerou uma discussão acalorada no Hacker News.

Alguns consideram que essa conta na verdade é muito vantajosa. Com 165 mil dólares, não se contrata muitos engenheiros de tempo integral em Silicon Valley, muito menos engenheiros de empresas do nível da Anthropic. De acordo com os dados salariais do levels.fyi, a remuneração total de um engenheiro da Anthropic provavelmente alcança 500 mil dólares ou mais. Mesmo considerando uma média aproximada de 336 mil dólares por ano para 50 engenheiros, isso equivale a cerca de 1.292 dólares por dia. Para 50 pessoas trabalhando continuamente por 11 dias, apenas o custo com mão de obra já se aproxima de 710 mil dólares, sem contar benefícios, espaço físico, equipamentos e outras despesas administrativas.

No entanto, Sumner usou a versão pré-lançamento do Claude Fable 5, um modelo avançado ainda não disponível ao público e possivelmente sujeito a restrições de exportação. Assim, o preço da API é apenas o número visto pelo usuário final, por trás do qual há enormes investimentos em P&D da Anthropic. Alguém também apontou que reduzir os custos ao preço da API é uma tentativa deliberada de minimizar o verdadeiro investimento. Se forem considerados os custos de desenvolvimento do modelo, treinamento, infraestrutura de computação e mão de obra de engenharia, acredita-se que o custo total final seja certamente muito alto, provavelmente superando US$ 1,5 milhão.

E, aparentemente, trocar 165 mil dólares por um ano de trabalho parece bastante vantajoso.

Mas o verdadeiro custo não está nessa fatura. Este repositório tem 6.778 commits, e ninguém leu completamente de ponta a ponta; embora tudo esteja funcionando bem agora, e daqui a seis meses? Quando um estranho problema de concorrência surgir repentinamente às 3 da manhã, o engenheiro de plantão enfrentará um sistema cuja lógica interna ele mesmo não consegue explicar. Estender isso para o futuro significa que o AI terá que mantê-lo — como calcular esse custo de manutenção? Na verdade, é bem difícil.

Aviso legal: as informações nesta página podem ter sido obtidas de terceiros e não refletem necessariamente os pontos de vista ou opiniões da KuCoin. Este conteúdo é fornecido apenas para fins informativos gerais, sem qualquer representação ou garantia de qualquer tipo, nem deve ser interpretado como aconselhamento financeiro ou de investimento. A KuCoin não é responsável por quaisquer erros ou omissões, ou por quaisquer resultados do uso destas informações. Os investimentos em ativos digitais podem ser arriscados. Avalie cuidadosamente os riscos de um produto e a sua tolerância ao risco com base nas suas próprias circunstâncias financeiras. Para mais informações, consulte nossos termos de uso e divulgação de risco.