Bun завершив 11-денну міграцію коду, спрямовану на ІІ, з Zig на Rust

iconMetaEra
Поділитися
AI summary iconКороткий зміст
Bun оголосив про запуск проекту у травні 2026 року, завершивши 11-денну AI-спрямовану міграцію коду з Zig на Rust. Зусилля включало понад 1 мільйон рядків коду, 6 778 комітів та 64 паралельні екземпляри Claude, що коштувало $165 000. Використання пам’яті зменшилося з 6,7 ГБ до 609 МБ після 2 000 збірок, з приростом продуктивності на 2–5%. У коді тепер міститься 13 000 ключових слів unsafe та 19 регресій. Проект тепер належить Anthropic. Цей оновлений новинний матеріал про AI та криптовалюту підкреслює значну зміну інфраструктури проекту.
Проект Bun завершив велике перенесення коду з Zig на Rust у травні 2026 року, здійснивши понад 1 мільйон змін рядків коду та 6 778 комітів за 11 днів. Для перенесення використовувалося 64 екземпляри Claude, що спричинило витрати на API у розмірі 165 000 доларів США. Після перенесення було фундаментально вирішено проблему витоків пам’яті: після 2000 збірок пам’ять стабілізувалася на рівні 609 МБ замість 6,7 ГБ, продуктивність зросла на 2–5%, а розмір бінарних файлів зменшився приблизно на 20%. Однак у коді залишилося близько 13 000 ключових слів unsafe — у 178 разів більше, ніж у подібних проектах; виявлено 19 відомих регресійних проблем, а також неможливо вручну перевірити кожен з мільйона змінених рядків. Наразі проект Bun був придбаний Anthropic.

Автор статті, джерело: InfoQ

У травні 2026 року проект Bun здійснив масштабне перенесення коду, що є майже рідкісним явищем в історії розробки програмного забезпечення.

Ця міграція розпочалася 3 травня і була офіційно об’єднана з основною гілкою 14 травня, що зайняло лише 11 днів. Написання коду тривало 6 днів, і весь процес був відкритим. Однак Джарреду Сомеру знадобилося майже місяць, щоб написати блог-підсумок — набагато довше, ніж на написання коду.

Цей JavaScript-середовище виконання спочатку містило 535 496 рядків коду Zig, без урахування коментарів; приблизно 20% коду було написано на C++ і вбудовано кілька бібліотек C/C++. Під час переписування за допомогою AI на Rust, весь процес включав понад мільйон змін рядків коду, 6778 комітів і запуск приблизно 50 динамічних робочих процесів у Claude Code.

Згідно з даними, оприлюдненими Сомером, це переписування спожило 5,9 мільярда некешованих вхідних токенів, 690 мільйонів вихідних токенів та 72 мільярди кешованих вхідних токенів, що за цінами API становить приблизно 165 000 доларів США.

Самнер сказав, що це межа того, чого можна досягти за допомогою сучасних технологій. Він оцінив, що якби три інженери, повністю знайомі з кодовою базою Bun, виконали цю міграцію вручну, це зайняло б близько року, і протягом цього року команда майже не змогла б продовжувати розробку нових функцій, виправлення помилок та безпекових виправлень.

Після цього переписування Bun v1.3.14 стане останньою версією на Zig, а Bun v1.4.0 — першою версією на Rust.

1 Результат: від 6,7 ГБ утечки пам’яті до стабільних 609 МБ

Bun спочатку був проектом на Zig і мав дуже широкий функціонал: він є транслятором JavaScript і TypeScript, бандлером, менеджером пакетів, запускачем тестів, резолвером модулів, а також клієнтом HTTP і WebSocket і реалізує шар API Node.js. Саме така широка функціональність зробила Bun CLI одним із найбільш завантажуваних інструментів у світі — понад 22 мільйони завантажень на місяць — і привернула підтримку таких проектів і компаній, як Vercel, Railway, DigitalOcean, Claude Code та OpenCode.

Але та сама ширина також створила деякі виклики для Bun.

Зокрема у Bun v1.3.14 існувала проблема, яка довго турбувала користувачів: під час послідовних викликів Bun.build() пам’ять накопичувалася і ніколи не звільнялася. Кожна збірка призводила до витоку приблизно 3 МБ — це здається невеликою кількістю, але якщо ви запускаєте розробницький сервер, де кожен запит тригерить збірку, пам’ять поступово споживається, доки процес не аварійно завершиться.

У реальних тестах після 500 збірок використання пам’яті становило 1,9 ГБ, після 1000 — 3,5 ГБ, після 1500 — 5,1 ГБ, а після 2000 — стрімко зросло до 6,7 ГБ.

Це лише вершина айсберга багатьох проблем з пам’яттю. У списку виправлень багів у v1.3.14 Sumner навів довгий перелік проблем:

Під час виклику .reset() у модулі zlib, якщо асинхронний .write() ще виконується у пулу потоків, процес аварійно завершується через «використання після звільнення купи»; у модулі http2 вкладені JavaScript-зворотні виклики спричиняють перехешування хеш-таблиці, що призводить до недійсності внутрішніх покажчиків потоку; під час перебору UDPSocket.sendMany(), якщо код користувача змінює стан підключення сокета через зворотні виклики valueOf або toString, відбувається запис за межами буфера; у crypto.scrypt, якщо виділення буфера виводу не вдалося, зворотний виклик і захищений буфер паролю ніколи не звільняються;......

Загальна риса цих багів очевидна — вони майже всі вказують на одну й ту саму причину: поєднання GC із ручним управлінням пам’яттю в одній програмі.

Сучасні движки, такі як JavaScriptCore (та V8), мають надзвичайно строгі правила щодо обробки винятків і GC, тоді як Zig, як і C, не керує пам’яттю автоматично. Коли ці дві парадигми працюють в одному процесі, кожне виділення пам’яті потребує построкового аналізу: де звільняються ці байти? Як забезпечити, щоб вони звільнялися лише один раз? Чи правильно перевіряються JavaScript-винятки? Чи видимий цей покажчик, що керується GC, для консервативного сканера стека? Це пам’ять, що керується GC, чи пам’ять, що керується вручну?

Ще більш тривожним є те, що команда не зробила нічого лишнього. Вони внесли зміни до компілятора Zig, додали підтримку Address Sanitizer (ASAN), запускають тести ASAN у CI при кожному коміті, використовують ReleaseSafe збірки на Windows, проводять 24/7 фаззинг за допомогою Fuzzilli та велику кількість енд-ту-енд тестів на виявлення витоків пам’яті. Незважаючи на це, звіти про збої продовжують постійно надходити.

«Наш список виправлень багів викликає неприємні відчуття, я втомився лягати спати зі страхом, що Bun зламається», — написав Сомер. Він не звинувачує Zig — інші користувачі Zig не стикалися з такими проблемами з Bun, бо поєднання GC із ручним управлінням пам’яттю — це надзвичайно рідкісна вимога, для якої майже жодна мова не була розроблена.

А версія на Rust показала такий результат: під час виконання 2000 разів Bun.build() пам’ять стабільно залишається на рівні 609 МБ.

Крім фундаментального вирішення проблеми витоків пам’яті, переписування на Rust принесло покращення в кількох інших аспектах.

Щодо стабільності, v1.4.0 виправив 128 відтворюваних багів з v1.3.14, включаючи витоки пам’яті, збої та помилки відображення кольорів у довідкових повідомленнях.

З точки зору розміру, поєднання переписування на Rust, змін ICU та того ж згортання коду зменшило розмір двійкових файлів Bun на Linux і Windows приблизно на 20%.

Щодо продуктивності, загальне покращення становить 2–5%. Bun.serve збільшився з 169 600 запитів/с до 177 700 запитів/с, node:http — з 103 800 до 108 500. У реальних сценаріях застосування next build зменшився з 13,62 до 13,03 секунди, а пакетна компіляція tsc — з 0,94 до 0,89 секунди.

Після випуску Claude Code на основі Rust Bun, час завантаження на Linux знизився з 517 мс до 464 мс, що на 10% швидше.

2 методи: 64 Claude, 11 днів, 50 робочих процесів

Як Сомеру вдалося це зробити — це, мабуть, найбільш варте уваги: бо він використав метод, відмінний від традиційного «дозволити ШІ писати код».

Самнер розбив весь процес на близько 50 динамічних робочих потоків, кожен з яких є циклом. Він описав цей шаблон у своєму блозі за допомогою псевдокоду:

Кожне завдання має контекст (наприклад, Jira ticket або GitHub issue), Claude пише код на основі цього контексту, а потім два рецензенти (також Claude) перевіряють код, після чого застосовуються зворотні зв’язки. Після завершення береться наступне завдання.

Цей підхід пронизує весь процес переписування. Кожен робочий процес відповідає за конкретну мету:

  • Створіть посібник з міграції, щоб зіставити шаблони та типи Zig з шаблонами та типами Rust;
  • Механічно перенесіть кожен файл .zig у файл .rs, зіставивши з PORTING.md і LIFETIMES.tsv;
  • Виправте помилки компіляції для кожного crate;
  • Запустіть підкоманди, такі як bun test або bun build;
  • Пройдіть усі тести в тестовому наборі Bun; зробіть кілька циклів великих рефакторингів та очищення.

У пік своєї роботи Семнер одночасно запускав 4 робочих процеси, у кожному з яких працювало 16 Claude, разом 64 Claude, що паралельно працювали у 4 робочих деревах, надсилаючи та відправляючи файли. У пік навантаження Claude писали приблизно 1300 рядків коду на хвилину.

Ця роздільна структура «реалізатор / рецензент» є ключовою. Claude, який пише код, хоче, щоб код був прийнятий — так само, як і людські інженери, він має упередження. Тому рецензенти і реалізатори повністю розділені — рецензенти бачать лише різниці в коді, але не бачать міркувань реалізатора, і їм чітко сказано: «припустіть, що код неправильний». На кожного реалізатора припадає більше двох протиставлених рецензентів, чиє єдине завдання — знаходити баги.

Написання коду — це лише перший крок. Код Zig є єдиним компіляційним одиницем, тоді як Rust потрібно розбити на близько 100 crate, щоб прискорити компіляцію; циклічні залежності призводять до того, що cargo check виводить одночасно близько 16 000 помилок. Для одного це катастрофа, але для 64 паралельно працюючих Claude це просто черга завдань, яку можна обробити. Робочий процес групує помилки за crate, для кожного crate запускається cargo check, один Claude виправляє, два перевіряють, один застосовує зміни.

Далі виконується bun --version, а потім bun test. Тестовий робочий процес випадково запускає 100 тестових файлів, розподілених на 4 робочі дерева. Тестовий набір також містить кілька типів: деякі тести працюють більше хвилини, деякі вичерпують кількість системних TCP-з’єднань, а деякі fork-ують близько 10 000 процесів. Sumner використовував systemd-run для створення cgroup для обмеження ресурсів, але машина все ще кілька разів збоїла через нестачу дискового простору.

Через два дні кількість невдалих тестів на платформі Linux зменшилася з 972 до 23. Після півтора днів Linux повністю пройшов тести. Через п’ять днів усі шість платформ — Linux x64, Linux arm64, macOS x64, macOS arm64, Windows x64, Windows arm64 — успішно пройшли тести.

14 травня PR #30412 було офіційно об’єднано, усі тести пройдені, жоден тест не було пропущено чи видалено.

3 Тривога: 13 000 небезпечних та неможливих для построкового перевірки рядків коду

Проте Сомер також визнає, що ця робота ще не завершена.

На даний момент у Rust-коді Bun приблизно 4% розташовані всередині unsafe-блоків, близько 13 000 ключових слів unsafe, розподілених у приблизно 27 000 рядках коду, тоді як загальний обсяг Rust-коду становить близько 780 000 рядків. Приблизно 78% unsafe-блоків містять лише один рядок, зазвичай це вказівник із C++ або виклик бібліотеки C.

Він очікує, що подальша рефакторизація знизить цей відсоток. Але хтось провів розрахунок: uv містить близько 350 000 рядків коду та лише 73 виклики unsafe. У Bun кількість unsafe в 178 разів більша, ніж у uv. Ця різниця важко пояснюється лише «необхідністю викликів бібліотек C».

І потім невизначена поведінка була виявлена й у безпечному коді на Rust. Це складніше налагоджувати, ніж у C++, бо ти вважаєш, що безпечний код не може мати помилок.

Після цього команда Bun змінила PathString::init на unsafe fn.

Сам Сомер підтвердив, що це переписування внесло 19 відомих регресійних проблем, і зазначив, що більшість із них виникли через код з однаковою граматикою, але різним значенням.

Наприклад, ці два фрагменти коду виглядають дуже схоже, але поводяться по-різному. У Zig assert є функцією, тому її параметри виконуються під час кожної збірки. У Rust debug_assert! — це макрос, тому у випускній версії весь вираз (включаючи виклик функції) видаляється insert_stale.

Хоча всі проблеми вже виправлено, це не означає, що в мільйоні рядків AI-коду немає інших проблем.

Хто звичайний людина перенесе своє продуктивне застосунок одразу після повної переписки його часу виконання? Вважати, що версія 1.4 не ввела нових багів або змін у поведінці, — це надто наївно.

Ще одна річ, яку не можна ігнорувати — це перевірка коду. Переглянути 1 мільйон рядків змін людиною по одному рядку неможливо — навіть якщо витрачати по хвилині на рядок, знадобиться безперервно 11,7 днів; при реальній швидкості перевірки коду (200 рядків за годину) знадобиться більше двох років, щоб їх переглянути.

Основними рецензентами цього PR були claude[bot] та coderabbitai[bot]. Сам Сумнер визнав, що його підхід до рецензування полягав у «перевірці, чи правильно агент протистояння виявив різниці, забезпеченні дотримання керівництва щодо перетворення, а також вручну прочитанні значної кількості коду». Але скільки саме — він не сказав.

Ще одна незручна проблема: Bun була придбана Anthropic у грудні 2025 року, і єдиним інструментом, який справді може ефективно підтримувати цей репозиторій, є сам Claude. У спільноті деякі стверджують, що це вже не можна вважати відкритим проектом у традиційному розумінні — щоб надіслати PR до Bun, вам потрібно спочатку підписатися на Anthropic або покладатися на кількох ключових учасників, які вже зрозуміли код, згенерований ШІ.

Чи варто 165 000 доларів США за рік роботи?

Саммер також розкрив у блозі, що вартість переписування API становить приблизно 165 000 доларів США, що дорівнює роботі трьох інженерів протягом року. Це число викликало запеклі дискусії на Hacker News.

Дехто вважає, що ця витрата насправді дуже вигідна. За 165 тисяч доларів США в Сіліконовій долині не вдасться найняти навіть кількох повноцінних інженерів, не кажучи вже про інженерів компанії рівня Anthropic. Згідно з даними про заробітну плату з levels.fyi, загальний пакет винагороди інженера Anthropic, ймовірно, досягає 500 тисяч доларів США або навіть більше. Навіть за грубою оцінкою — середня річна заробітна плата 50 інженерів у розмірі 336 тисяч доларів США — щоденна вартість становить близько 1292 доларів США. Витрати на заробітну плату для 50 осіб, які працювали безперервно 11 днів, вже складають майже 710 тисяч доларів США, не враховуючи бонусів, оренди офісних приміщень, обладнання та інших адміністративних витрат.

Але Сомер використовував «попередню версію Claude Fable 5» — високопродуктивну модель, яка ще не доступна для загальної публіки і може підлягати експортному контролю. Тому ціни на API — це лише цифри, які бачать кінцеві користувачі, а за ними — величезні інвестиції Anthropic у дослідження та розробку. Хтось зазначив, що спрощення витрат до рівня цін на API навмисно зменшує реальні витрати. Якщо врахувати витрати на розробку моделі, навчання, обчислювальні ресурси, інженерні зусилля тощо, загальні витрати, безумовно, будуть дуже високими — ймовірно, перевищать 1,5 мільйона доларів США.

І наразі, хоча 165 000 доларів за рік роботи здається досить вигідним на папері.

Але справжні витрати не вказані в цьому рахунку. Цей репозиторій містить 6778 комітів, і ніхто не читав його повністю від початку до кінця. Хоча зараз все працює нормально, а що буде через шість місяців? Коли у три години ночі раптово виникне дивна проблема з конкурентним доступом, і інженер, який несе чергову зміну, зіткнеться з системою, логіку якої навіть він сам не може чітко пояснити. А що буде далі — чи доведеться весь цей код підтримувати за допомогою ШІ? Як розрахувати витрати на підтримку? Насправді, це дуже складно.

Відмова від відповідальності: Інформація на цій сторінці може бути отримана від третіх осіб і не обов'язково відображає погляди або думки KuCoin. Цей контент надається лише для загального інформування, без будь-яких запевнень або гарантій, а також не може розглядатися як фінансова або інвестиційна порада. KuCoin не несе відповідальності за будь-які помилки або упущення, а також за будь-які результати, отримані в результаті використання цієї інформації. Інвестиції в цифрові активи можуть бути ризикованими. Будь ласка, ретельно оцініть ризики продукту та свою толерантність до ризику, виходячи з ваших власних фінансових обставин. Для отримання додаткової інформації, будь ласка, зверніться до наших Умов використання та Розкриття інформації про ризики.