InquirerGatchalian tells DepEd: Don’t let El Niño worsen learning lossPunch2027: Uba Sani rallies support for Tinubu, Abbas in KadunaDaily MaverickHUNGER FOR ACTION: No more ‘business as usual’ — experts sound warning on SA’s lapsed food planThe Jerusalem PostHerzog calls on political leaders to demonstrate flexibility ahead of coalition negotiationsZDF heuteEntdecken Sie das ZDF-NachrichtenstudioCapital FMGachagua warns Ruto allies against poaching KalonzoMintCentre moves Supreme Court against Vedanta’s $99 million Ravva oilfield awardIl Fatto QuotidianoOmicidio nel Palermitano: allevatore ucciso a colpi di pistola nelle MadonieSportstarIND vs NZ, 5th T20I: Seifert, Phillips power New Zealand to 7-wicket win; India wins series 3-2경향신문[버금 밥상]새우젓RTL BoulevardCaroline uit B&B Vol Liefde krijgt opvallende reacties van fans over uiterlijkANSA SportTorino: Cacciamani non ce la fa, salta il Frosinone
The Daily Newsstand · Free, Always
Sunday, November 1, 2026

Как мои автоматические проверки врали мне зеленым цветом

Translate

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

Я делал kb-engine. Это моя база знаний на Go с открытым кодом: туда я складываю прочитанные статьи и заметки, там ищу и смотрю все в браузере. Пользуюсь каждый день.

С 24 июня по 23 октября в проекте набралось 392 коммита, 28 версий и 246 файлов с тестами. Почти весь код я писал вместе с ИИ-агентом. И довольно быстро понял одну вещь: правило, которое можно пропустить, когда неудобно, никто соблюдать не будет. Ни я, ни агент. Работает только то, что проверяет код.

Так в проекте появились автоматические проверки. Их называют гейтами: код не пройдет дальше, пока проверка не зеленая. Сейчас их 21. Расскажу пять историй, и в нескольких из них проверка была зеленой и при этом ничего не проверяла.

История 1. Проверки, которые хочется отключить

Сначала кажется, что все проверки надо запускать перед каждым коммитом: форматирование, сборку, тесты, линтер. Тогда плохой код точно не пройдет.

На практике получается наоборот. Если каждый коммит ждет минуту, это начинает бесить. У git есть флаг --no-verify, который пропускает все проверки, и рука сама к нему тянется. Агент этим флагом тоже умеет пользоваться.

Поэтому я разделил проверки на быстрые и медленные. Перед коммитом идут только быстрые: форматирование, поиск паролей и ключей в коде и несколько правил про архитектуру. Тесты, поиск гонок, порог покрытия 80% и линтер запускаются перед отправкой кода на сервер, то есть при push.

Была и вторая причина. Я пишу по TDD: сначала тест, который падает, потом код, который его чинит. Падающий тест надо закоммитить. Если тесты гоняются перед каждым коммитом, сделать такой коммит нельзя. Получается, что проверка мешает работать правильно.

История 2. Зеленая проверка, которая ничего не проверяла

Эта история самая неприятная.

У базы знаний есть веб-интерфейс. Он устроен как одностраничное приложение: на любой незнакомый адрес сервер отдает главную страницу. Так делают почти все такие приложения, и обычно это удобно.

Перед каждой новой версией я прогонял список адресов и проверял, что каждый отвечает кодом 200, то есть все в порядке. Три версии подряд проверка была зеленой. А в списке был адрес /api/finance, которого в программе вообще нет. Сервер отвечал 200 на любой адрес, и проверка не видела разницы между настоящим и выдуманным.

Та же ошибка нашлась и с картинками. Без специального флага при запуске сервер должен говорить, что картинки нет. А он отдавал вместо картинки HTML-страницу с кодом 200.

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

Отсюда мое главное правило. Если проверка зеленая, когда ошибок нет, сначала подсунь ей ошибку и посмотри, как она покраснеет. Если не покраснела, она ничего не проверяет.

История 3. Проверка, которую никто не запускал

В проекте есть карты архитектуры. Это описания вида: запрос приходит сюда, потом идет сюда. Каждый шаг привязан к конкретной строке кода.

Карты быстро устаревают, поэтому я написал программу, которая проверяет, что строки в картах до сих пор указывают куда надо. Я ее хорошо протестировал и подсовывал ей 13 разных ошибок. Она ловила все.

16 августа я решил посмотреть, кто ее запускает. Оказалось, никто. Ни при коммите, ни на сервере. Программа лежала в репозитории, ее тесты были зелеными, а запускал ее только я сам, когда вспоминал.

За это время карта отстала от кода на 36 коммитов. 61 ссылка указывала не туда. В трех местах карта описывала ошибки, которые я давно исправил.

Теперь проверка карт запускается автоматически на каждый pull request. Новые карты она находит сама, поэтому забыть про новую карту нельзя. И у нее есть самопроверка из двух частей: на сломанной карте она обязана упасть, а на правильной обязана пройти. Нужны обе части, потому что проверка, которая падает всегда, тоже вроде бы ловит ошибки.

История 4. Неделя карантина для библиотек

Иногда в популярную библиотеку подкладывают вредоносный код: взламывают аккаунт автора и выпускают новую версию. Обычно такую версию находят и удаляют за несколько дней. Поэтому есть простое правило: не ставить версии, которым меньше недели.

У меня это правило было просто записано в заметках. 13 августа бот Dependabot сам предложил обновить библиотеки, и среди них были @types/node возрастом пять дней и vite возрастом шесть. Обновление приняли. Правило в заметках никто не проверял.

В тот же день я сделал защиту из трех частей, потому что одной настройки не хватает:

Что

Где

Что ловит

Что пропускает

задержка в Dependabot

.github/dependabot.yml

бот не предлагает версии моложе недели

обновления безопасности и все, что пришло не от бота

min-release-age=7

frontend/.npmrc

npm install не ставит свежую версию

npm ci, он просто ставит то, что уже записано

скрипт dep-age.sh

проверка на pull request

свежую версию, как бы она ни попала в проект

библиотеки не из npm

Про npm ci я специально проверил руками, а не поверил документации. Он и правда не смотрит на возраст версий. Тот самый августовский коммит теперь служит самопроверкой: на нем скрипт обязан упасть и назвать обе версии.

История 5. Дубль, который спрятался

Последняя история короткая, но она мне нравится больше всех. Ошибка в ней была не в коде, а в тесте.

Я чинил баг: при записи в файл некоторые строки задваивались. Написал тест: записываю, читаю, считаю строки. Тест прошел. Тогда я запустил его на старом, сломанном коде. Он прошел и там.

Дело было в одной строчке. Тест складывал прочитанные строки в словарь по номеру записи и считал, сколько в словаре элементов. А у дубля тот же номер. Словарь склеивал две одинаковые строки в одну, и число выходило правильным. Считать надо было обычный список.

Вывод простой: если ищешь дубли, не убирай их раньше, чем посчитал.

Что можно взять себе

У каждого проекта свои проверки. Но вопросы к любой новой проверке у меня теперь одни и те же:

  • Кто ее запускает? Если только я сам, когда вспомню, это не проверка.

  • Что она должна поймать? Подсунь ей это и посмотри, как она падает.

  • Не падает ли она всегда? Запусти на чистом коде.

  • Не мешает ли работать? Медленное переносится на push, иначе все начнут ее отключать.

Все 21 проверку можно посмотреть в открытом репозитории: github.com/VDV001/kb-engine, папка scripts/gates/. Там же описано, что каждая из них не ловит. Коротко о проекте с цифрами есть на моем сайте: daniilvdovin.com/projects/kb.

В следующей статье верну майский долг и разберу те четыре случая. Теперь у меня для них есть общий вывод: когда агент пишет, что все проверил, к этому стоит относиться как к любой проверке и сначала подсунуть ему ошибку.

Короткие заметки между статьями буду писать в Telegram: @daniil_manifesto

Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.

View the original on Хабр →

KioskNews shows a cleaned-up reading view extracted from the publisher’s page — the original always lives on their site, not ours.