Когда автоматические проверки говорят неправду: пять случаев из проекта, который пишут ИИ‑агенты

Я не программист. По крайней мере, несмотря на то, что в 2010 году я закончил «Прикладную информатику в менеджменте» (ДГТУ) и учился писать на C++, таковым в настоящее время себя не считаю.
При этом с июня 2026 года я управляю большим продуктом (собственная фабрика аналитики, своего рода ERP внутри компании), код которого пишут ИИ‑агенты. Я даю задачи голосом (не помню, когда в последний раз формировал текст задач на клавиатуре), агенты пишут код, проверяют его и выкладывают новую версию на сайт. Продукт собран на Next.js 16, TypeScript и PostgreSQL. На 1 октября в истории проекта уже более 8000 коммитов и почти 1,8 млн строк кода.
Код я не читаю. Поэтому между словом агента «готово» и появлением новой версии на сайте стоят автоматические проверки. Их называют «сторожами», сейчас их около двухсот. Если хотя бы один сторож покраснел, новая версия не попадает на сайт, а я получаю в Telegram сообщение «выкат остановлен» со списком красных.
Так я узнаю, готов ли продукт. И несколько раз эти проверки говорили неправду. Ниже пять примеров: что случилось, как мы это заметили и что изменили.
Восемьдесят шесть проверок, которые никто не запускал
1 сентября выяснилось, что в проекте есть 86 проверок, но ни один автоматический процесс их не запускает. Новая версия сразу летела на сервер после отправки кода. Проверки срабатывали только тогда, когда кто‑то вручную вводил команду перед выкладкой.
Я не могу точно сказать, как долго это длилось — история проекта не показывает. Видно лишь, что проверки были написаны и лежали в папке, но сайт ими не защищали.
Теперь перед выкатом прогоняются все проверки, и деплой ждёт их результата. Если хотя бы одна красная, на сайте остаётся прежняя версия. Список проверок собирается автоматически из списка команд проекта, поэтому новую проверку нельзя забыть подключить. Есть правило: проверку нельзя выключать только потому, что она краснеет и мешает. На выключенную проверку продолжают рассчитывать все, кто о ней знает.
Проверка секретов не читала каждый третий файл
(далее идут остальные случаи, в которых проверки давали ложные результаты, как мы их обнаружили и какие поправки внесли) В тот же день шёл аудит перед выкатом: пять независимых разборов, код при этом не меняли. Один из разборов дошёл до проверки, которая ищет в истории утёкшие ключи и пароли. Эта проверка запускается перед каждым выкатом и всегда отвечает «секретов не найдено».
У меня в проекте много файлов с русскими именами — гайды, отчёты, разборы. Git по‑умолчанию выводит такие имена в закодированном виде. Например, файл «гайд.md» в выводе выглядит так:
"\320\263\320\260\320\271\320\264.md"
Проверка брала это имя как есть, получала «файл не найден», глушила ошибку и шла дальше. В итоге 438 из 1413 файлов, в том числе 286 гайдов, так и не проверялись, хотя проверка честно писала «секретов нет».
Мы прогнали пропущенные файлы исправленной проверкой — настоящих ключей там не оказалось. Но всё это время над третьей частью непрочитанных файлов стояла зелёная галочка.
Починка заняла две строки. Код писали агенты, показываю его как есть:
git -c core.quotePath=false … -z
while IFS= read -r -d ''
Первая строка заставляет git отдавать имена файлов без кодирования. Вторая читает список имён, разделённых нулевым байтом, поэтому пробелы или кириллица больше не ломают процесс.
2 сентября нашли класс ошибок в запросах к базе, при котором счётчик тихо показывает неверное число. Никакого сообщения, никакого пустого экрана — просто другая цифра. В нашем коде таких мест не нашли, но проверку на этот класс добавили заранее.
Чтобы убедиться, что проверка работает, ту же ошибку специально вернули в рабочий файл. Проверка молчала. Она приняла служебное слово WHERE, стоявшее на следующей строке, за псевдоним таблицы — за её второе короткое имя — и решила, что всё ок.
Если бы ошибку не подставили нарочно, проверка бы осталась в списке как защита от проблемы, которую не видит. После этого мы ввели правило. Каждую новую проверку в тот же час проверяют подставленной ошибкой. Если проверка никогда не краснела, она ничего не доказывает. С 10 сентября за этим следит отдельная проверка: без такого испытания выкат не пройдёт.
Три ложные тревоги за неделю
21 августа ночью пришло сообщение о двух неразобранных ошибках на сайте, одна из них, как говорили, висела 1072 часа. В рабочей базе в тот момент открытых ошибок не было, а запись такого возраста была невозможна ‑ база была моложе.
Оказалось, кто‑то из команды поднял у себя копию панели с тестовыми ошибками, и копия написала мне, будто это боевой сайт. После похожего случая 18 августа защиту уже ставили, но она искала признаки копии в тексте сообщения, а в тексте их не было.
Теперь панель отправляет сигналы только после того, как убедилась, что это та самая панель, к которой приходят запросы на боевой адрес.
22 августа случился третий раз. Агент проверял отправку уведомлений на своей копии и прислал мне в Telegram настоящее сообщение «Фоновый процесс встал». На сайте в тот момент всё работало.
Из этой недели в проекте осталось правило: ложная тревога хуже молчания. После нескольких ложных красных сигналов на красное перестают смотреть, и настоящая поломка проходит тем же цветом.
Все проверки зелёные, а экран разъехался
Эту историю я видел своими глазами.
В сентябре одна страница сайта три выката подряд приходила ко мне с разъехавшейся вёрсткой. Значки карточек стояли на разной высоте, названия ‑ на трёх разных уровнях, текст прилипал к плашкам, ссылки в подвале съехали. Каждый раз я видел это за секунду.
При этом сборка проходила, проверки кода ошибок не находили, все прогоны были зелёными. Проверки читают текст файлов, а вёрстка появляется только на собранной странице в браузере. Ни одна проверка на собранную страницу не смотрела. После третьего раза, 13 сентября, я добавил правило: агент открывает экран в браузере и проверяет его, прежде чем предлагать выкат. Это касается любой работы, которую можно увидеть глазами. Теперь экран считается сданным только после того, как браузер открыл его и измерил три ширины, в том числе телефонную.
Что изменилось
По датам выглядит так:
21 августа ‑ сигналы о поломках отправляет только рабочая панель;
1 сентября ‑ новая версия не попадает на сайт без проверок;
2 сентября ‑ каждую новую проверку проверяют подставленной ошибкой;
13 сентября ‑ экран открывают в браузере и измеряют.
К этому добавилось правило из моего второго проекта. Там счётчик показывал «1», когда в базе было 23 записи, и все проверки были зелёными. С тех пор раздел, где на экране показываются числа, не считается сданным, пока через него не прошли настоящие данные.
Из этих правил получаются три вопроса со словом «готово». Краснела ли эта проверка хотя бы раз? Открыл ли ты экран сам? Прошли ли через раздел настоящие данные?
Есть и нерешённый случай. Проверка, сравнивающая величину саму с собой, всегда зелёная, и машина по тексту её не отличит. Ловит её только подставленная ошибка, а подставить её должен тот, кто помнит об этом правиле.
KioskNews shows a cleaned-up reading view extracted from the publisher’s page — the original always lives on their site, not ours.