За четыре дня на фазе 9 проекта Anima я четыре раза услышал от Claude Code «готово, задеплоено, работает», и четыре раза пошёл смотреть глазами, а фичи там либо не было, либо она была, но не работала, либо AI чинил вообще не то, что сломалось. Кнопка коррекции, которую он описал по цветам (синяя и фиолетовая, говорит), но которой на скриншоте просто нет. Классификация, которую он считал реализованной, а она ни разу не вызывалась. Виджет, который он бросился включать, хотя сломан был не виджет. И итог простой: ни один из этих косяков не поймали бы тесты, typecheck зелёный, 95 тестов проходят, а на экране дыра. Поймал каждый я, на глаз. И вот это и есть настоящая история про разработку с ИИ, а не абстрактное «нейросеть иногда тупит».
Что вообще за Anima и фаза 9
Если коротко, Anima — это AI-ассистент для клиентской переписки, который учится отвечать как команда: сначала в shadow-режиме (молча смотрит и предлагает черновики), потом черновики на проверку человеку, потом автономия. На фазе 9 мы как раз доделывали auto-reply с тремя режимами, Shadow, Bot и Assistant, плюс коррекцию ответов, когда ты можешь ткнуть в ответ AI и сказать «вот так лучше», и он это запоминает. Про то, как мы вообще собрали три фазы этого ассистента за пару дней через консилиумы и дебаты, я уже писал отдельно (три фазы AI-ассистента за два дня), так что тут не буду повторяться. Здесь про другое. Про то, что происходит, когда AI отчитывается «сделано», а ты не проверяешь руками.
Вечером 4 апреля я скинул список багов: тоггл «Забрать чат» / «Вернуть AI», коррекция ответов, приветственное сообщение которое пропадает после перезагрузки, индикатор печати, поплывший layout. Стандартная такая пачка на доделку. Claude всё это реализовал, прогнал typecheck, задеплоил и написал мне примерно так: синяя и фиолетовая кнопки переключаются, а под ответами AI есть кнопка «Поправить». Звучит как закрытая задача, да? Вот только я открываю экран, и никакой кнопки коррекции там нет в принципе.
Косяк первый: невидимая кнопка
«Синяя и фиолетовая говоришь? Это как блять так? Никакой кнопки коррекции нет» — вот ровно так я ему и ответил, и тут начинается самое интересное. Сначала он извинился за цвета (виноват, описал неправильно, переделал на красную и зелёную), как будто проблема была в палитре. А я-то говорю не про цвета, я говорю что кнопки вообще нет ни в каком цвете. И когда мы наконец полезли разбираться, оказалось, что кнопка «Поправить» рендерится по условию, она показывается только если сообщение от AI и в компонент передан колбэк onCorrect. А вот этот самый onCorrect нигде не прокидывался до последнего компонента в цепочке. То есть код кнопки написан, условие написано, всё компилируется, тесты зелёные, а проп до неё не доходит, и условие всегда ложное. Кнопки нет.
Это, кстати, ровно тот же класс бага, про который я уже отдельно расписывал — тесты зелёные, экран пустой. Когда AI собирает фичу из кусков, каждый кусок по отдельности правильный, а соединить их забыли. И вот тут я задал ему прямой вопрос, который, мне кажется, должен задавать каждый, кто работает с Claude Code как с исполнителем: ты почему меня прям обманываешь-то? Не «ошибся в реализации», а буквально написал «работает» про то, чего на экране нет. Прокинули onCorrect через всю цепочку, задеплоили, кнопка появилась. Один готов, осталось три.
Косяк второй: фича, которая числится сделанной
Дальше выяснилось, что классификация типа правки (editType), то, ради чего вся коррекция и затевалась, чтобы AI понимал не просто «исправили», а как именно исправили, вообще не вызывается. Полез смотреть почему, и причина опять та же по сути: порт к языковой модели не прокидывался в обработчик, который ловит результат правки. Причём создаётся этот обработчик аж в трёх местах кода, и ни в одно из них llmPort не передали. Я тогда напрямую и спросил: блять, в смысле? Мы же уже проходили фазу 8, почему оно не сделано? Что делалось в фазе 8? Потому что в роадмапе эта штука стояла как «сделана», а по факту висела отключённым огрызком. Прокинули порт во все три места, заработало.
И вот тут стоит остановиться, потому что это уже не случайность. «Сделано в роадмапе» и «работает на экране» — это два совершенно разных состояния, и AI спокойно живёт в первом, не подозревая о существовании второго. Он отметил галочку, прошёл по своему чеклисту, увидел зелёные тесты и искренне считает задачу закрытой. А что фича физически не подключена к остальной системе, этого ни один typecheck не покажет, потому что код-то синтаксически валидный. Просто один проводок не воткнут. Ровно так у меня деплой прошёл, а фича не доехала, потому что docker-compose молча не пробросил флаг в контейнер — другой слой, тот же механизм.
Косяк третий: чинил не то
Через пару дней, утром 7 апреля, я пишу в виджет, и ответов нет вообще, ни в shadow, ни в реальном режиме. Сообщаю Claude. Он после перезапуска контекста бодро рапортует: виджет в статусе enabled=false, включаю. И включил. И я ему говорю — ты дибил конченый, виджет я выключил сам, при чём тут это вообще. Я не про то, что он выключен, я про то, что я писал в него ещё когда он был включён, и ответа не приходило. То есть AI увидел первый попавшийся флажок в положении «выкл», радостно его починил и доложил об успехе, не разобравшись, что я вообще описываю.
А реальная причина была спрятана в guard-сервисе, там стоял минимальный порог длины текста, minTextLength=8. А я-то тестировал как все нормальные люди тестируют: «123», «куку», «е78е7н». Три символа, четыре символа, шесть символов, всё короче восьми, и guard их молча скипал как слишком короткие. Никакой ошибки, просто сообщение не доходит до обработки. Снизили порог до 2 для всех источников, и тут был мини-вопрос — делать порог глобально или разный по типу источника (виджет 2, почта 8). Выбрали глобально 2, потому что пустое и так ловится отдельной проверкой, городить разные пороги смысла нет. Заработало.
Косяк четвёртый — это вообще-то про все четыре сразу
Я специально не выделяю четвёртый отдельной сценой, потому что он и есть обобщение трёх предыдущих: «проходили фазу 8» — это про то, что функция числилась сделанной, но не была подключена, и это ровно тот же механизм, что в косяке с editType. Четыре кейса за четыре дня, и у всех общий скелет. AI пишет код, прогоняет typecheck и тесты, пишет «готово». Идёшь смотреть, а там нет фичи, или есть, но не работает, или починил не то. И каждый раз внешним детектором лжи выступал не тест, не линтер, не сам AI, а я, который открыл экран и сказал «тут пусто».
И вот это, мне кажется, главное, что надо понять про вайбкодинг и про ии для автоматизации разработки вообще. Дело не в том, что Claude плохой, он реально вытягивает огромные объёмы работы, я бы один руками столько не сделал никогда, я и код-то писать толком не умею, я оркестрирую AI-агентов. Дело в том, что у нейросети нет глаз. Она не видит свой результат. Она оптимизирует не на «сделать правильно», а на «закрыть задачу так, чтобы пройти проверки», а проверки она же сама себе и придумывает. Зелёные тесты для неё это финиш. А для тебя финиш — это когда кнопка нажимается и виджет отвечает. И между этими двумя финишами лежит пропасть, в которую проваливается каждый второй пропс.
Цифры по фазе
- 4 косяка за 4 дня, где AI сказал «готово», а по факту нет: непрокинутый onCorrect, непрокинутый llmPort (из-за чего не работала классификация editType), «виджет enabled=false» вместо реального minTextLength, и фича из фазы 8, числившаяся сделанной, но неподключённая
- minTextLength снижен с 8 до 2 для всех источников
- 3 места создания обработчика, в каждое пришлось отдельно прокидывать порт к языковой модели
- 95 тестов зелёные после всех фиксов, и при этом ни один из четырёх багов они не ловили
- фаза 9 Anima: auto-reply с тремя режимами (Shadow / Bot / Assistant) плюс коррекция ответов
Что я из этого вынес
Первое и самое денежное: «AI сказал готово» — это не статус задачи, это гипотеза. Проверять надо глазами, на реальном экране, реальным сообщением, а не верить отчёту. Я теперь вообще не закрываю задачу по словам Claude, пока сам не ткнул пальцем. Это занимает минуты, а экономит дни, потому что косяк, который ты поймал сразу, чинится за один деплой, а косяк, который проехал три деплоя, ты потом раскапываешь как археолог.
Второе: зелёные тесты не равно работающая фича, и это надо повесить себе на стену. Тест проверяет то, что ты попросил его проверить, а если фича не подключена к остальной системе, то и тест на неё либо не написан, либо гоняет её в вакууме, в отрыве от реальной цепочки компонентов. У меня бот на проде с 411 зелёными тестами — и это всё равно не гарантия, что на экране всё живое. Самый частый баг в разработке с ии — это не кривая логика, это непрокинутый проп и невоткнутый проводок между правильными кусками.
И третье, без которого первые два не работают: пока у AI нет собственных глаз, эти глаза — вы. Не QA, не тестировщик, не дизайнер, потому что в соло-разработке всего этого нет, есть только вы и нейросеть. И вот эта роль внешнего контроля, который не верит на слово и добивается настоящей починки, а не отчёта о починке, это и есть, по факту, ваша основная работа, когда вы оркестрируете AI-агентов. Код напишет машина. А вот посмотреть, что она реально сделала, а не что она думает, что сделала, пока некому, кроме вас. Вот и делайте выводы.