opopa.top

Принимаем работу агента по живым тестам

·5 мин чтения·обновлено

разборыагенты

Как принимать работу агента: живой бэкенд, проверка последствий, одна версия сборки и независимый повтор. Шаблон задания и отчёта.

Мы делаем терминал для агентов — SSH-клиент с tmux: на экране панель, а работа идёт на сервере. Поэтому нажатие «Разделить» должно создать ещё один терминал на сервере, а не только панель. В нашем живом GUI-тесте именно это и проверяется: число терминалов до нажатия сравнивается с числом после. Новая панель на экране сама по себе тест не удовлетворит.

Так удобнее ставить задачу кодинг-агенту. Вместо расплывчатого «почини кнопку» получается конкретное действие с наблюдаемым последствием. Агент может написать реализацию, запустить приложение и повторять сценарий до проверки человеком. Принимать результат по одному сообщению «готово» мы перестали.

Но каждое звено такой приёмки можно подделать — агентом или случайно. Ниже пять звеньев и чем закрыто каждое.

Что считать выполненной работой

У каждой приёмки есть три участника: исполнитель, приложение и проверяющий. Исполнитель меняет код. Приложение выполняет действие. Проверяющий смотрит, что действительно произошло. Если последний читает только пересказ первого, вся схема держится на доверии к тексту.

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

Даже нас агенты иногда вводят в заблуждение мокированными прогонами. Случай с подменённым IPC и проверкой на следующей ступени разобран в статье про пирамиду стендов.

Ничего не запустилось — нечего принимать

В живых API-тестах отсутствие окружения обозначено как NOT COLLECTED. Нет нужного сервера или сокета — проверка не состоялась. Для обязательной проверки это блокирует приёмку, хотя само приложение может быть исправно.

Отдельно считаются исполненные тесты и пропуски. Набор, который нашёл тесты, но пропустил их все, не подтверждает работу. Одного кода возврата тоже мало: при передаче вывода через tail без pipefail Bash возвращает статус последней команды, который может скрыть ошибку теста.

Я сам наступил на это, проверяя артефакт к черновику: печатал $? после пайпа и смотрел на код tail. Ошибка исчезла, когда сначала сохранил результат команды и лишь потом обрезал вывод для показа. Маленькая деталь, способная озеленить отчёт о полностью проваленном запуске.

Все устройства проверяют одну сборку

Несопоставимые результаты у нас дала и сама сборка. Каждая сборка устройства подтягивала главную ветку в начале своего запуска. Пока последовательные сборки заканчивались, ветка менялась. Устройства получали разный код, хотя в разговоре это называлось одним раундом проверки.

Теперь скрипт сборки требует ожидаемый SHA и проверяет чистоту отслеживаемого дерева до копирования исходников. Для одного раунда выбирается один коммит. Отчёт должен называть также конфигурацию: сборка для удалённой отладки и сборка для выпуска могут отличаться включёнными возможностями.

Один SHA не описывает незакоммиченные изменения или внешние зависимости. Для простой приёмки удобнее начать с чистого согласованного checkout и повторить тест, если код после него менялся.

Проверку тоже можно испортить

Надпись PASS в JSON не удостоверяет исполнение. Её можно написать руками. Хеш защищает сравнение содержимого, но сам по себе не доказывает, что тест запускался. Даже команда, напечатавшая «8 passed», могла вообще не вызвать тестовый раннер.

Поэтому из этого поста убран мой первоначальный скрипт, который разбирал stdout и называл результат доказательством. Он отсекал некоторые пустые прогоны, но обещание неподделываемости было неверным. Такой же ошибкой было бы объявить самодостаточной защитой приложенный ниже шаблон.

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

И тест должен уметь падать. Для исправления проверяем тот же сценарий на старой версии. Если обе версии проходят, тест не замечает дефект, сколько бы раз он ни позеленел. В начале октября это стало правилом репозитория: новая проверка — три зелёных прогона подряд и один на старом коде, где она обязана упасть. Безопасный отрицательный контроль в отдельной копии — ещё один способ проверить это предположение: убрать нужный эффект и убедиться, что проверка отказывает.

Приёмка — не полный прогон

Когда мы убрали моки, появилась обратная проблема: агент стал гонять весь живой набор на каждую правку — 44 минуты, хотя фича делается минут десять. Это описано в статье про агента-суперфаната.

Для приёмки одного изменения хватает его собственной проверки: четыре прогона одного теста, как выше. Полный набор нужен по поводу — перед раундом сборки на устройства или после нескольких слияний. Если в отчёте полный прогон без повода, это тоже стоит вернуть: время ушло, а доказательства не прибавилось.

Задание, с которым можно начинать

Артефакт — шаблон приёмки для исполнителя и проверяющего. В нём нужно заполнить действие, реальное последствие, способ его прочитать, команду запуска и среду. В конце остаётся отчёт с выполненными сценариями и тем, что проверить не удалось.

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