Frontier · Bun Blog
Reescribir Bun en Rust
Jarred Sumner explica por qué y cómo se reescribió el paquete de Bun de Zig a Rust, incluidos los bucles de codificación agente, la revisión adversaria, las pruebas y el trabajo de rendimiento detrás de la migración.

Este artículo ha sido traducido del texto original en inglés.
Edición de texto: las figuras de datos, visualizaciones interactivas y diagramas de flujo del original no se reproducen aquí. Consulte la fuente para ver los gráficos completos.
Divulgación: Bun fue adquirida por Anthropic en diciembre de 2025. Yo y otros miembros del equipo de Bun trabajamos en Anthropic. Utilicé una versión preliminar de Claude Fable 5 durante gran parte de la reescritura de Rust.
Bun comenzó como una adaptación línea por línea del transpilador JavaScript y TypeScript de esbuild desde Ir a Zig. Escribí mi primera línea de Zig el 16 de abril de 2021. Apuesto a Zig después de ver la Zig Referencia del lenguaje de una sola página en Hacker News y de entusiasmarme mucho con el control de bajo nivel y el cuidado del rendimiento.
Desde el principio, el alcance de Bun fue enorme:
- JavaScript, TypeScript y transpilador, minificador y empaquetador de CSS
- administrador de paquetes compatible con npm
- Jestcorredor de pruebas tipo
- Resolución de módulo compatible con Node.js y TypeScript
- HTTP/1.1 y cliente WebSocket
- Implementaciones de API de Node.js como
fs,net,tlsy docenas de otros módulos
La versión inicial de Bun fue escrita por mí en 1 año, en un apartamento estrecho de Oakland, antes de LLM, en Zig. El resultado predeterminado para proyectos de alcance ambicioso como Bun es unirse al cementerio de proyectos muertos en una página de perfil de GitHub. Zig hizo posible Bun. Nunca habría podido construir tanto en 1 año si no fuera por Zig.
Hoy en día, la CLI de Bun recibe más de 22 millones de descargas mensuales. Herramientas populares como Claude Code y OpenCode apuestan por Bun como tiempo de ejecución. Vercel, Railway, DigitalOcean y más tienen soporte propio para Bun.
Bun también ha sido un desafío para la estabilidad. Aquí hay una pequeña muestra de errores que solucionamos en Bun v1.3.14:
- Se bloquea el uso después de la liberación del montón en
node:zlibal llamar a.reset()en una secuencia zlib, Brotli o Zstd mientras un.write()asíncrono todavía está en progreso en el grupo de subprocesos - fallo de uso después de la liberación en
node:zlibcuando una devolución de llamadaonerroremitió un reentrantewrite()seguido declose()en identificadores nativos - use-after-free falla en
node:http2cuando las devoluciones de llamadas JS reentrantes (por ejemplo,session.request()dentro de un detector de tiempo de espera, un captador de opciones o una devolución de llamada de escritura) activaron una repetición de hashmap, invalidando los punteros de flujo internos - use-after-free en
UDPSocket.send()ysendMany()donde el código de usuario en las devoluciones de llamadavalueOf()otoString()podría separar unArrayBufferentre la captura de carga útil y el envío real - bloqueo y lectura fuera de límites en
Buffer#copyyBuffer#fillcuando una devolución de llamadavalueOfsepara o cambia el tamaño delArrayBuffersubyacente durante la coerción de argumento - escritura fuera de límites del montón en
UDPSocket.sendMany()cuando el estado de la conexión del socket cambió a mitad de la iteración a través de devoluciones de llamada JS del usuario - pérdida de memoria en
crypto.scryptdonde la devolución de llamada y la contraseña protegida/búferes salt nunca se liberaron cuando falló la asignación del búfer de salida SSLWrapper.initfiltró la frase de contraseña de strdup en rutas de error- pérdida de memoria en
tlsSocket.setSession()donde cada llamada perdió unSSL_SESSION(~6,5 KB por llamada) debido a que falta unSSL_SESSION_freedespués ded2i_SSL_SESSION - pérdida de memoria donde los observadores
fs.watch()nunca fueron recolectados como basura después de.close(), causado por un desbordamiento insuficiente del recuento de referencias que fijó permanentemente a cada observador como raíz de GC - fallo de doble liberación en el analizador CSS cuando
background-cliptenía prefijos de proveedor y fondos multicapa DuplexUpgradeContextnunca se liberó: una filtración completa portls.connect({ socket: duplex })- caída de la condición de carrera en
MessageEventdonde el subproceso del marcador GC podría observar una variante rota enm_datadurante el acceso simultáneo desde unBroadcastChanneloMessagePort
Podríamos haber seguido solucionando este tipo de errores una sola vez a perpetuidad, pero se lo debemos a nuestros usuarios, que cuentan con nosotros para hacerlo mejor y evitar sistemáticamente que este tipo de errores se repitan.
Lo que ya estábamos haciendo
- Parchamos el compilador Zig para agregar compatibilidad con Address Sanitizer. Ejecutamos nuestro conjunto de pruebas con ASAN en cada confirmación.
- Enviamos Zig compilaciones ReleaseSafe con seguridad comprobada en Windows
- Fusionamos las API de tiempo de ejecución de Bun las 24 horas del día, los 7 días de la semana usando Fuzzilli, el fuzzer del motor JavaScript utilizado por V8 y JavaScriptCore
- Tenemos una gran cantidad de pruebas de pérdida de memoria de un extremo a otro
Esto es más de lo que hacen muchos proyectos.
¿Sé realmente inteligente y no cometas errores?
Nuestra lista de correcciones de errores se sentía mal y estaba cansado de irme a dormir preocupándome por fallas en Bun. No culpo a Zig por eso: otros usuarios de Zig no tienen los errores que nosotros tuvimos, y mezclar GC con memoria administrada manualmente es algo tan poco común como para que el software lo necesite, por lo que ningún lenguaje realmente diseña para ello. No hubiéramos llegado tan lejos si no fuera por Zig y siempre estaré agradecido. Hasta hace muy poco, la elección del lenguaje de programación era una decisión unidireccional para un proyecto como Bun.
JavaScript es un lenguaje de recolección de basura y los motores JavaScript modernos como JavaScriptCore (y V8) tienen reglas estrictas sobre el manejo de excepciones y el recolector de basura. Zig, al igual que C, no administra la memoria por usted y esta es una compensación que para muchos proyectos es una gran razón para usar Zig. Zig no tiene constructores/destructores y se espera que la mayor parte de la limpieza se escriba explícitamente en cada sitio de llamada con defer.
Para Bun, manejar correctamente la vida útil de los valores recolectados como basura y los valores administrados manualmente ha sido una fuente importante de problemas de estabilidad: en la mayoría de los casos, pequeñas pérdidas de memoria y, ocasionalmente, fallas. Cada asignación de memoria debe revisarse meticulosamente. ¿Dónde se liberan estos bytes? ¿Cómo nos aseguramos de que solo se libere una vez? ¿Comprobamos correctamente las JavaScript excepciones? ¿Este puntero recolectado como basura es visible para el escáner de pila conservador? ¿Se trata de memoria recolectada como basura o memoria administrada manualmente?
Para problemas de estabilidad, lo mejor es saberlo lo antes posible. La confusión ocurre después de fusionar el código. La CI ocurre cuando se inserta el código. Las comprobaciones de seguridad en tiempo de ejecución y el saneamiento de direcciones se realizan cuando se ejecuta el código (con suerte, en desarrollo, antes de CI).
Una forma común de reducir este tipo de problema es garantizar que el código de limpieza siempre se ejecute exactamente una vez para el código que lo necesita. Zig está diseñado para ser un lenguaje simple sin flujo de control oculto, por lo que prefiere la palabra clave explícita defer para ejecutar código al final de un alcance en lugar del ~Destructor implícito de C++ o el Drop implícito de Rust.
| Idioma | Limpieza |
|---|---|
| Zig | defer, errdefer |
| C++ | ~Destructor, &&Mover |
| Rust | Soltar |
Para el código Zig, ¿cuándo exactamente deberíamos ejecutar el código de limpieza? Si pasamos el mismo *T a muchas funciones diferentes, ¿cómo sabemos cuándo ya no es accesible y se puede limpiar? ¿Cómo funciona cuando algunas funciones necesitan continuar haciendo referencia a la memoria después de llamar a la función? Nuestro enfoque actual es una combinación de:
- vida útil de la arena, donde el alcance de cuándo es accesible es claro (el estado del analizador no escapa a la función de llamada y, por lo tanto, los nodos AST son una buena opción allí)
- recuento de referencias
- presta mucha atención
Muchos proyectos optan por responder este tipo de preguntas a través de una guía de estilo. La TigerStyle de TigerBeetle es un ejemplo en Zig y la guía de estilo C++ de 31.000 palabras de Google es otro. El desafío de las guías de estilo es su cumplimiento. ¿Cómo te aseguras de que se siga la guía de estilo? Históricamente, la revisión del código era la respuesta con la mejor aplicación mediante linters y analizadores estáticos.
Tener una guía de estilo rígida con expectativas claras de propiedad detalladas explícitamente en el sistema tipográfico fue una opción real para Bun. Dado que Zig no tiene sobrecarga de operadores, probablemente terminaríamos con una gran cantidad de código parecido a este:
fn foo(a_ptr: SharedPtr(TCPSocket)) !void {
const a: *TCPSocket = a_ptr.get();
defer a_ptr.deref();
const b = try do_something_with_a(a);
defer b.deref();
// ...
}
Esto es menos ergonómico que el Zig que esperábamos:
fn foo(a: *TCPSocket) !void {
const b = try do_something_with_a(a);
// ...
}
¿Qué pasa con C/C++?
Aproximadamente el 20% del código de Bun está escrito en C++ y Bun incorpora varias bibliotecas de C/C++:
- JavaScriptCore, el motor JavaScript que impulsa Safari
- uWebSockets y usockets: nuestro servidor HTTP/WebSocket y bucle de eventos
- lshpack & lsquic - bibliotecas
HPACKy HTTP/3 - BoringSSL, la bifurcación OpenSSL de Google
- SQLite
C++ en lugar de Zig sería una opción razonable para Bun. Obtendríamos constructores y destructores. Podríamos eliminar muchos extern "C" código contenedor.
Sin embargo, todavía dependeríamos de las guías de estilo aplicadas mediante la revisión de código, e incluso con ASAN, aún se producirían daños y pérdidas de memoria.
¿Por qué Rust?
Un gran porcentaje de errores de esa lista son de uso después de la liberación, de doble liberación y de "olvidé liberar" en una ruta de error. En Rust seguro, estos son errores del compilador y limpieza automática similar a RAII con Drop. Los errores del compilador son un mejor circuito de retroalimentación que una guía de estilo.
Históricamente, las reescrituras son una idea terrible. Excluyendo comentarios, Bun son 535.496 líneas de Zig. Reescribirlo en otro idioma requeriría un año completo para un pequeño equipo de ingenieros. Significaría congelar correcciones de errores, correcciones de seguridad o desarrollo de funciones para ese momento. El enfoque menos riesgoso para conseguir algo que se pueda enviar sería un puerto mecánico de Zig a Rust, con un número mínimo de cambios de comportamiento, utilizando exactamente el mismo conjunto de pruebas que ya utilizamos para probar Bun.
Afortunadamente, el propio conjunto de pruebas de Bun está escrito en TypeScript, lo que significa que no depende del lenguaje de programación del tiempo de ejecución.
Un año sin impacto para los usuarios no es una opción realista que podamos considerar. Por lo tanto, la aplicación mediante estilo de código para solucionar problemas de estabilidad fue nuestra mejor opción, y fue nuestro plan cuando agregamos punteros inteligentes inspirados en Rust al código base de Bun.
Pero, sinceramente, no quería hacerlo. Los punteros inteligentes de fabricación propia ofrecen peor ergonomía que Rust y no ofrecen ninguna de las garantías.
¿Qué pasa si, en cambio, paso una semana probando si el nuevo modelo de Anthropic puede reescribir Bun en Rust?
Al principio, no esperaba que funcionara. Unos días después, un alto porcentaje del conjunto de pruebas comenzó a aprobarse y vi en qué medida coincidía el nuevo código Rust con el código base Zig original. Mi opinión pasó de "vale la pena intentarlo" a "voy a fusionarlo".
Claude, reescribe Bun en Rust.
Hay muchas maneras de hacer un trabajo terrible con esto. Por ejemplo, pedirle a Claude "Reescribe Bun en Rust. No cometas ningún error". y luego rezar para que funcionara no es lo que hice.
Piensa en cómo una persona haría esto. La primera gran pregunta es:
¿Reescritura incremental? ¿O todo a la vez?
En mi experiencia al trasladar el transpilador de esbuild desde Ir a Zig para la versión inicial de Bun (sin LLMs), todo a la vez es mejor. Una reescritura incremental agrega código temporal que esperas que se elimine eventualmente y que sería doloroso a corto y mediano plazo.
La segunda gran pregunta: ¿cómo?
¿Cómo mantenemos Bun en Rust igual Bun que antes, con la misma arquitectura, rendimiento y conjunto de características y al mismo tiempo obtenemos las características del lenguaje de Rust como el verificador de préstamos? ¿Cómo nos aseguramos de que el equipo pueda seguir manteniéndolo después de la reescritura?
Haga la reescritura que parece que hemos transpilado nuestro código Zig a Rust. Podemos refactorizarlo gradualmente para reducir el uso de unsafe y que parezca más idiomático Rust después de que se publique Bun v1.4.
Esas son las únicas dos grandes preguntas. Todo lo demás son tácticas.
Bucles que escriben y revisan código
Gran parte del trabajo de ingeniería diario de los ingenieros de software se puede simplificar demasiado en bucles.
// Pseudocode, not real code:
let task;
while ((task = todoList.pop())) {
const result = task();
const feedback = await Promise.all([review(result), review(result)]);
await apply(feedback, result);
}
Un task tiene algún contexto asociado (un ticket de Jira, un problema de GitHub, etc.). El result es el código que escribiste para solucionarlo. Revisor(es) de código review los cambios para comprobar las regresiones y la corrección. Y luego abordas los comentarios.
Reescribí Bun en Rust usando alrededor de 50 flujos de trabajo dinámicos en Claude Code ejecutados continuamente durante el transcurso de 11 días.
Cada flujo de trabajo dinámico era un bucle como este: un flujo de trabajo para:
- Generar una guía de portabilidad que asigne Zig patrones y tipos a Rust patrones y tipos
- Transfiera mecánicamente cada archivo
.ziga un archivo.rs, coincidiendo con PORTING.md y LIFETIMES.tsv - Corregir los errores del compilador de cada caja
- Hacer que subcomandos como
bun testobun buildfuncionen - Haga que todas las pruebas del conjunto de pruebas completo de Bun pasen
- Varias refactorizaciones grandes y pases de limpieza
Durante la mayor parte de esos 11 días (y después), supervisé los flujos de trabajo: leí manualmente los resultados para comprobar si había problemas y errores, y le pedí a Claude que editara el bucle para arreglar las cosas.
¿Cómo se revisa un PR con más de 1 millón de líneas agregadas? ¿Cómo se puede empezar a generar la confianza necesaria para fusionar de forma responsable grandes cantidades de código escrito por LLM?
Un conjunto de pruebas independiente del lenguaje con un millón de afirmaciones, revisión de código adversario y, cuando algo sale mal, arregla el proceso que genera el código en lugar de arreglarlo manualmente.
Revisión contradictoria
La revisión contradictoria le pide a Claude (en una ventana contextual separada) que explique exhaustivamente las razones por las cuales los cambios crean errores o no funcionan.
Ventanas de contexto divididas
Por lo general, con los humanos, la persona que revisa el código no es la persona que lo escribió. La persona que escribe el código quiere fusionarlo, lo que puede influir en sus acciones para que se envíe antes de que esté listo.
Claude es igual. El Claude que escribió el código quiere que el código sea aceptado. El Claude que revisa quiere encontrar problemas en el código.
1 implementador, 2 o más revisores contradictorios por implementador. El único trabajo del revisor: encontrar errores y razones por las que el código no funciona. El implementador no revisa. El revisor no implementa.
error 1 de 3 · el cierre asíncrono
su contexto: el .zig original, el plano portuario, su propio razonamiento
su contexto: solo la diferencia. Se le dice que asuma que el código es incorrecto.
src/runtime/api/bun/js_bun_spawn_bindings.rs · compila limpio
para stdio en [spawned_stdout, spawned_stderr] {
coincidir con stdio {
StdioResult::Buffer(mutación de tubería) => {
// pipe: Boxuv::Pipe — entrégaselo a libuv para cerrar
pipe.close(Subproceso::on_pipe_close)
}
StdioResult::Fd(fd) => fd.close(),
StdioResult::No disponible => {}
}
}
uv_close es asíncrono: libuv mantiene el puntero del identificador sin formato hasta el siguiente ciclo, luego llama a_pipe_close, lo que libera la asignación. Pero `pipe` es una caja que cae al final de este brazo de coincidencia: libuv queda con la memoria liberada y la devolución de llamada de cierre la libera por segunda vez. Uso posterior gratuito y luego doble gratuito.
Box::leak(tubería).close(Subproceso::on_pipe_close)
f0a454376c7 · win-review: js_bun_spawn_bindings.rs fuga Boxuv::Pipe antes de async uv_close para evitar UAF/doble liberación en on_pipe_close
Tres errores que los revisores adversarios realmente detectaron: cada confirmación citada lleva su atribución de revisión en la línea de asunto. Los tres compilados; los tres parecían plausibles. El revisor es un segundo Claude en su propia ventana de contexto: obtiene la diferencia y nada más (ninguno del razonamiento del implementador) y se le dice que encuentre la forma en que está equivocado. El código está condensado de las confirmaciones citadas; Los mismos errores, las mismas correcciones.
¿Cómo se ve esto?
Si está a punto de hacer algo grande y costoso, le ahorrará tiempo y dinero eliminar el riesgo primero.
Trabajo de preparación
Antes de escribir cualquier código, pasé aproximadamente 3 horas hablando con Claude sobre cómo asignar patrones de nuestro código base Zig estrechamente a Rust. Claude serializó esta discusión en un documento PORTING.md, que terminó en Hacker News.
La siguiente pregunta: ¿cómo se agregan Rust tiempos de vida al código que administra la memoria manualmente?
Ahí es donde le pedí a Claude algo como esto:
Yo: Iniciemos un flujo de trabajo dinámico para analizar la duración adecuada de cada campo de estructura en el código base. Este flujo de trabajo debe leer cada campo de estructura dentro de cada archivo y rastrear el flujo de control. Primero, busque campos de estructura con tiempos de vida complejos para express en Rust, luego proponga un tiempo de vida para ese campo, luego use 2 agentes de revisión adversarios para revisar ese tiempo de vida, luego aplique cualquier comentario y serialícelo en un LIFETIMES.tsv para que otros claudes lo vean.
Luego, se realiza una ronda de revisiones contradictorias sobre PORTING.md y LIFETIMES.tsv juntas para corregir cualquier sugerencia contradictoria y volver a verificar todo. También lo leí manualmente.
Ejecución de prueba
Antes de pedirle a Claude que tradujera los 1,448 archivos .zig a archivos .rs, comencé con solo 3. Para cada uno de los 3 archivos, 1 implementador escribió el nuevo archivo .rs, 2 revisores adversarios verificaron que el archivo .rs coincidiera con el comportamiento del archivo .zig y que siguiera los PORTING.md y LIFETIMES.tsv. Después de eso, 1 reparador aplicó las sugerencias.
Comienzos en falso
Le pedí a Claude que repitiera el flujo de trabajo en los 1448 archivos .zig y, aproximadamente 2 minutos después, Claude ejecutó git stash antes de confirmarlo. Otro ejecutó git stash pop. Y luego git reset HEAD --hard. ¡Se estaban pisando el uno al otro! Y si coloco cada Claude en un árbol de trabajo separado, me quedaría sin espacio en disco porque el repositorio git de Bun es demasiado grande y eventualmente los cambios deberán compilarse y verse juntos.
Entonces, le pedí a Claude que editara el flujo de trabajo para indicarle que nunca ejecutara git stash o git reset ni ningún comando git que no confirmara un archivo específico a la vez. Tampoco cargo. No hay ningún comando lento.
Luego, Claude reanudó los flujos de trabajo. ¡Y estaba funcionando! Demasiado lento, así que lo dividí en solo 4 fragmentos de flujo de trabajo, cada uno con su propio árbol de trabajo (4 árboles de trabajo en total), cada uno ejecutando 16 claudes confirmando y enviando archivos.
Finalmente escribiendo el código
Gracias a toda la paralelización y este trabajo de preparación, en el pico, Claude escribió alrededor de 1300 líneas de código por minuto. Cada línea de código fue revisada por dos revisores adversarios separados (también Claude) y pasó por una ronda de correcciones antes de comprometerse. Absolutamente nada de eso funcionó todavía.
11 días × 24 horas · PDT
5.463 confirmaciones
1695 confirmaciones/hora
12 a. m. 6 a. m. 12 p. m. 6 p. m. 4 de mayo 4 de mayo, 7 a. m. a 8 a. m. PDT: 6 confirmaciones, +89 278 líneas 4 de mayo, 8 a. m. a 9 a. m. PDT: 2 confirmaciones, +50 742 líneas 4 de mayo, 9 a. m. a 10 a. m. PDT: 1 confirmación, +28 149 líneas 4 de mayo, 11 a. m. a 12 p. m. PDT: 1 confirmación, +39,752 líneas 4 de mayo, 12 p. m. a 1 p. m. PDT: 3 confirmaciones, +251 616 líneas 4 de mayo, 1 p. m. a 2 p. m. PDT: 2 confirmaciones, +161 724 líneas 4 de mayo, 3 p. m. a 4 p. m. PDT: 3 confirmaciones, +136 381 líneas 4 de mayo, 5 p. m. a 6 p. m. PDT: 5 confirmaciones, +895 líneas 4 de mayo 6 p. m. a 7 p. m. PDT: 5 confirmaciones, +17 027 líneas 4 de mayo, 7 p. m. a 8 p. m. PDT: 1 confirmación, +106 líneas 4 de mayo, 9 p. m. a 10 p. m. PDT: 13 confirmaciones, +11 661 líneas 4 de mayo, 11 p. m. a 12 a. m. PDT: 6 confirmaciones, +8 516 líneas 5 de mayo 5 de mayo, 12 a. m. a 1 a. m. PDT: 9 confirmaciones, +1381 líneas 5 de mayo, 1 a.m. a 2 a.m. PDT: 7 confirmaciones, +1577 líneas 5 de mayo, 2 a.m. a 3 a.m. PDT: 4 confirmaciones, +2035 líneas 5 de mayo, 3 a.m. a 4 a.m. PDT: 4 confirmaciones, +7808 líneas 5 de mayo, 4 a.m. a 5 a.m. PDT: 1 confirmación, +2796 líneas 5 de mayo 5 a. m. a 6 a. m. PDT: 2 confirmaciones, +29 370 líneas 5 de mayo, 8 a. m. a 9 a. m. PDT: 2 confirmaciones, +7 076 líneas +1452 líneas 5 de mayo, 13:00 a 14:00 PDT: 1 confirmación, +2142 líneas 5 de mayo, 14:00 a 15:00 PDT: 4 confirmaciones, +7787 líneas 5 de mayo: 15:00 a 16:00 PDT: 2 confirmaciones, +5835 líneas 5 de mayo: 16:00 a 17:00 PDT: 1 confirmación, +3417 líneas 5 de mayo: 17:00 a 18:00 PDT 4 confirmaciones, +3960 líneas 5 de mayo, de 6 p. m. a 7 p. m. PDT: 4 confirmaciones, +9,179 líneas 5 de mayo, de 7 p. m. a 8 p. m. PDT: 4 confirmaciones, +1983 líneas 5 de mayo, de 8 p. m. a 9 p. m. PDT: 4 confirmaciones, +18 902 líneas 5 de mayo, de 9 p. m. a 10 p. m. PDT: 43 confirmaciones, +40 650 líneas de mayo 5, 10 p. m. a 11 p. m. PDT: 139 confirmaciones, +64 842 líneas 5 de mayo, 11 p. m. a 12 a. m. PDT: 141 confirmaciones, +34 814 líneas 6 de mayo 6 de mayo, 12 a. m. a 1 a. m. PDT: 60 confirmaciones, +10 417 líneas 6 de mayo, 1 a. m. a 2 a. m. PDT: 296 confirmaciones, +38 530 líneas 6 de mayo, 2 a. m. a 3 a. m. PDT: 306 confirmaciones, +18 836 líneas 6 de mayo, 3 a. m. a 4 a. m. PDT: 196 confirmaciones, +10 245 líneas 6 de mayo, 4 a. m. a 5 a. m. PDT: 86 confirmaciones, +2655 líneas 6 de mayo, 5 a. m. a 6 a. m. PDT: 16 confirmaciones, +289 líneas 6 de mayo, 8 a. m. a 9 a. m. PDT: 5 confirmaciones, +264 líneas 6 de mayo, de 9 a. m. a 10 a. m. PDT: 458 confirmaciones, +16 409 líneas 6 de mayo de 10 a. m. a 11 a. m. PDT: 695 confirmaciones, +44 000 líneas 6 de mayo de 11 a. m. a 12 p. m. PDT: 102 confirmaciones, +21 972 líneas 6 de mayo de 12 p. m. a 1 p. m. PDT: 19 confirmaciones, +2891 líneas 6 de mayo, 13:00 a 14:00 PDT: 3 confirmaciones, +56 líneas 6 de mayo, 15:00 a 16:00 PDT: 64 confirmaciones, +3606 líneas 6 de mayo: 16:00 a 17:00 PDT: 264 confirmaciones, +60 132 líneas 6 de mayo: 17:00 a 18:00 PDT: 268 confirmaciones, +40 953 líneasMayo 6, 6 p. m. a 7 p. m. PDT: 281 confirmaciones, +16 283 líneas 6 de mayo, 7 p. m. a 8 p. m. PDT: 258 confirmaciones, +26 654 líneas 6 de mayo, 8 p. m. a 9 p. m. PDT: 327 confirmaciones, +16 599 líneas 6 de mayo, 9 p. m. 10 p. m. a 11 p. m. PDT: 17 confirmaciones, +2200 líneas 6 de mayo, 11 p. m. a 12 a. m. PDT: 11 confirmaciones, +3590 líneas 7 de mayo 7 de mayo, 12 a. m. a 1 a. m. PDT: 17 confirmaciones, +6577 líneas 7 de mayo, 1 a. m. a 2 a. m. PDT: 22 confirmaciones, +8 718 líneas 7 de mayo, 2 a. m. a 3 a. m. PDT: 21 confirmaciones, +11 392 líneas 7 de mayo, de 3 a. m. a 4 a. m. PDT: 53 confirmaciones, +6 476 líneas 7 de mayo de 4 a. m. a 5 a. m. PDT: 31 confirmaciones, +2 356 líneas 7 de mayo de 5 a. m. a 6 a. m. PDT: 9 confirmaciones, +1 787 líneas 7 de mayo de 6 a. m. a 7 a. m. PDT: 4 confirmaciones, +580 líneas de mayo 7 de mayo, de 7 a. m. a 8 a. m. PDT: 5 confirmaciones, +181 líneas 7 de mayo, de 11 a. m. a 12 p. m. PDT: 3 confirmaciones, +421 líneas 7 de mayo, de 12 p. m. a 1 p. m. PDT: 1 confirmación, +13 líneas 7 de mayo, de 15:00 a 16:00 PDT: 51 confirmaciones, +3207 líneas 7 de mayo, de 16:00 a 17:00 PDT: 56 confirmaciones, +2647 líneas 7 de mayo de 17:00 a 18:00 PDT: 159 confirmaciones, +2787 líneas 46 confirmaciones, +4170 líneas 7 de mayo, de 8 p. m. a 9 p. m. PDT: 52 confirmaciones, +2113 líneas 7 de mayo de 9 p. m. a 10 p. m. PDT: 27 confirmaciones, +1585 líneas 7 de mayo de 10 p. m. a 11 p. m. PDT: 27 confirmaciones, +2231 líneas 7 de mayo de 11 p. m. a 12 a. m. PDT: 30 confirmaciones +4987 líneas 8 de mayo 8 de mayo, 12 a. m. a 1 a. m. PDT: 27 confirmaciones, +1196 líneas 8 de mayo, 1 a. m. a 2 a. m. PDT: 14 confirmaciones, +904 líneas 8 de mayo, 2 a. m. a 3 a. m. PDT: 8 confirmaciones, +536 líneas 8 de mayo, 3 a. m. a 4 a. m. PDT: 13 confirmaciones, +253 líneas 8 de mayo, 4 a. m. a 5 a. m. PDT: 3 confirmaciones, +771 líneas 8 de mayo, de 5 a. m. a 6 a. m. PDT: 15 confirmaciones, +1545 líneas 8 de mayo, de 6 a. m. a 7 a. m. PDT: 12 confirmaciones, +1965 líneas 8 de mayo, de 7 a. m. a 8 a. m. PDT: 14 confirmaciones, +1866 líneas 8 de mayo, de 8 a. m. a 9 a. m. PDT: 55 confirmaciones, +3622 líneas de mayo 8, de 9 a. m. a 10 a. m. PDT: 35 confirmaciones, +4778 líneas 8 de mayo, de 10 a. m. a 11 a. m. PDT: 1 confirmación, +0 líneas 8 de mayo, de 12 p. m. a 1 p. m. PDT: 1 confirmación, +116 líneas 8 de mayo, de 1 p. m. a 2 p. m. PDT: 2 confirmaciones, +66 líneas 8 de mayo, de 2 p. m. a 3 p. m. PDT: 9 confirmaciones, +1071 líneas 8 de mayo, 3 p. m. a 4 p. m. PDT: 26 confirmaciones, +1691 líneas 8 de mayo, 4 p. m. a 5 p. m. PDT: 18 confirmaciones, +2751 líneas 8 de mayo, 5 p. m. a 6 p. m. PDT: 2 confirmaciones, +97 líneas 8 de mayo, 6 p. m. a 7 p. m. PDT: 2 confirmaciones, +135 líneas +1763 líneas 8 de mayo, de 8 p. m. a 9 p. m. PDT: 20 confirmaciones, +5272 líneas 8 de mayo, de 9 p. m. a 10 p. m. PDT: 12 confirmaciones, +952 líneas 8 de mayo, de 10 p. m. a 11 p. m. PDT: 2 confirmaciones, +334 líneas 8 de mayo, de 11 p. m. a 12 a. m. PDT: 6 confirmaciones, +2033 líneas 9 de mayo 9 de mayo 12 a. m. a 1 a. m. PDT: 9 confirmaciones, +387 líneas 9 de mayo, 1 a. m. a 2 a. m. PDT: 9 confirmaciones, +723 líneas 9 de mayo, 2 a. m. a 3 a. m. PDT: 8 confirmaciones, +98 líneas 9 de mayo, 3 a. m. a 4 a. m. PDT: 63 confirmaciones, +2538 líneas 9 de mayo, 4 a. m. a 5 a. m. PDT: 11 confirmaciones, +8 861 líneas Mayo 9 de mayo, de 5 a. m. a 6 a. m. PDT: 4 confirmaciones, +42 líneas 9 de mayo, de 6 a. m. a 7 a. m. PDT: 3 confirmaciones, +2616 líneas 9 de mayo, de 7 a. m. a 8 a. m. PDT: 6 confirmaciones, +6993 líneas +199 líneas 9 de mayo, de 11 a. m. a 12 p. m. PDT: 1 confirmación, +23 líneas 9 de mayo, de 12 p. m. a 1 p. m. PDT: 4 confirmaciones, +5012 líneas confirmaciones, +248 líneas 9 de mayo, 4 p. m. a 5 p. m. PDT: 17 confirmaciones, +508 líneas 9 de mayo, 5 p. m. a 6 p. m. PDT: 2 confirmaciones, +135 líneas 9 de mayo, 6 p. m. a 7 p. m. PDT: 4 confirmaciones, +822 líneas 9 de mayo, 7 p. m. a 8 p. m. PDT: 1 confirmación, +7 líneas 10 de mayo 10 de mayo, 12 a. m. a 1 a. m. PDT — 4 confirmaciones, +497 líneas 10 de mayo, 1 a. m. a 2 a. m. PDT: 2 confirmaciones, +35 líneas 10 de mayo, 2 a. m. a 3 a. m. PDT: 1 confirmación, +131 líneas 10 de mayo, 3 a. m. a 4 a. m. PDT: 2 confirmaciones, +322 líneas 10 de mayo, 4 a. m. a 5 a. m. PDT: 1 confirmación, +3 líneas 10 de mayo, 5 a. m. a 6 a. m. PDT: 1 confirmación, +26 líneas 10 de mayo, 6 a. m. a 7 a. m. PDT: 2 confirmaciones, +81 líneas 10 de mayo, 7 a. m. a 8 a. m. PDT: 1 confirmación, +5 líneas 10 de mayo, 8 a. m. a 9 a. m. PDT: 4 confirmaciones, +78 líneas 10 de mayo, 9 a. m. a 10 a. m. PDT: 1 confirmación, +1 líneas 10 de mayo, 10 a. m. a 11 a. m. PDT: 2 confirmaciones, +128 líneas 10 de mayo, 11 a. m. a 12 p. m. PDT: 1 confirmación, +4 líneas 10 de mayo, 12 p. m. a 1 p. m. PDT: 2 confirmaciones, +413 líneas 10 de mayo, 1 p. m. a 2 p. m. PDT: 1 confirmación, +25 líneas 10 de mayo, 2 p. m. a 3 p. m. PDT: 5 confirmaciones, +327 líneas 10 de mayo, 3 p. m. a 4 p. m. PDT: 6 confirmaciones, +1,172 líneas 10 de mayo, 4:00 p. m. a 5:00 p. m. PDT: 4 confirmaciones, +752 líneas 10 de mayo, 5:00 p. m. a 6:00 p. m. PDT: 3 confirmaciones, +227 líneas 10 de mayo, 6:00 p. m. a 7:00 p. m. PDT: 2 confirmaciones, +242 líneas 10 de mayo, 7:00 p. m. a 8:00 p. m. PDT: 1 confirmación, +306 líneas 10 de mayo, 8:00 p. m. a 9:00 p. m. PDT: 1 compromiso, +54 líneas 10 de mayo, 9 p. m. a 10 p. m. PDT: 2 confirmaciones, +75 líneas 10 de mayo, 10 p. m. a 11 p. m. PDT: 1 compromiso, +134 líneas 10 de mayo, 11 p. m. a 12 a. m. PDT: 5 confirmaciones, +103 líneas 11 de mayo 11 de mayo, 12 a. m. a 1 a. m. PDT: 2 confirmaciones, +150 líneas 11 de mayo, 1 a. m. a 2 a. m. PDT: 4 confirmaciones, +398 líneas 11 de mayo, 2 a. m. a 3 a. m. PDT: 2 confirmaciones, +364 líneas 11 de mayo, 3 a. m. a 4 a. m. PDT: 3 a. m. PDT: 3 a. m. a 7 a. m. PDT: 2 a. m. a 5 a. m. PDT: 7 confirmaciones, +9,367 líneas 11, de 7 a. m. a 8 a. m. PDT: 2 confirmaciones, +149 líneas 11 de mayo, de 8 a. m. a 9 a. m. PDT: 10 confirmaciones, +2171 líneas 11 de mayo, de 9 a. m. a 10 a. m. PDT: 16 confirmaciones, +2047 líneas 11 de mayo, de 10 a. 11 a. m. a 12 p. m. PDT: 9 confirmaciones, +861 líneas 11 de mayo, 12 p. m. a 1 p. m. PDT: 3 confirmaciones, +412 líneas 11 de mayo, 1 p. m. a 2 p. m. PDT: 12 confirmaciones, +2978 líneas 11 de mayo, 2 p. m. a 3 p. m. PDT: 157 confirmaciones, +10 700 líneas 11 de mayo, 3 p. m. a 4 p. m. PDT: 16 confirmaciones, +1346 líneas 11 de mayo, 4 p. m. a 5 p. m. PDT: 3 confirmaciones, +78 líneas 11 de mayo, 5 p. m. a 6 p. m. PDT: 41 confirmaciones, +2568 líneas 11 de mayo, 6 p. m. a 7 p. m. PDT: 55 confirmaciones, +4912 líneas 11 de mayo, 7 p. m. a 8 p. m. PDT: 53 confirmaciones, +3475 líneas mayo 11, 8 p. m. a 9 p. m. PDT: 32 confirmaciones, +1732 líneas 11 de mayo, 9 p. m. a 10 p. m. PDT: 46 confirmaciones, +4506 líneas 11 de mayo, 10 p. m. a 11 p. m. PDT: 45 confirmaciones, +1711 líneas 11 de mayo, 11 p. 12 de mayo, 12 a. m. a 1 a. m. PDT: 30 confirmaciones, +3760 líneas 12 de mayo, 1 a. m. a 2 a. m. PDT: 24 confirmaciones, +9 443 líneas 12 de mayo, 2 a. m. a 3 a. m. PDT: 41 confirmaciones, +1 635 líneas 12 de mayo, 3 a. m. PDT: 27 confirmaciones, +651 líneas 12 de mayo, 5 a. m. a 6 a. m. PDT: 23 confirmaciones, +779 líneas 12 de mayo, 6 a. m. a 7 a. m. PDT: 1 confirmación, +137,576 líneas 12 de mayo, 7 a. m. a 8 a. m. PDT: 2 confirmaciones, +81 líneas 12 de mayo, 8 a. m. a 9 a. m. PDT: 2 confirmaciones, +75 líneas 12 de mayo 9 a. m. a 10 a. m. PDT: 2 confirmaciones, +130 líneas 12 de mayo, 10 a. m. a 11 a. m. PDT: 5 confirmaciones, +160 líneas 12 de mayo, 11 a. m. a 12 p. m. PDT: 2 confirmaciones, +20 líneas 12 de mayo, 12 p. m. a 1 p. m. PDT: 1 confirmación, +2 líneas 12 de mayo, 1 p. m. a 2 p. m. PDT: 30 confirmaciones, +2677 líneas 12 de mayo, 2:00 p. m. a 3:00 p. m. PDT: 41 confirmaciones, +7,022 líneas 12 de mayo, 3:00 p. m. a 4:00 p. m. PDT: 4 confirmaciones, +200 líneas 12 de mayo, 4:00 p. m. a 5:00 p. m. PDT: 27 confirmaciones, +1,423 líneas 6 p. m. a 7 p. m. PDT: 2 confirmaciones, +380 líneas 12 de mayo, 7 p. m. a 8 p. m. PDT: 2 confirmaciones, +84 líneas 12 de mayo, 9 p. m. a 10 p. m. PDT: 7 confirmaciones, +273 líneas 12 de mayo, 10 p. m. a 11 p. m. PDT: 3 confirmaciones, +230 líneas 12 de mayo, 11 p. m. a 12 a. m. PDT: 7 confirmaciones, +319 líneas 13 de mayo 13 de mayo, 12 a. m. a 1 a. m. PDT: 2 confirmaciones, +133 líneas 13 de mayo, 1 a. m. a 2 a. m. PDT: 14 confirmaciones, +2177 líneas 13 de mayo, 2 a. m. a 3 a. m. PDT: 12 confirmaciones, +685 líneas 13 de mayo, 4 a. m. a 5 a. m. PDT: 10 confirmaciones, +657 líneas 13 de mayo, 5 a. m. a 6 a. m. PDT: 1 confirmación, +687 líneas 13 de mayo, de 6 a. m. a 7 a. m. PDT: 11 confirmaciones, +380 líneas 13 de mayo, de 7 a. m. a 8 a. m. PDT: 12 confirmaciones, +5247 líneas 13 de mayo, de 8 a. m. a 9 a. m. PDT: 14 confirmaciones, +1051 líneas 13 de mayo, de 9 a. m. a 10 a. m. PDT: 7 confirmaciones, +680 líneas de mayo 13 de mayo, de 10 a. m. a 11 a. m. PDT: 10 confirmaciones, +412 líneas 13 de mayo, de 11 a. m. a 12 p. m. PDT: 6 confirmaciones, +314 líneas confirmaciones, +439 líneas 13 de mayo, 5 p. m. a 6 p. m. PDT: 7 confirmaciones, +114 líneas 13 de mayo, 6 p. m. a 7 p. m. PDT: 4 confirmaciones, +605 líneas 13 de mayo, 9 p. m. a 10 p. m. PDT: 1 confirmación, +13 líneas 13 de mayo, 10 p. m. a 11 p. m. PDT: 1 confirmación, +48 líneas 13 de mayo, 11 p. m. a 12 a. m. PDT — 1 confirmación, +8 líneas 14 de mayo 14 de mayo, 12 a. m.–1 a. m. PDT — 1 confirmación, +150 líneas
Cada confirmación en la rama del puerto (excluidas las fusiones), agrupadas por hora. Hora pico: 695 confirmaciones.
¿Notas la sincronización inconsistente? Olvidé aumentar el IOPS predeterminado en la instancia EC2 en la que se ejecutó. Un lento comando grep fue todo lo que se necesitó para congelar las lecturas y escrituras en el disco durante minutos.
Errores del compilador como cola de trabajo
Después de escribir todo el código, le pedí a Claude que escribiera un flujo de trabajo que corrigiera cada error del compilador. Fuimos caja por caja.
Quedan ≈15,125 errores
Miércoles, 6 de mayo, 1:29 a.m. PDT
errors.txt88 confirmaciones de corrección
error: src/event_loop/SpawnSyncEventLoop.rs
error: src/sys/lib.rs
error: tiempo de ejecución/temporizador/TimerObjectInternals.rs
error: src/runtime/ffi/ffi_body.rs
error: src/http/lib.rs
error: src/js_parser/ast/Parser.rs
error: JSPromise.rs
error: independiente_graph/StandaloneModuleGraph.rs
error: src/http_jsc/websocket_client.rs
error: doStep5.rs
error: src/install/PackageManager.rs
repartido · 64 claudes
árbol de trabajo 1
→→
→→
→→
→→
árbol de trabajo 2
→→
→→
→→
→→
árbol de trabajo 3
→→
→→
→→
→→
árbol de trabajo 4
→→
→→
→→
→→
Se aplican 1 revisión 2 correcciones
→ compromete terreno por caja
moño_bundler0
bun_js_parser17
moño_css10
moño_http3
bun_sys3
bollo_alloc1
bollo_sourcemap3
bollo_ini0
bun_analytics1
moño_zlib0
· fase-d(sql_jsc/mysql/protocol): corregir importaciones, límites de ReaderContext, ayudante WTFStringImpl
· fase-d(tier0): bun_sourcemap parse_json: campo BabyList.len, opción<StoreRef> desempaquetando
· fase-d(jpa): skipTypescript.rs - transferir cuerpos reales, soltar _draft/todo stubs
Cómo funcionó la fase D, reproducido a partir de sus 1.610 confirmaciones reales (6 de mayo, PDT): cargo check escribió ≈16.000 errores en un archivo, agrupados por caja; el flujo de trabajo los dividió entre 64 Claudes: 16 bucles en 4 árboles de trabajo, cada uno de los cuales Claude solucionó, dos revisó y uno aplicó. Cada ficha es un lote de confirmaciones reales: aterriza en su caja real y solo entonces se mueven las fichas. Las líneas de error son temas de confirmación reales.
La clase de error más complicada fueron las dependencias cíclicas.
Nuestra base de código Zig era una unidad de compilación (efectivamente, una caja). Quería dividir el nuevo código base Rust en ~100 cajas para que Rust se compilara más rápido, pero esto necesitaba evitar dependencias cíclicas y minimizar los cambios en comparación con la implementación Zig original. Mi PR para hacer esto inmediatamente antes de comenzar la reescritura Rust fue insuficiente. En lugar de empezar de nuevo, ejecuté otro flujo de trabajo para clasificar dónde debería ir el código con dependencias cíclicas y escribirlo todo, y luego otro flujo de trabajo para realizar la refactorización.
La corrección de las dependencias cíclicas reveló alrededor de 16.000 errores del compilador. Un número enorme para 1 humano, pero no un número descabellado para 64 claudes a la vez.
Para maximizar el paralelismo, el flujo de trabajo recorrió cada caja.
- Para cada caja, ejecute
cargo check, agrupe la salida por archivo y guarde los errores en un archivo - Corregir todos los errores del compilador dentro de esa caja
- 2 revisores contradictorios para los cambios de la caja
- 1 reparador aplica las correcciones
Para evitar que Claudes se pise entre sí, cargo check solo se ejecutó al principio y, al igual que las otras ejecuciones, no git hasta el final.
Otro comienzo en falso
Claude interpretó "compilemos todas las cajas" como "eliminemos las funciones con errores de compilación". Claude también comenzó a agregar comentarios explicativos sospechosamente largos para documentar las soluciones, así que agregué esta regla para que los revisores adversarios la rechacen:
Si necesita un comentario de un párrafo para justificar por qué la solución alternativa es correcta, el código es incorrecto: corríjalo.
Una edición rápida y unas horas más tarde, estas cosas dejaron de suceder.
Pruebas de humo
A las modelos les encanta decir "pruebas de humo"
Una vez que pasó cargo check, lo siguiente fue compilarlo y ejecutar bun --version. Tenía errores de enlazador. Luego, entró en pánico inmediatamente al empezar.
El siguiente objetivo era lograr que se ejecutara bun test <file>. Una vez que eso funcionó, ¡podríamos comenzar a realizar pruebas! Es hora de otro flujo de trabajo, recorriendo los subcomandos CLI de bun:
- Guarde cada seguimiento de pila fallido en un archivo junto con su subcomando
- Para cada seguimiento de pila defectuoso agrupado por subcomando, tenga 1 corrección de Claude
- 2 revisores contradictorios
- 1 reparador aplica las sugerencias
Hacer que el conjunto de pruebas se apruebe localmente
Este flujo de trabajo se repitió en archivos de prueba.
Ejecute alrededor de 100 archivos de prueba aleatorios fragmentados en uno de los 4 árboles de trabajo por carpeta en el código base. Para cada prueba fallida, guarde el seguimiento de la pila y los errores en un archivo, 1 implementador propone una solución, 2 revisores adversarios y luego se aplica 1 solucionador.
Aún más comienzos en falso
Nuestro conjunto de pruebas tiene muchas pruebas de pérdida de memoria y un puñado de pruebas de integración que pueden tardar más de un minuto; por ejemplo: una prueba que ejecuta next dev y comprueba la recarga del módulo en caliente puede detectar cambios 100 veces. Varias de estas pruebas agotan el tiempo de espera en las compilaciones de depuración.
También tenemos pruebas de estrés que agotan el número máximo de sockets TCP en la máquina, pruebas que leen y escriben gigabytes en el disco y pruebas que generan ~10k procesos.
Esto necesitaba un aislamiento más fuerte que "por favor", por lo que usamos systemd-run (cgroups) para limitar el uso de memoria y CPU y aislar los espacios de nombres pid. La máquina se quedó sin espacio en disco y de todos modos falló varias veces.
Obtener la aprobación del conjunto de pruebas en CI
Dos días después de la primera ejecución de CI, la lista de errores bajó de 972 archivos de prueba a 23. Un día y medio después de eso, Linux se volvió completamente verde y, por primera vez, parecía que esta Rust reescritura realmente iba a funcionar.
0 / 6 plataformas verde
compilación n.° 53047 · sábado 9 de mayo a las 11:52 a. m. PDT
macOS x64 · 2 fragmentos
compilación n.º 52897: fallas de fragmentos compilación n.° 52932: fallas de fragmentos compilación n.° 52934: fallas de fragmentos compilación n.° 52938: fallas de fragmentos compilación n.° 52944: fallas de fragmentos compilación n.° 52946: fallas de fragmentos compilación n.° 52949: fallas de fragmentos compilación n.° 52975: fallas de fragmentos compilación n.° 52998: fallas de fragmentos compilación n.° 53007: fallas de fragmentos compilación n.° 53015: fallas de fragmentos compilación n.° 53026: fallas de fragmentos compilación n.° 53027: fallas de fragmentos compilación n.° 53035: fallas de fragmentos compilación n.° 53041: fallas de fragmentos compilación n.° 53047: fallas de fragmentos compilación n.° 53056: fallas de fragmentos compilación n.° 53077: fallas de fragmentos compilación n.° 53090: fallas de fragmentos compilación n.° 53095: fallas de fragmentos compilación n.° 53106: fallas de fragmentos compilación n.° 53109: fallas de fragmentos compilación n.° 53123: fallas de fragmentos compilación n.° 53127: fallas de fragmentos compilación n.° 53130: fallas de fragmentos compilación n.° 53131: fallas de fragmentos compilación n.° 53133: fallas de fragmentos compilación n.° 53134: fallas de fragmentos compilación n.° 53143: fallas de fragmentos compilación n.° 53149: todos los fragmentos aprobados compilación n.° 53159: todos los fragmentos aprobados compilación n.° 53164: todos los fragmentos aprobados compilación n.° 53167: todos los fragmentos aprobados compilación n.° 53172: todos los fragmentos aprobados compilación n.° 53176: todos los fragmentos aprobados #53194: todos los fragmentos aprobadoscompilación #53208: todos los fragmentos aprobadoscompilación #53213: fallas de fragmentoscompilación #53214: fallas de fragmentoscompilación #53216: sin fallas (ejecución parcial)compilación #53222: todos los fragmentos aprobadoscompilación #53229: sin fallas (ejecución parcial)compilación #53241: todos los fragmentos aprobadoscompilación #53265: todos los fragmentos aprobados compilación # 53271: todos los fragmentos aprobados compilación # 53304: fallas de fragmentos compilación # 53327: fallas de fragmentos compilación # 53340: fallas de fragmentos compilación # 53401: fallas de fragmentos compilación # 53431: fallas de fragmentos compilación # 53491: todos los fragmentos aprobados compilación # 53503: todos fragmentos aprobadoscompilación #53748: fallas de fragmentoscompilación #53753: todos los fragmentos aprobadoscompilación #53787: todos los fragmentos aprobadoscompilación #53811: todos los fragmentos aprobadoscompilación #53933: sin fallas (ejecución parcial)compilación #53952: todos los fragmentos aprobadoscompilación #53983: fallas de fragmentoscompilación #53992: fallas de fragmentoscompilación #53999: fallas de fragmentos compilación # 54012: todos los fragmentos aprobados compilación # 54015: todos los fragmentos aprobados compilación # 54017: todos los fragmentos aprobados compilación # 54022: fallas de fragmentos compilación # 54026: fallas de fragmentos compilación # 54033: todos los fragmentos aprobados compilación # 54040: todos los fragmentos aprobados compilación # 54047: fallas de fragmentos compilación n.° 54049: fallas de fragmentos compilación n.° 54057: fallas de fragmentos compilación n.° 54064: todos los fragmentos aprobados compilación n.° 54074: todos los fragmentos aprobados compilación n.° 54093: todos los fragmentos aprobados compilación n.° 54144: sin fallas (ejecución parcial)compilación n.° 54161: fallas de fragmentos compilación n.° 54186: fallas de fragmentos compilación #54189: fallas de fragmentos, compilación #54196: fallas de fragmentos, compilación #54202: todos los fragmentos pasaron
✓
Linux arm64 · 60 fragmentos
compilación n.º 52934: fallas de fragmentos compilación n.° 52938: fallas de fragmentos compilación n.° 52944: fallas de fragmentos compilación n.° 52969: fallas de fragmentos compilación n.° 52975: fallas de fragmentos compilación n.° 52980: fallas de fragmentos compilación n.° 52988: fallas de fragmentos compilación n.° 52996: fallas de fragmentos compilación n.° 52998: fallas de fragmentos compilación n.° 53007: fallas de fragmentos compilación n.° 53013: fallas de fragmentos compilación n.° 53014: fallas de fragmentos compilación n.° 53015: fallas de fragmentos compilación n.° 53026: fallas de fragmentos compilación n.° 53027: fallas de fragmentos compilación n.° 53031: sin fallas (ejecución parcial)compilación n.° 53032: compilación de fallas de fragmentos #53035: fallas de fragmentos, compilación #53041: fallas de fragmentos, compilación #53047: fallas de fragmentos, compilación #53056: fallas de fragmentos, compilación #53059: fallas de fragmentos, compilación #53077: fallas de fragmentos, compilación #53083: fallas de fragmentos, compilación #53086: fallas de fragmentos, compilación #53090: fallas de fragmentos #53095: fallas de fragmentos, compilación #53106: fallas de fragmentos, compilación #53109: fallas de fragmentos, compilación #53123: fallas de fragmentos, compilación #53127: fallas de fragmentos, compilación #53130: fallas de fragmentos, compilación #53131: fallas de fragmentos, compilación #53133: fallas de fragmentos, compilación #53134: fallas de fragmentos #53135: fallas de fragmentoscompilación #53143: fallas de fragmentoscompilación #53149: fallas de fragmentoscompilación #53159: fallas de fragmentoscompilación #53164: fallas de fragmentoscompilación #53167: todos los fragmentos aprobadoscompilación #53172: fallas de fragmentoscompilación #53176: todos los fragmentos aprobadoscompilación #53188: fragmento compilación #53194: fallas de fragmentoscompilación #53208: todos los fragmentos aprobadoscompilación #53212: fallas de fragmentoscompilación #53213: fallas de fragmentoscompilación #53214: fallas de fragmentoscompilación #53216: todos los fragmentos aprobadoscompilación #53222: todos los fragmentos aprobadoscompilación #53229: todos los fragmentos aprobadoscompilación #53236: sin fallas (ejecución parcial) compilación #53241: todos los fragmentos aprobados compilación # 53260: todos los fragmentos aprobados compilación # 53265: todos los fragmentos aprobados compilación # 53271: todos los fragmentos aprobados compilación # 53280: sin fallas (ejecución parcial) compilación # 53298: sin fallas (ejecución parcial) compilación # 53304: fallas de fragmentos compilación # 53327: todas fragmentos aprobadoscompilación #53340: todos los fragmentos aprobadoscompilación #53360: sin fallas (ejecución parcial)compilación #53419: fallas de fragmentoscompilación #53431: fallas de fragmentoscompilación #53458: sin fallas (ejecución parcial)compilación #53485: fallas de fragmentoscompilación #53491: fallas de fragmentoscompilación #53503: fallas de fragmentoscompilación #53514: sin fallas (ejecución parcial) compilación # 53570: fallas de fragmentos compilación # 53583: fallas de fragmentos compilación # 53599: fallas de fragmentos compilación # 53748: fallas de fragmentos compilación # 53753: todos los fragmentos aprobados compilación # 53762: sin fallas (ejecución parcial) compilación # 53787: compilación sin fallas (ejecución parcial) #53811: todos los fragmentos aprobadoscompilación #53852: sin fallas (ejecución parcial)compilación #53863: fallas de fragmentoscompilación #53893: fallas de fragmentoscompilación #53914: todos los fragmentos aprobadoscompilación #53933: todos los fragmentos aprobadoscompilación #53952: todos los fragmentos aprobadoscompilación #53983: fallas de fragmentoscompilación #53992: fallas de fragmentos compilación n.° 53999: fallas de fragmentos compilación n.° 54008: sin fallas (ejecución parcial) compilación n.° 54012: todos los fragmentos aprobados compilación n.° 54015: todos los fragmentos aprobados compilación n.° 54017: todos los fragmentos aprobados compilación n.° 54022: fallas de fragmentos compilación n.° 54026: todos los fragmentos aprobados compilación n.° 54030: fallas de fragmentos compilación #54033: todos los fragmentos aprobados compilación # 54040: todos los fragmentos aprobados compilación # 54047: fallas de fragmentos compilación # 54049: fallas de fragmentos compilación # 54055: fallas de fragmentos compilación # 54057: fallas de fragmentos compilación # 54064: todos los fragmentos aprobados compilación # 54074: todos los fragmentos aprobados compilación # 54083: sin fallas (ejecución parcial) compilación n.° 54093: todos los fragmentos aprobados compilación n.° 54144: todos los fragmentos aprobados compilación n.° 54161: fallas de fragmentos compilación n.° 54186: fallas de fragmentos compilación n.° 54189: fallas de fragmentos compilación n.° 54196: fallas de fragmentos compilación n.° 54202: todos los fragmentos aprobados
✓
Linux x64 · 60 fragmentos
compilación n.º 52934: fallas de fragmentos compilación n.° 52938: fallas de fragmentos compilación n.° 52944: fallas de fragmentos compilación n.° 52969: fallas de fragmentos compilación n.° 52975: fallas de fragmentos compilación n.° 52988: fallas de fragmentos compilación n.° 52996: fallas de fragmentos compilación n.° 52998: fallas de fragmentos compilación n.° 53007: fallas de fragmentos compilación n.° 53013: fallas de fragmentos compilación n.° 53014: fallas de fragmentos compilación n.° 53015: fallas de fragmentos compilación n.° 53026: fallas de fragmentos compilación n.° 53027: fallas de fragmentos compilación n.° 53032: fallas de fragmentos compilación n.° 53033: fallas de fragmentos compilación n.° 53035: fallas de fragmentos compilación n.° 53041: fallas de fragmentos compilación n.° 53047: fallas de fragmentos compilación n.° 53056: fallas de fragmentos compilación n.° 53059: sin fallas (ejecución parcial) compilación n.° 53077: fallas de fragmentos compilación n.° 53083: sin fallas (ejecución parcial) compilación n.° 53086: fallas de fragmentos compilación n.° 53090: fallas de fragmentos compilación n.° 53095: compilación de fallas de fragmentos #53106: fallas de fragmentos, compilación #53109: fallas de fragmentos, compilación #53123: fallas de fragmentos, compilación #53127: fallas de fragmentos, compilación #53130: fallas de fragmentos, compilación #53131: fallas de fragmentos, compilación #53133: fallas de fragmentos, compilación #53134: fallas de fragmentos, compilación #53135: fallas de fragmentos #53143: fallas de fragmentoscompilación #53149: fallas de fragmentoscompilación #53159: fallas de fragmentoscompilación #53164: fallas de fragmentoscompilación #53167: todos los fragmentos aprobadoscompilación #53172: todos los fragmentos aprobadoscompilación #53176: todos los fragmentos aprobadoscompilación #53188: fallas de fragmentoscompilación #53194: todos fragmentos aprobadoscompilación #53208: todos los fragmentos aprobadoscompilación #53212: fallas de fragmentoscompilación #53213: fallas de fragmentoscompilación #53214: fallas de fragmentoscompilación #53216: todos los fragmentos aprobadoscompilación #53222: todos los fragmentos aprobadoscompilación #53229: todos los fragmentos aprobadoscompilación #53236: sin fallas (ejecución parcial)compilación #53241: todos los fragmentos aprobadoscompilación #53260: todos los fragmentos aprobadoscompilación #53265: todos los fragmentos aprobadoscompilación #53271: todos los fragmentos aprobadoscompilación #53280: sin fallas (ejecución parcial)compilación #53304: fallas de fragmentoscompilación #53327: todos los fragmentos aprobadoscompilación #53340: todos los fragmentos aprobadoscompilación #53360: sin fallas (ejecución parcial) compilación # 53419: sin fallas (ejecución parcial) compilación # 53431: fallas de fragmentos compilación # 53458: sin fallas (ejecución parcial) compilación # 53485: fallas de fragmentos compilación # 53491: todos los fragmentos aprobados compilación # 53503: todos los fragmentos aprobados compilación # 53514: sin fallas (ejecución parcial) compilación #53570: fallas de fragmentoscompilación #53583: fallas de fragmentoscompilación #53599: fallas de fragmentoscompilación #53748: fallas de fragmentoscompilación #53753: todos los fragmentos aprobadoscompilación #53759: sin fallas (ejecución parcial)compilación #53781: fallas de fragmentoscompilación #53787: sin fallas (ejecución parcial)compilación #53811: todos los fragmentos aprobados compilación #53863: fallas de fragmentos compilación #53893: fallas de fragmentos compilación #53914: todos los fragmentos aprobados compilación #53933: fallas de fragmentos compilación #53952: todos los fragmentos aprobados compilación #53983: fallas de fragmentos compilación #53992: fallas de fragmentos compilación #53999: fallas de fragmentos compilación #54008: sin fallas (ejecución parcial) compilación # 54012: todos los fragmentos aprobados compilación # 54015: todos los fragmentos aprobados compilación # 54017: todos los fragmentos aprobados compilación # 54022: fallas de fragmentos compilación # 54026: todos los fragmentos aprobados compilación # 54030: fallas de fragmentos compilación # 54033: todos los fragmentos aprobados compilación #54040: sin fallas (ejecución parcial) compilación # 54047: fallas de fragmentos compilación # 54049: fallas de fragmentos compilación # 54055: fallas de fragmentos compilación # 54057: fallas de fragmentos compilación # 54064: todos los fragmentos aprobados compilación # 54074: todos los fragmentos aprobados compilación # 54083: sin fallas (ejecución parcial) compilación #54093: todos los fragmentos pasaroncompilación #54144: todos los fragmentos pasaroncompilación #54161: fallas de fragmentoscompilación #54186: fallas de fragmentoscompilación #54189: fallas de fragmentoscompilación #54196: fallas de fragmentoscompilación #54202: todos los fragmentos pasaron
✓
macOS arm64 · 4 fragmentos
compilación n.º 52897: fallas de fragmentos compilación n.° 52929: fallas de fragmentos compilación n.° 52932: fallas de fragmentos compilación n.° 52944: fallas de fragmentos compilación n.° 52975: fallas de fragmentos compilación n.° 52996: fallas de fragmentos compilación n.° 52998: fallas de fragmentos compilación n.° 53007: fallas de fragmentos compilación n.° 53013: fallas de fragmentos compilación n.° 53014: fallas de fragmentos compilación n.° 53015: fallas de fragmentos compilación n.° 53026: fallas de fragmentos compilación n.° 53027: fallas de fragmentos compilación n.° 53032: fallas de fragmentos compilación n.° 53035: fallas de fragmentos compilación n.° 53041: fallas de fragmentos compilación n.° 53047: fallas de fragmentos compilación n.° 53056: fallas de fragmentos compilación n.° 53059: fallas de fragmentos compilación n.° 53077: fallas de fragmentos compilación n.° 53095: fallas de fragmentos compilación n.° 53109: fallas de fragmentos compilación n.° 53123: fallas de fragmentos compilación n.° 53127: fallas de fragmentos compilación n.° 53130: fallas de fragmentos compilación n.° 53131: fallas de fragmentos compilación n.° 53133: fallas de fragmentos compilación n.° 53134: fallas de fragmentos compilación n.° 53135: fallas de fragmentos compilación n.° 53143: fallas de fragmentos compilación n.° 53149: fallas de fragmentos compilación n.° 53159: fallas de fragmentos compilación n.° 53164: fallas de fragmentos compilación n.° 53167: fallas de fragmentos compilación n.° 53172: fallas de fragmentos compilación n.° 53176: fallas de fragmentos compilación n.° 53188: fallas de fragmentos compilación n.° 53194: fallas de fragmentos compilación n.° 53208: fallas de fragmentos compilación n.° 53212: fallas de fragmentos compilación n.° 53213: fallas de fragmentos compilación n.° 53214: fallas de fragmentos compilación n.° 53216: fallas de fragmentos compilación n.° 53222: fallas de fragmentos compilación n.° 53229: no fallas (ejecución parcial) compilación n.° 53236: sin fallas (ejecución parcial) compilación n.° 53241: todos los fragmentos aprobados compilación n.° 53265: todos los fragmentos aprobados compilación n.° 53271: sin fallas (ejecución parcial) compilación n.° 53280: sin fallas (ejecución parcial) compilación n.° 53304: fallas de fragmentos compilación n.° 53327: sin fallas (ejecución parcial) compilación #53340: sin fallas (ejecución parcial) compilación # 53360: sin fallas (ejecución parcial) compilación # 53368: fallas de fragmentos compilación # 53379: fallas de fragmentos compilación # 53383: fallas de fragmentos compilación # 53401: fallas de fragmentos compilación # 53431: fallas de fragmentos compilación # 53458: fallas de fragmentos compilación # 53491: no fallas (ejecución parcial) compilación n.° 53503: fallas de fragmentos compilación n.° 53570: fallas de fragmentos compilación n.° 53583: fallas de fragmentos compilación n.° 53599: fallas de fragmentos compilación n.° 53601: fallas de fragmentos compilación n.° 53748: fallas de fragmentos compilación n.° 53753: todos los fragmentos pasaron compilación n.° 53757: sin fallas (ejecución parcial) #53759: sin fallas (ejecución parcial) compilación # 53787: sin fallas (ejecución parcial) compilación # 53811: todos los fragmentos pasaron compilación # 53952: sin fallas (ejecución parcial) compilación # 53992: fallas de fragmentos compilación # 53999: fallas de fragmentos compilación # 54007: sin fallas (ejecución parcial) compilación # 54012: todos los fragmentos pasaron compilación #54015: fallas de fragmentos compilación #54017: todos los fragmentos aprobados compilación #54022: fallas de fragmentos compilación #54026: sin fallas (ejecución parcial)compilación #54030: fallas de fragmentos compilación #54033: todos los fragmentos aprobadoscompilación #54040: fallas de fragmentoscompilación #54047: fallas de fragmentoscompilación #54049: fallas de fragmentos compilación n.° 54055: fallas de fragmentos compilación n.° 54057: fallas de fragmentos compilación n.° 54064: fallas de fragmentos compilación n.° 54074: fallas de fragmentos compilación n.° 54093: fallas de fragmentos compilación n.° 54161: fallas de fragmentos compilación n.° 54186: fallas de fragmentos compilación n.° 54189: fallas de fragmentos compilación n.° 54196: Fallos de fragmentos, compilación n.º 54202: todos los fragmentos pasaron
✓
Windows x64 · 8 fragmentos
compilación n.º 53090: fallas de fragmentos compilación n.° 53094: fallas de fragmentos compilación n.° 53095: fallas de fragmentos compilación n.° 53106: fallas de fragmentos compilación n.° 53109: fallas de fragmentos compilación n.° 53123: fallas de fragmentos compilación n.° 53127: fallas de fragmentos compilación n.° 53130: fallas de fragmentos compilación n.° 53131: fallas de fragmentos compilación n.° 53133: fallas de fragmentos compilación n.° 53134: fallas de fragmentos compilación n.° 53135: fallas de fragmentos compilación n.° 53143: fallas de fragmentos compilación n.° 53149: fallas de fragmentos compilación n.° 53159: fallas de fragmentos compilación n.° 53164: fallas de fragmentos compilación n.° 53167: fallas de fragmentos compilación n.° 53172: fallas de fragmentos compilación n.° 53176: fallas de fragmentos compilación n.° 53188: fallas de fragmentos compilación n.° 53194: fallas de fragmentos compilación n.° 53208: fallas de fragmentos compilación n.° 53212: fallas de fragmentos compilación n.° 53213: fallas de fragmentos compilación n.° 53214: fallas de fragmentos compilación n.° 53216: fallas de fragmentos compilación n.° 53222: fallas de fragmentos compilación n.° 53229: fallas de fragmentos compilación n.° 53236: fallas de fragmentos compilación n.° 53241: fallas de fragmentos compilación n.° 53260: fallas de fragmentos compilación n.° 53265: fallas de fragmentos compilación n.° 53271: fallas de fragmentos compilación n.° 53280: fallas de fragmentos compilación n.° 53298: fallas de fragmentos compilación n.° 53304: fallas de fragmentos compilación n.° 53327: todos los fragmentos aprobados compilación n.° 53340: todos los fragmentos aprobados compilación n.° 53360: sin fallas (ejecución parcial) compilación n.° 53419: fallas de fragmentos compilación n.° 53431: fallas de fragmentos compilación n.° 53458: fallas de fragmentos compilación n.° 53470: sin fallas (ejecución parcial) compilación n.° 53485: compilación de fallas de fragmentos #53491: sin fallas (ejecución parcial) compilación # 53503: fallas de fragmentos compilación # 53514: sin fallas (ejecución parcial) compilación # 53565: sin fallas (ejecución parcial) compilación # 53570: fallas de fragmentos compilación # 53599: fallas de fragmentos compilación # 53745: fallas de fragmentos compilación # 53748: compilación de fallas de fragmentos #53753: fallas de fragmentos, compilación #53757: fallas de fragmentos, compilación #53759: fallas de fragmentos, compilación #53762: fallas de fragmentos, compilación #53769: fallas de fragmentos, compilación #53781: fallas de fragmentos, compilación #53787: fallas de fragmentos, compilación #53808: fallas de fragmentos, compilación #53811: fallas de fragmentos #53852: fallas de fragmentos compilación # 53863: fallas de fragmentos compilación # 53883: fallas de fragmentos compilación # 53893: fallas de fragmentos compilación # 53914: todos los fragmentos aprobados compilación # 53933: todos los fragmentos aprobados compilación # 53952: todos los fragmentos aprobados compilación # 53973: sin fallas (ejecución parcial) compilación # 53983: fallas de fragmentos compilación n.° 53992: fallas de fragmentos compilación n.° 53999: fallas de fragmentos compilación n.° 54002: sin fallas (ejecución parcial) compilación n.° 54004: sin fallas (ejecución parcial) compilación n.° 54007: fallas de fragmentos compilación n.° 54008: sin fallas (ejecución parcial) compilación n.° 54012: todos los fragmentos aprobados compilación n.° 54015: todos fragmentos aprobadoscompilación #54017: todos los fragmentos aprobadoscompilación #54022: fallas de fragmentoscompilación #54026: todos los fragmentos aprobadoscompilación #54030: todos los fragmentos aprobadoscompilación #54033: todos los fragmentos aprobadoscompilación #54040: todos los fragmentos aprobadoscompilación #54047: fallas de fragmentoscompilación #54049: fallas de fragmentoscompilación #54055: fallas de fragmentoscompilación #54057: fallas de fragmentoscompilación #54064: todos los fragmentos aprobadoscompilación #54074: todos los fragmentos aprobadoscompilación #54083: todos los fragmentos aprobadoscompilación #54093: todos los fragmentos aprobadoscompilación #54144: fallas de fragmentoscompilación #54161: fallas de fragmentoscompilación #54186: fragmento Failuresbuild #54189: Fragmentos fallidos Build #54196: Fragmentos fallidos Build #54202: todos los fragmentos aprobados
✓
Windows arm64 · 8 fragmentos
compilación n.º 53090: fallas de fragmentos compilación n.° 53095: fallas de fragmentos compilación n.° 53106: fallas de fragmentos compilación n.° 53109: fallas de fragmentos compilación n.° 53123: fallas de fragmentos compilación n.° 53127: fallas de fragmentos compilación n.° 53130: fallas de fragmentos compilación n.° 53131: fallas de fragmentos compilación n.° 53134: fallas de fragmentos compilación n.° 53135: fallas de fragmentos compilación n.° 53149: fallas de fragmentos compilación n.° 53159: fallas de fragmentos compilación n.° 53164: fallas de fragmentos compilación n.° 53167: fallas de fragmentos compilación n.° 53172: fallas de fragmentos compilación n.° 53176: fallas de fragmentos compilación n.° 53188: fallas de fragmentos compilación n.° 53194: fallas de fragmentos compilación n.° 53208: fallas de fragmentos compilación n.° 53212: fallas de fragmentos compilación n.° 53213: fallas de fragmentos compilación n.° 53214: fallas de fragmentos compilación n.° 53216: fallas de fragmentos compilación n.° 53222: fallas de fragmentos compilación n.° 53229: fallas de fragmentos compilación n.° 53236: compilación sin fallas (ejecución parcial) #53241: fallas de fragmentos compilación #53260: fallas de fragmentos compilación #53265: fallas de fragmentos compilación #53271: fallas de fragmentos compilación #53304: fallas de fragmentos compilación #53327: todos los fragmentos aprobadoscompilación #53340: todos los fragmentos aprobadoscompilación #53360: sin fallas (ejecución parcial)compilación #53419: no fallas (ejecución parcial) compilación n.° 53431: fallas de fragmentos compilación n.° 53458: sin fallas (ejecución parcial) compilación n.° 53485: fallas de fragmentos compilación n.° 53491: sin fallas (ejecución parcial) compilación n.° 53503: sin fallas (ejecución parcial) compilación n.° 53599: fallas de fragmentos compilación n.° 53748: fallas de fragmentos compilación n.° 53753: fragmento compilación de fallas #53757: compilación de fallas de fragmentos #53759: compilación de fallas de fragmentos #53762: compilación de fallas de fragmentos #53787: compilación de fallas de fragmentos #53808: compilación de fallas de fragmentos #53811: compilación de fallas de fragmentos #53852: compilación de fallas de fragmentos #53863: compilación de fallas de fragmentos #53883: fragmento Failuresbuild #53893: fallas de fragmentosbuild #53914: sin fallas (ejecución parcial)build #53933: todos los fragmentos aprobadosbuild #53952: todos los fragmentos aprobadosbuild #53983: fallas de fragmentoscompilación #53992: fallas de fragmentosbuild #53999: fallas de fragmentosbuild #54007: sin fallas (ejecución parcial)build #54012: todos los fragmentos aprobadoscompilación #54015: todos los fragmentos aprobadoscompilación #54017: todos los fragmentos aprobadoscompilación #54022: fallas de fragmentoscompilación #54026: todos los fragmentos aprobadoscompilación #54030: sin fallas (ejecución parcial)compilación #54033: todos los fragmentos aprobadoscompilación #54040: todos los fragmentos aprobadoscompilación #54047: fallas de fragmentoscompilación #54049: fallas de fragmentoscompilación #54055: sin fallas (ejecución parcial)compilación #54057: fallas de fragmentoscompilación #54064: todos los fragmentos aprobadoscompilación #54074: todos los fragmentos aprobadoscompilación #54083: sin fallas (ejecución parcial)compilación #54093: todos los fragmentos aprobadoscompilación #54144: fallas de fragmentos, compilación #54161: fallas de fragmentos, compilación #54186: fallas de fragmentos, compilación #54189: fallas de fragmentos, compilación #54196: fallas de fragmentos, compilación #54202: todos los fragmentos pasaron
✓
Los fragmentos de prueba de cada compilación de CI, por plataforma, en 135 compilaciones que ejecutaron pruebas (420 extraídas de BuildKite). Verde brillante: cada fragmento pasó. Verde tenue: no hubo fallas, pero la carrera fue interrumpida (reemplazada). Rojo: al menos un fragmento falló. Cada carril está marcado cuando pasa por primera vez su conjunto completo: los 60 fragmentos de Linux estaban en verde casi un día antes que Windows. Las plataformas siguieron temblando en rojo hasta que cayeron las últimas pruebas fallidas; la versión final totalmente ecológica fue la número 54202.
El resto del tiempo previo a la fusión fue sencillo. Un flujo de trabajo que se repitió para corregir fallas en las pruebas de CI para cada plataforma hasta que no hubo más fallas en las pruebas. Varios flujos de trabajo para la limpieza relacionada con Windows, para deduplicar código, reducir el uso inseguro y, en general, limpiar parte del código.
Fusionando la reescritura Rust
Una vez que el 100% del conjunto de pruebas de Bun pasó en CI en todas las plataformas (y verifiqué manualmente que las pruebas se estaban ejecutando y no se omitían), ejecuté un montón de comandos localmente para probar cosas y luego presioné el botón de combinación.
Fusionarse con main no es una versión versionada. En este punto, tenía la suficiente confianza para seguir adelante y comprometerme con la reescritura, pero aún no lo suficiente para publicarla.
Estadísticas
En el pico, estábamos ejecutando 4 de estos flujos de trabajo a la vez, cada uno en un árbol de trabajo separado, cada uno con 16 Claudes por flujo de trabajo. Alrededor de 64 Claudes a la vez.
git log · claude/phase-a-portpeak: 58 confirmaciones en un minuto
52
compromisos
+796,601
líneas escritas, reescrituras incluidas
Martes, 5 de mayo, 0:39 a.m. PDT
primer lote de borradores de 100 archivosPR #30412 abierto fusionado
· fase-a: borrador del encabezado del lote-1 (100 archivos)+12,379−0
· fase-b1: rutas + compilación de cadenas (borradores de puerta; codificación/cadenas/superficie lexer mínimas)+2,312−2,149
Las 6.502 confirmaciones (excluidas las fusiones), reproducidas. Las barras rosas son en su mayoría código nuevo; Las barras cian se eliminan en su mayoría. El contador de líneas cuenta cada reescritura a lo largo del camino: la diferencia que aterrizó fue +1,009,272. El registro son mensajes de confirmación reales.
0 pruebas omitidas o eliminadas
11 días (3 de mayo → fusionado el 14 de mayo) · 6778 confirmaciones
| Plataforma | llamadas expect() | Pruebas | Archivos |
|---|---|---|---|
| Debian 13 x64 | 1,386,826 | 60,624 | 4,174 |
| macOS 14 arm64 | 1,259,953 | 58,850 | 4,175 |
| Windows 2019 x64 | 1,007,544 | 57,337 | 4,173 |
Antes de la fusión, esto requirió 5,9 mil millones de tokens de entrada no almacenados en caché, 690 millones de tokens de salida y 72 mil millones de lecturas de tokens de entrada almacenados en caché, alrededor de $165 000 al precio de API. A mano, creo que esto habría requerido a 3 ingenieros con contexto completo en el código base alrededor de un año, tiempo durante el cual no podríamos mejorar la compatibilidad de Node.js, corregir errores, solucionar problemas de seguridad o implementar nuevas características. Nunca hubiéramos hecho eso. La alternativa realista era no hacer nada y seguir solucionando los errores que aparecen en la parte superior de esta publicación para siempre.
Esta es la vanguardia de lo que es posible hoy. Utilicé una versión preliminar de Claude Fable 5, un modelo de clase Mythos. Los flujos de trabajo dinámicos de Claude Code mantuvieron a 64 Claudes en funcionamiento durante 11 días (de lo contrario, habría tenido que crear mi propio equipo para lograrlo).
El trabajo continúa
Desde que fusionamos el puerto Rust, hemos completado 11 rondas de revisión de seguridad de Claude Code Seguridad y abordamos los hallazgos.
También agregamos fuzzing guiado por cobertura las 24 horas del día, los 7 días de la semana de cada analizador en Bun: JavaScript, TypeScript, JSX, CSS, JSON5, JSONC, TOML, YAML, Markdown, INI, Bun scripts de Shell, rangos de semver, archivos .patch y colores CSS. El fuzzer envía automáticamente los errores que encuentra a Claude para que envíe un PR para reproducirlos y corregirlos, y los humanos revisan los PR. Hasta ahora, ha ejecutado nuestros analizadores 100 mil millones de veces, lo que ha generado alrededor de 15 RP.
En el momento de escribir este artículo, aproximadamente el 4% del código Rust de Bun se encuentra dentro de un bloque unsafe (~13,000 palabras clave unsafe en ~27,000 líneas / ~780,000 líneas), y el 78% de esos bloques son una sola línea: un puntero que proviene de C++ o una llamada a una biblioteca de C. Espero que este número disminuya con el tiempo a medida que refactoricemos desde un puerto Zig fiel (que no tenía una palabra clave unsafe greppable) a un Rust idiomático, pero continuaremos usando bibliotecas C y C++ como JavaScriptCore, por lo que siempre tendrá más proyectos unsafe que Rust puros.
Errores de portabilidad
El objetivo de la reescritura Rust es la estabilidad, pero sería imposible implementar un cambio masivo como este e introducir regresiones cero.
Esta reescritura introdujo 19 regresiones conocidas, cada una de las cuales ha sido corregida.
La mayoría de las regresiones provienen de código que es sintácticamente idéntico en ambos idiomas pero semánticamente diferente.
Efecto secundario dentro debug_assert!
Estos dos fragmentos parecen similares pero se comportan de manera diferente. assert de Zig es una función, por lo que su argumento se ejecuta en cada compilación. debug_assert! de Rust es una macro, por lo que en las compilaciones de lanzamiento se borra todo el expression, incluida la llamada insert_stale.
// Zig:
if (dev.framework.react_fast_refresh) |rfr| {
assert(try dev.client_graph.insertStale(rfr.import_source, false) == IncrementalGraph(.client).react_refresh_index);
}
// Rust:
if let Some(rfr) = &dev.framework.react_fast_refresh {
debug_assert!(dev.client_graph.insert_stale(&rfr.import_source, false)? == react_refresh_index);
}
insert_stale agrega un archivo al gráfico de recarga en caliente del servidor de desarrollo frontend. En las versiones de lanzamiento, dejó de ejecutarse y HMR se rompió en ciertos casos para proyectos con rutas HTML que usan React mientras que un archivo recargado en caliente se invalida: Cannot destructure property 'isLikelyComponentType' of 'k'. Las compilaciones de depuración funcionaron. #30678
Rebanadas de longitud impar
Bun (anterior a las conversiones integradas que admiten cortes) usó @divTrunc e ignoró un byte impar final. En cambio, bytemuck::cast_slice entra en pánico. Blob.text() en una marca de orden de bytes UTF-16 seguida de un número impar de bytes dejó de devolver una cadena y el proceso entró en pánico. Volvimos a ignorar el byte impar: &buf[..buf.len() & !1]. #31188
Verificaciones de límites
En macOS y Linux, compilamos el código Zig de Bun con ReleaseFast, lo que elimina las comprobaciones de límites. Las versiones de lanzamiento de Rust las conservan.
Bun interna nombres de archivos largos en una lista global que se desborda en bloques de desbordamiento. El código Zig original tenía un tamaño de cada bloque de count / 4, o 2048. El puerto dejó un marcador de posición:
/// ... so use a nonzero stand-in until Phase B threads the
/// per-instantiation value through.
pub const BSS_OVERFLOW_BLOCK_SIZE: usize = 64;
Eso redujo el límite de 8,4 millones de nombres de archivos internos a 270.272, que alcanzaron los proyectos reales, e hizo que un ptrs[4095] uno por uno que portamos desde Zig fuera accesible. Rust entró en pánico en lugar de escribir más allá del final. Zig también entraría en pánico en este caso, si usáramos ReleaseSafe (solo lo hicimos en Windows). #31503
comptime cadenas de formato
Output.pretty reescribe los marcadores de color <r> y <d> en escapes ANSI. En Zig, fmt es comptime, por lo que los marcadores desaparecen antes de que se sustituyan los argumentos. Las funciones Rust no tienen parámetros de tiempo de compilación, por lo que Output::pretty solo vio la cadena terminada y también reescribió los marcadores sobre los argumentos.
// Zig:
pub inline fn pretty(comptime fmt: string, args: anytype) void;
Output.pretty("<r>{f}<r>", .{hyperlink});
// Rust:
pub fn pretty(payload: impl PrettyFmtInput);
Output::pretty(format_args!("<r>{}<r>", hyperlink));
bun update -i imprime los nombres de los paquetes como hipervínculos OSC 8, terminados en ESC \. Esa barra invertida se encuentra justo antes del < del <r> final, el analizador de marcadores la come y el r se imprime como texto.
En Rust tiene que ser una macro: bun_core::pretty!("<r>{}<r>", hyperlink). #30693
Bun es mejor en Rust
Hasta ahora, Bun v1.4.0 corrige 128 errores que se reproducen en v1.3.14. Estos van desde pérdidas de memoria hasta fallas y texto de ayuda mal coloreado.
Uso de memoria reducido
Rust tiene una potente herramienta a nivel de lenguaje para limpiar la memoria: Drop. Cuando se implementa Drop, la función drop se llama automáticamente cada vez que el valor sale del alcance.
impl Drop for Bytes {
fn drop(&mut self) {
if !self.pinned.is_empty() {
JSC__JSValue__unpinArrayBuffer(self.pinned);
}
}
}
En Zig, defer se puede utilizar para ejecutar código al final de un alcance:
const bytes: ArrayBuffer = try .fromPinned(global, value);
defer bytes.unpin();
En Zig, defer debe agregarse a cada sitio de llamadas individual que pueda necesitar limpieza. Es fácil terminar olvidándose de limpiar (una pérdida de memoria) o ejecutar el código de limpieza dos veces en un código de manejo de errores que rara vez se alcanza (una doble liberación). En Rust, Drop se ejecuta automáticamente cuando el valor ya no es accesible, intercambiando "sin flujo de control oculto" por evitar una pistola común.
Drop solucionó varias pérdidas de memoria en Bun relacionadas con rutas de archivos en el código de manejo de errores.
Arreglamos todas las pérdidas de memoria instrumentables
Mejoramos la integración LeakSanitizer de Bun para realizar un seguimiento de todas las asignaciones de memoria de código nativo.
Aquí hay un ejemplo: cada llamada Bun.build() en proceso filtró varios megabytes de memoria: texto fuente analizado y tablas de símbolos AST que sobrevivieron a la compilación a la que pertenecían.
// Bundle the same 60-module project 2,000 times in one process
for (let i = 0; i < 2_000; i++) {
await Bun.build({
entrypoints: ["./index.js"],
minify: true,
sourcemap: "external",
});
}
En Bun v1.3.14, cada compilación pierde alrededor de 3 MB, para siempre; las herramientas como los servidores de desarrollo que agrupan cada solicitud eventualmente se quedan sin memoria. En Bun v1.4.0, la memoria se nivela:
| Construcciones | Bun v1.3.14 | Bun v1.4.0 |
|---|---|---|
| 500 | 1.914 MB | 526 MB |
| 1,000 | 3.506 MB | 586 MB |
| 1,500 | 5.097 MB | 608 MB |
| 2,000 | 6.745 MB | 609 MB |
Un intento anterior de hacer esto en Zig no se fusionó porque la falta de un equivalente de Drop hizo que fuera más difícil sentirse seguro al fusionarse.
Tamaño binario más pequeño
Los cambios iniciales en la reescritura Rust redujeron el tamaño binario en 3,8 MB en Windows, 5,5 MB en macOS y 6,8 MB en Linux. Esto se debe en gran medida a que usamos demasiado comptime en nuestro código Zig.
Después de esa reducción inicial, el equipo exploró más oportunidades para reducir el tamaño binario utilizando optimizaciones de enlazadores como el plegado de código idéntico, eliminando datos no utilizados de ICU y descomprimiendo lentamente pequeñas partes de libicu con un diccionario zstd bajo demanda.
Combinado con la reescritura de Rust, los cambios de ICU y el plegado de código idéntico, el tamaño binario de Bun se reduce en un ~20% en Linux y Windows.
| Versión | Plataforma | Tamaño |
|---|---|---|
| Bun v1.4.0 (canario) | Windows | 76 MB |
| Bun v1.3.14 | Windows | 94 MB |
| Bun v1.4.0 (canario) | Linux | 70 MB |
| Bun v1.3.14 | Linux | 88 MB |
Uso reducido de espacio de pila
El analizador TOML y todos los demás analizadores de descenso recursivo en Bun (JSON, YAML, JavaScript, TypeScript y más) ahora usan menos espacio de pila.
Esto provocó algunos fallos en las pruebas antes de fusionar la reescritura Rust:
bun test v1.3.14-canary.1 (e99311e58)
.......
105 | });
106 |
107 | it("Bun.TOML.parse throws on deeply nested inline tables instead of crashing", () => {
108 | const depth = 25_000;
109 | const deepToml = "a = " + "{ b = ".repeat(depth) + "1" + " }".repeat(depth);
110 | expect(() => Bun.TOML.parse(deepToml)).toThrow(RangeError);
^
error: expect(received).toThrow(expected)
Expected constructor: RangeError
Received function did not throw
Received value: {
a: {
b: {
b: {
b: {
b: {
b: {
b: {
b: {
b: [Object ...],
},
},
},
},
},
},
},
},
}
at <anonymous> (/var/lib/buildkite-agent/build/test/js/bun/resolve/toml/toml.test.js:110:42)
✗ Bun.TOML.parse throws on deeply nested inline tables instead of crashing [2907.64ms]
Rust emite los intrínsecos llvm.lifetime.start y llvm.lifetime.end de LLVM para las variables de pila cuando ya no están en uso, lo que permite a LLVM reutilizar ranuras de espacio de pila. Esto permite que funciones grandes con ámbitos anidados utilicen mucho menos espacio de pila.
Anteriormente, solucionamos manualmente un problema abierto refactorizando funciones particularmente grandes en muchas funciones más pequeñas.
2% - 5% más rápido
Rust admite la optimización del tiempo de enlace entre lenguajes entre C/C++ y Rust, lo que permite la integración entre lenguajes de programación (¡qué genial es eso!).
Evaluamos Bun v1.3.14 con Bun v1.4.0 en Linux x64 (EC2, Xeon Platinum 8488C). Rendimiento HTTP medido con oha frente a servidores hello-world, cargas de trabajo de aplicaciones medidas con hyperfine.
Rendimiento HTTP (req/s, promedio de 3 rondas)
| servidor | Bun v1.3.14 | Bun v1.4.0 | Δ |
|---|---|---|---|
| Bun.serve | 169.6k | 177.7k | +4.8% |
| node:http | 103.8k | 108.5k | +4.5% |
| Elysia | 158.9k | 163.3k | +2.8% |
| express | 64.5k | 66.6k | +3.2% |
| fastify | 91.5k | 95.9k | +4.8% |
Aplicaciones/CLI (hyperfine)
| carga de trabajo | Bun v1.3.14 | Bun v1.4.0 | Δ |
|---|---|---|---|
| next build | 13.62 s | 13.03 s | +4.5% |
| vite build (tsc + vite) | 1.69 s | 1.65 s | +2.2% |
| tsc -b --force | 0.94 s | 0.89 s | +4.7% |
Producción
Prisma lanzó la versión beta pública de Prisma Compute en la reescritura Rust de Bun.
"Nos topamos con pérdidas de memoria y un grupo de conexiones que no podía recuperarse después de pausar y reanudar una VM. Cuando apareció la reescritura Rust, la probamos con los mismos modos de falla. Los manejó perfectamente". - Alexey Orlenko
Claude Code v2.1.181 (lanzado el 17 de junio) y posteriormente use el puerto Rust de Bun. El inicio se volvió un 10% más rápido en Linux pero, por lo demás, casi nadie se dio cuenta. Aburrirse es bueno.
Envío
Bun v1.3.14 fue la última versión de Bun escrita en Zig. Bun v1.4.0 será la primera versión de Bun escrita en Rust. Está disponible en Canary ahora. Informe cualquier problema que encuentre:
bun upgrade --canary
Mantenibilidad
Para mí y para el equipo, nuestro nuevo código base Rust se parece mucho al antiguo código base Zig. Por ejemplo, aquí hay un fragmento del código Zig original y el nuevo código Rust:
pub fn canMergeSymbols(
scope: *Scope,
existing: Symbol.Kind,
new: Symbol.Kind,
comptime is_typescript_enabled: bool,
) SymbolMergeResult {
if (existing == .unbound) {
return .replace_with_new;
}
if (comptime is_typescript_enabled) {
// In TypeScript, imports are allowed to silently collide with symbols within
// the module. Presumably this is because the imports may be type-only:
//
// import {Foo} from 'bar'
// class Foo {}
//
if (existing == .import) {
return .replace_with_new;
}
// ...
}
// ...
}
pub fn can_merge_symbol_kinds<const IS_TYPESCRIPT_ENABLED: bool>(
scope_kind: Kind,
existing: symbol::Kind,
new: symbol::Kind,
) -> SymbolMergeResult {
if existing == symbol::Kind::Unbound {
return SymbolMergeResult::ReplaceWithNew;
}
if IS_TYPESCRIPT_ENABLED {
// In TypeScript, imports are allowed to silently collide with symbols within
// the module. Presumably this is because the imports may be type-only:
//
// import {Foo} from 'bar'
// class Foo {}
//
if existing == symbol::Kind::Import {
return SymbolMergeResult::ReplaceWithNew;
}
// ...
}
// ...
}
Cualquiera que comprenda el código Zig original comprenderá el código Rust traducido mecánicamente. Revisé el PR de reescritura Rust original comprobando que los agentes de revisión de código adversarios detectaban correctamente las discrepancias entre el código Zig y el código Rust, que se aseguraban de que se siguieran la guía de portabilidad y la guía de por vida, y también leía manualmente gran parte del código junto con Zig frente a Rust.
Qué sigue
Bun v1.4 hace que Bun sea más rápido, más pequeño, use menos memoria y le brinda al equipo herramientas increíblemente poderosas para mejorar sistemáticamente la estabilidad en el futuro: el comprobador de préstamos de Rust, Miri (que se ejecuta para una creciente porción de código en CI), LeakSanitizer y fuzzing guiado por cobertura 24 horas al día, 7 días a la semana para analizadores. Todavía queda más por refactorizar, pero las cosas han tenido un gran comienzo.
Esta reescritura Rust habría requerido un año de trabajo para un equipo de ingenieros con todo el contexto en el código base. Con 1 ingeniero usando Fable y monitoreando de cerca Claude Code, logramos aprobar el 100 % del conjunto de pruebas en todas las plataformas en 11 días.
Un ingeniero puede hacer mucho más hoy que hace un año.
