Назад к блогу

Агенты переписывают кодовые базы: чему учат миграции GitHub и Anthropic на Rust

Агенты переписывают кодовые базы: чему учат миграции GitHub и Anthropic на Rust

Две громкие миграции на Rust — рантайма Copilot в GitHub и JavaScript-рантайма Bun в Anthropic — показывают, насколько по-разному можно встроить ИИ-агентов в переписывание крупной кодовой базы: от 128 постепенных pull request'ов до единовременного порта почти 536 тысяч строк. Разбор их подходов полезен тем, кто думает о собственных крупных миграциях и хочет понять, где именно агенты уже меняют экономику таких проектов.

Две крупные миграции на Rust — рантайма Copilot у GitHub и JavaScript-рантайма Bun у Anthropic — устроены настолько по-разному, что их удобно читать как два противоположных ответа на один вопрос: как встроить агентов в переписывание большого объёма кода. Ниже — механика обоих процессов, роль инструментов Rust в агентном цикле и условия, при которых такая миграция вообще становится возможной.

Две кодовые базы и два подхода

GitHub переписывал на Rust рантайм продукта Copilot. Работу выполняли собственные агенты компании — приложение GitHub Copilot и Copilot CLI. Изменения шли 128 pull request'ами, которые мержились и поставлялись постепенно. Разработка продукта при этом продолжалась вокруг миграции: части рантайма конвертировались и выпускались по мере готовности.

Anthropic переписывал Bun — JavaScript-рантайм, приобретённый в декабре. Это был порт 535 496 строк Zig в Rust, выполненный сразу целиком: множество параллельно работающих агентов Claude Code переводили и проверяли разные части одновременно, а основатель Bun Jarred Sumner следил за их работой и вмешивался при сбоях.

Разница принципиальна. Bun выбрал all-at-once port. GitHub выбрал более медленный инкрементальный путь: части рантайма конвертировались и поставлялись по мере готовности, пока разработка продукта продолжалась вокруг миграции. Мотивация у обеих компаний схожая: агенты сделали крупные переписывания доступными по стоимости там, где раньше такие проекты были бы слишком дорогими.

Playbook GitHub: агенты в цикле миграции

Инициатором выступила сама компания. Microsoft engineer Stephen Toub сообщает, что GitHub использовала собственные Copilot coding agents для перевода рантайма Copilot на Rust, а инструментами служили GitHub Copilot app и Copilot CLI.

Работа была разбита на 128 pull request'ов, которые мержились и поставлялись инкрементально. Такой подход, по словам Toub, позволял ловить и исправлять регрессии по ходу. Процесс занял примерно 14 с половиной недель, при этом разработка продукта продолжалась параллельно.

Какие именно проверки и guardrails GitHub ставит перед слиянием и на каком шаге обязан вмешаться человек, не описано. Известно только, что работа шла через 128 pull request'ов с постепенным мержем и выпуском, что давало возможность находить и исправлять регрессии по ходу. Отдельно упоминается, что нужны CI с merge queue, а лимитирующим фактором для dev-агентов является окружение, в котором они работают, а не модели и harnesses.

Playbook Anthropic: агенты как основной исполнитель

У Bun Sumner организовал несколько агентов Claude Code, которые параллельно переводили и проверяли разные части кодовой базы. Задачи распределялись по разным частям Bun, а сам Sumner следил за работой агентов и вмешивался при отклонениях процесса.

Проверка корректности опиралась на существующие тесты: через одиннадцать дней после старта Rust-версия проходила существующие тесты Bun на всех шести поддерживаемых платформах. После этого код был смержен, но дальнейшее ревью и очистка продолжались до релиза.

Инструменты Rust в агентном цикле

clippy

clippy запускается в трёх режимах: базовый — cargo clippy, автоматическое исправление — cargo clippy --fix, превращение предупреждений в ошибки — cargo clippy -- -D warnings. Дополнительный набор придирчивых проверок включается флагом -W clippy::pedantic.

Поведение части линтов настраивается в TOML-файле clippy.toml или .clippy.toml, который содержит простое сопоставление variable = value. Один из таких параметров — msrv, задаваемый строкой версии:

msrv = "1.30.0"

rustfmt

rustfmt — инструмент форматирования кода Rust. Запускается как rustfmt filename либо через cargo fmt для всех бинарных и библиотечных целей крейта. Для согласованного форматирования между cargo fmt и rustfmt рекомендуется задавать style_edition в rustfmt.toml, например style_edition = "2024". Причина в том, что rustfmt по умолчанию использует стилевую редакцию 2015, а cargo fmt выводит её из edition в Cargo.toml; рассинхрон этих настроек приводит к тому, что две команды форматируют один и тот же код по-разному. Чтобы разбор тоже был согласованным, следует настраивать edition в rustfmt.toml.

Ограничения rustfmt, влияющие на автоматизацию, включают: программы, где любая часть не парсится; объявления и использования макросов; комментарии и узлы AST с комментарием внутри; код Rust в блоках кода в комментариях; фрагменты программ; код с не-ASCII Unicode; а также баги самого rustfmt. Среди nightly-only опций — coverage, checkstyle и json, тогда как files и stdout доступны без nightly.

rust-analyzer и rustup

rust-analyzer — языковой сервер, предоставляющий функциональность IDE для написания программ на Rust; совместим с любым редактором, поддерживающим Language Server Protocol. Его возможности включают переход к определению, поиск всех ссылок, рефакторинги и автодополнение кода, а также интегрированное форматирование (с rustfmt) и интегрированную диагностику (с rustc и clippy). Внутренне rust-analyzer устроен как набор библиотек для анализа кода на Rust.

rustup — установщик тулчейна Rust из официальных каналов выпуска, позволяющий легко переключаться между компиляторами stable, beta и nightly и поддерживать их в актуальном состоянии. Он упрощает кросс-компиляцию за счёт бинарных сборок стандартной библиотеки для распространённых платформ и работает на всех платформах, которые поддерживает Rust, включая Windows.

Условия, при которых агентная миграция вообще возможна

agent-legible dev environments нужны потому, что ошибки возникают преимущественно там, где агенты их не видят; без видимости интеграций и фронтенда агенты работают вслепую.

global memory нужна, чтобы агенты не повторяли одни и те же ошибки. Исправления, сделанные одним агентом, должны быть известны всем будущим агентам: система памяти должна работать по всему инструментарию, чтобы бот ревью кода знал о поправке, выданной агенту две недели назад.

codebase rot prevention нужно, чтобы не накапливались мёртвый код, несколько способов делать одно и то же и расхождения типа и данных с продуктом. Без этого кодовая база начинает спиралить.

Защитный код агенты генерируют из-за стремления закрыть любую мыслимую неоднозначность без понимания реальных рисков. Повторение ошибок связано с отсутствием общей памяти: если каждому новому агенту приходится заново объяснять одно и то же, команда возвращается в цикл низкоуровневой работы.

Tokenmaxxing и следующий шаг

Авторы описывают tokenmaxxing: в первой половине года инженерные организации делали это, но получили горы сомнительного кода без цунами невероятного софта, а ROI по токенам был в лучшем случае шатким.

Следующим шагом авторы называют не простое увеличение контекста, а self-driving codebase. Причина в том, что ценность инженерной работы смещается к наличию хороших идей и убийственной архитектуре, а не к низкоуровневой работе, которую должны брать на себя агенты. Предлагаемый путь состоит из трёх шагов: искать баги в кодовых базах и учиться выбирать значимые; исправлять их, отслеживая пробелы, мешающие проверить корректность фикса или реальность бага; использовать трассы исправлений для приоритизации работы по адаптации кодовой базы к агентам. Это позволяет постепенно повышать готовность кодовой базы к агентам и передавать им всё большую часть работы. Ограничивающим фактором для dev-агентов авторы называют среду, в которой они работают, а не модели и харнессы.

Пограничные случаи и риски

Систематическая ошибка агентов, которую называют источники, — большие объёмы избыточно защитного кода: агенты пытаются закрыть любую мыслимую неоднозначность, не зная, какие риски реальны.

Для отлова ошибок до мержа источники предлагают clippy: cargo clippy -- -D warnings превращает предупреждения в ошибки, cargo clippy -- -W clippy::pedantic включает дополнительный набор придирчивых проверок. Кроме того, нужна глобальная память: исправления, выданные одному агенту, должны быть известны всем будущим агентам, включая бота-ревьюера, чтобы ошибки не повторялись. Также упоминается предотвращение гниения кодовой базы — контроль мёртвого кода, дублирующих способов решения и интуитивности типов. В примере с миграцией Bun код сначала прошёл существующие тесты на всех шести платформах, и только затем был смержен, хотя дальнейшая проверка и очистка продолжались до релиза.

Boneheaded mistakes и роль global memory

Сам факт множества глупых ошибок агентов источник считает допустимым. Недопустимо лишь повторение одной и той же ошибки. Проблема в том, что если одну и ту же поправку приходится сообщать каждому агенту, который касается этой области, человек снова оказывается в цикле низкоуровневой работы. Поэтому global memory позиционируется как система, работающая по всему инструментарию: бот ревью кода должен знать о поправке, выданной агенту две недели назад, а после выговора SRE-боту за небезопасную prod-операцию агент должен понять причину, и каждый будущий агент должен знать об этой поправке.

Что видит пользователь во время миграции

Для пользователей продуктов GitHub миграция была постепенной: части рантайма Copilot переводились и выпускались по мере готовности, разработка продукта продолжалась вокруг миграции. Работа была разбита на 128 pull request'ов, что позволяло находить и исправлять регрессии по ходу.

Для пользователей Bun миграция была связана со стабильностью: рост проекта сопровождался постоянными ошибками управления памятью, включая утечки и падения, и компания заявила, что обязана систематически предотвращать их повторение, а не чинить по одному случаю. Через одиннадцать дней после старта версия на Rust проходила существующие тесты Bun на всех шести поддерживаемых платформах, затем код был слит, но до релиза продолжались проверка и очистка.

Компромиссы и мотивация

Подходы у компаний разные: Bun пошёл на all-at-once port с множеством параллельных экземпляров Claude, GitHub выбрал более медленный инкрементальный путь с конвертацией и выпуском частей рантайма по мере готовности в 128 pull request'ах.

Причина выбора массовой переписи у Bun экономическая: обычный рерайт 535 496 строк Zig потребовал бы небольшой команды примерно на год, что сделало бы проект нереалистичным, поскольку означало бы заморозку багфиксов, security-фиксов и разработки фич. GitHub также считает, что рерайт такого размера был недоступен до агентов, оценивая прежнюю стоимость в год-два работы команды.

Компромиссы: у GitHub инкрементальный подход через 128 pull request'ов позволил ловить и исправлять регрессии по ходу, а у Bun после слияния Rust-версии продолжались дополнительное ревью и очистка перед релизом.

Конфликт интересов

GitHub и Anthropic — крупные вендоры тех самых кодирующих агентов, которым они приписывают заслугу в выполнении проектов, поэтому их рассказы по своей природе корыстны. У обеих компаний есть все основания приводить такие доводы: именно они больше всех выигрывают от демонстрации того, на что способны агенты при крупных переписываниях. Такие проекты пока остаются отдельными кейсами, о которых сообщают компании с наибольшей выгодой. При этом по индустрии есть признаки, что явление «агенты делают крупную миграцию на Rust» набирает силу. Отдельно указано, что владелец TNS Insight Partners является инвестором OpenAI и Anthropic.

Что из этого следует на практике

  • Выбор между all-at-once и инкрементальным путём — это выбор между скоростью и управляемостью регрессий. Bun прошёл путь до прохождения тестов на всех шести платформах за одиннадцать дней, но после слияния ещё продолжал ревью и очистку до релиза. GitHub шёл медленнее, зато ловил и исправлял регрессии по ходу.
  • Экономика решает. Обычный рерайт 535 496 строк Zig потребовал бы небольшой команды примерно на год с заморозкой багфиксов, security-фиксов и фич. Именно недоступность такой цены до агентов — общий аргумент обеих компаний.
  • Тесты — единственный названный критерий готовности. У Bun это прохождение существующих тестов на всех шести поддерживаемых платформах; порогов покрытия или clippy не приводится.
  • Инструменты Rust дают агенту обратную связь, которую можно автоматизировать. clippy с -D warnings превращает предупреждения в ошибки, --fix правит автоматически, -W clippy::pedantic добавляет придирчивые проверки; rustfmt нормализует диффы, но не парсит макросы, комментарии и фрагменты программ, а часть его опций доступна только на nightly.
  • Среда важнее модели. Лимитирующий фактор для dev-агентов — окружение, в котором они работают, а не модели и харнессы; ошибки возникают там, где агенты не видят.
  • Без общей памяти ошибки повторяются. Допустимы многие глупые ошибки, недопустимо их повторение: если поправку приходится сообщать каждому агенту, затрагивающему область, человек возвращается в цикл низкоуровневой работы.
  • Избыточно защитный код — систематическая ошибка агентов, и её приходится отлавливать до мержа вместе с мёртвым кодом, дублирующими способами решения и неинтуитивными типами.
  • Кейсы публикуют заинтересованные стороны. Обе компании — вендоры тех самых агентов, поэтому цифры и выводы стоит читать с поправкой на этот интерес.

Источники

Похожее