0:00 — сборка завершена. Агент говорит, что готово, но это утверждение о том, что код написан, а не о том, что он работает. Каждый пользователь ИИ-строителя хотя бы раз чувствовал разрыв между этими двумя утверждениями: превью открывается, нажимаешь третью кнопку — ничего не происходит. Я видел, как демонстрационная комната замолкала именно в такой момент. Поэтому, прежде чем сборку увидит хоть один человек, она проходит около шести минут цепочки, которая сама с собой спорит. Вот как это выглядит на самом деле, на примере одной сборки, которая пошла не так, а затем была исправлена.
0:02 — начинается код-ревью. Не тот же агент, который писал код, перечитывает своё же домашнее задание — это отдельный агент, с другим промптом, не заинтересованный в том, чтобы сборка прошла проверку. Это разделение важнее, чем кажется. Агент, который в 14:14 решил, что fetch-запрос без обработки ошибок — это нормально, в 14:15 будет думать так же, если попросить его проверить собственную работу. Свежий рецензент, которому сказано «найди, что сломано, укажи файл», ведёт себя как тот самый ворчливый senior-инженер, который вам нужен на этой роли. На одной из предыдущих сборок он обнаружил, что общая сумма корзины никогда не обновлялась — функция `updateTotal` была определена в `Cart.jsx`, но никогда не подключалась к обработчику изменения количества, так что функция существовала и просто никогда не вызывалась. Именно для таких случаев и нужен код-ревью — вещей, на которые компилятор просто пожмёт плечами.
0:04 — аудит безопасности. Он уже, чем может показаться, и это намеренно — это не пентест, а поиск паттернов, характерных для нескольких ошибок, которые реально встречаются в коде, сгенерированном ИИ. SQL-запросы через конкатенацию строк. Валидация только на клиенте, которой доверяют так, будто это вся история целиком. И особый случай: захардкоженный API-ключ, потому что у агента, писавшего функцию, не было под рукой соглашения об использовании переменных окружения, и он потянулся к тому, что просто работало. Мы видим это достаточно часто, чтобы это уже почти не удивляло.
0:07 — ссылки и SEO. Не самая яркая проверка, но она находит то, что никто не замечает, пока не заметит клиент: ссылка навигации, указывающая на /pricing тогда как страница на самом деле сгенерирована по адресу /price, запись в карте сайта для страницы, которая отдаёт 404, метаописание, до сих пор содержащее текст-заглушку из шаблона. Ничего из этого не ломает сборку. Но всё это тихо губит именно то, ради чего большинство наших пользователей и создавали сайт — возможность быть найденным и получать клики.
0:09 — доступность. Это автоматическая проверка на базе axe-core, а не полный ручной аудит, и стоит честно сказать, что даёт этот компромисс. axe-core находит проблемы с контрастностью, отсутствующий alt-текст, неподписанные поля форм, ловушки порядка табуляции — механический уровень, что-то около 30-40% от того, что выявил бы полный аудит WCAG. Он не поймает опыт использования со скринридером, который технически соответствует стандартам, но реально сбивает с толку. Мы выбрали только автоматическую проверку, потому что она выполняется за секунды, а через эту систему в основном проходят маркетинговые сайты и небольшие инструменты, а не приложения, где частичный аудит представляет реальный риск для кого-либо.
0:11 — проверка соответствия. Этот уровень задаёт не вопрос «хорошо ли это», а вопрос «соответствует ли это обещанному». В плане было четыре страницы, а в сборке — три: проверка соответствия это заметит. В плане была обещана рабочая форма обратной связи, а на деле форма без действия при отправке — тот же уровень, та же поимка. Это проверка, наиболее напрямую отвечающая перед пользователем, потому что она сверяется с заявленным намерением пользователя, а не с какой-то абстрактной идеей качества.
0:13 — проверка прямо в браузере, и именно на этом этапе наша сборка на самом деле сломалась. Этот уровень труднее всего обмануть, потому что он не читает код, а управляет настоящим браузером — кликает, вводит текст, ждёт, проверяет, что DOM изменился так, как должен был. Речь шла об идле-игре, а игры проходят здесь дополнительную проверку, потому что игра может выглядеть идеально попиксельно и при этом оставаться неиграбельной — отображение счёта может выглядеть безупречно, но быть полностью оторванным от логики начисления очков. Верификатор сыграл в неё. Счёт обновлялся нормально. Звук не издавал ни звука.
Три раунда, затем эскалация
Находка не попала к нам в виде отчёта об ошибке — она сразу ушла на исправление, и цепочка провела повторную проверку, до трёх раундов внутри сборки. Раунд первый: исправление затронуло инициализацию микшера, которая уже была в порядке, поэтому звук остался беззвучным. Раунд второй: другое исправление затронуло смежный на вид пограничный случай состояния загрузки и — такое случается чаще, чем можно ожидать, — внесло небольшую новую проблему, не решив исходную. Раунд третий: по-прежнему тишина, и на этом этапе обычно вы имеете дело либо с чем-то действительно сложным, либо с ложной тревогой, и это был сложный случай.
Тогда платформа самостоятельно инициировала эскалацию. Она поставила в очередь дополнительный прогон исправления, целиком сфокусированный на оставшейся находке, работая с клоном сборки, а не с самой сборкой — то есть эскалационный прогон мог провалиться, не стоя нам уже работающей версии. Этот прогон нашёл настоящую причину: флаг отключения звука, установленный во время более раннего отладочного прогона и так и не сброшенный обратно, находившийся в совершенно другом файле, чем те два, которые затрагивали предыдущие исправления. Флаг сбросили, провели повторную проверку — прошла. Никто не смотрел на эту сборку, пока она уже не заработала.
| Заказ | Слой | Что находит |
|---|---|---|
| 1 | Код-ревью | Сломанную логику, нерабочие обработчики, ошибки состояния |
| 2 | Аудит безопасности | Поверхности для инъекций, утечки секретов, небезопасные паттерны |
| 3 | Ссылки и SEO | Битые ссылки, отсутствующие метаданные, корректность sitemap/robots.txt |
| 4 | Доступность | Автоматический axe-core: контраст, подписи, навигация с клавиатуры |
| 5 | Соответствие | Содержит ли сборка то, что было обещано в плане |
| 6 | Проверка в браузере | Запускает сборку по-настоящему — кликает, вводит текст, наблюдает за реакцией |
Что я бы пропустил в следующий раз
За несколько месяцев до этой идле-игры мы пробовали более мягкую версию всей системы — верификаторам разрешалось поднимать любые опасения в произвольной формулировке. Это порождало находки вроде «стоит вынести это в отдельную функцию» и «это имя переменной можно сделать понятнее», которые выглядели как усердие, но ничего не исправляли. Прогоны исправлений тратили целые раунды на полировку формулировок вместо устранения реальных проблем. Мы ужесточили правило до: назови файл, опиши сбой, либо промолчи. Количество находок верификаторов упало примерно вдвое, и почти всё оставшееся было применимо на практике. Если бы я перестраивал это с нуля, я бы вообще пропустил мягкую версию и сразу перешёл к правилу доказательности — нам не нужно было усваивать этот урок дорогой ценой, но мы всё же его усвоили именно так.
У этого правила есть реальная цена, и я не буду это скрывать: расплывчатое, но верное замечание вроде «этот дизайн API кому-то аукнется через полгода» теперь просто отбрасывается, потому что верификатор не может привязать его к конкретному сбою. Мы смирились с этим компромиссом. Цепочка, которая также проводила бы архитектурный анализ, не была бы достаточно быстрой, чтобы запускаться на каждой сборке, а скорость — это весь смысл автоматизации этого процесса вместо того, чтобы просить человека делать это вручную.
Если кто-то спросит, я бы также не стал добавлять четвёртый раунд. Мы подобрали количество раундов на реальных сборках, и предельная польза после третьего раунда резко падает — первый раунд устраняет большинство исправимых находок, второй в основном устраняет проблемы, внесённые первым, а к третьему то, что осталось, либо действительно сложно, либо никогда по-настоящему не было сломано. Четвёртый раунд в основном просто увеличивает время ожидания при том же результате.
Ничто из этого не бесплатно и не безупречно. Шесть уровней плюс сколько бы ни потребовалось раундов исправлений добавляют реальное время к каждой сборке — разницу между тем, чтобы закончить меньше чем за минуту, и тем, чтобы закончить за несколько минут. Мы считаем это правильным компромиссом для всего, что вы собираетесь показать собственным клиентам, но «быстро» и «проверено» тянут в разные стороны, и мы выбрали проверенность. Верификаторы — это тоже LLM, поэтому они иногда отмечают то, что на самом деле не сломано, или пропускают то, что сломано. Правило доказательности и многораундовый цикл — это подстраховка от этого, а не гарантия.
В итоге вы получаете протокол: какие уровни отработали, что они нашли, что было исправлено, и что осталось на ваше собственное усмотрение. Этот протокол ближе к реальному продукту, чем сам код — это разница между доверием сборке потому, что она выглядит завершённой, и доверием ей потому, что нечто враждебное попыталось её сломать и потерпело неудачу.



