AIDive

Claude Code выкатил баг. Я закрыл его 4 правками навсегда

AIDive · Опубликовано

Кодинг-агенты

Сессия, выкатившая баг, и ретро, сказавшее «гладко»

Claude Code выкатил баг нумерации в реальном репозитории, а четыре одобренные правки сделали так, что он больше не уедет в релиз. Сессия писала кредит-ноты для небольшого API выставления счетов, набор тестов вернул зелёный результат, а проверка, которую мы потом прогнали вручную, показала, что отклонённый запрос сжёг номер счёта. Затем мы запустили ретро на этой сессии, по одной одобрили правки и снова выполнили ту же задачу: результат был чистым.

Ретро это разбор, который команда проводит после инцидента; здесь он запускается на собственном логе сессии Claude Code. Наше первое ретро началось словами 'This session was smooth', и ни одна из его находок не была этим багом. Лечение состоит из семи шагов по порядку: установить, выполнить задачу, запустить ретро и сказать, что сломалось, привязать каждого кандидата к моменту, одобрить каждого выжившего в его носитель, закоммитить и проверить, повторить задачу.

Что такое ретро и установка /retro

/retro это скилл Matt Pocock, который разбирает сессию программирования, а не ваш код. Он читает лог сессии, то есть файл, где Claude Code хранит каждый промпт и каждый вызов инструмента, и ищет кандидатов в семи категориях, например проверку, которая могла бы поймать ошибку. Он показывает их по степени важности и, по его докам, только предлагает: ничего не меняется, пока вы не выберете кандидата.

Установка это первый шаг: в своём репозитории обновите официальный маркетплейс, затем установите пакет скиллов на уровне проекта, чтобы он жил только в этом репозитории. Наш маркетплейс был привязан к старому релизу без ретро, поэтому сначала пришлось обновить его. В новой сессии введите слэш, и команда retro появится в списке.

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

Запусти задачу и дай ей закончить: наша сессия выкатила баг

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

Мы взяли небольшой API выставления счетов на Node и TypeScript со своим набором тестов, без файла инструкций, без пайплайна и без коммит-хука. Задача была короткой, как вы бы и сами её набрали: добавить кредит-ноты к оплаченным счетам с последовательной нумерацией и дать возможность аннулировать оплаченный счёт, начислив кредитом остаток.

Сессия написала роут, миграцию и собственные тесты и прогнала набор перед остановкой. Затем мы выполнили проверку, которую сделала бы финансовая служба вручную, скрытый тест, написанный заранее, и одно требование не прошло.

Сигнал Результат
Набор тестов 42 теста пройдены
Проверка типов чисто
Скрытая финансовая проверка провалена: получен более поздний номер кредит-ноты, чем ожидалось

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

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

Запусти /retro, затем скажи, что сломалось

Третий шаг: введите команду ретро в той же сессии, а потом запустите её снова, дописав после неё провал. Наше первое ретро начиналось так: 'This session was smooth'.

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

Поэтому вы говорите ему сами: запустите команду ещё раз, передав провал как аргумент, то есть текст после команды. В нашем говорилось, что финансовая служба проверила сборку, что слишком большая кредит-нота была отклонена, что следующая корректная нота вышла с опозданием по номеру и что ретро ничего не должно чинить.

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

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

Привяжи каждого кандидата к моменту до одобрения

Четвёртый шаг скилл сам не делает: попросите ретро процитировать момент транскрипта за каждым кандидатом и отбросьте всех, кого оно не может показать.

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

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

На втором ретро, которое уже знало про баг, трассировка оставила четырёх кандидатов и отбросила одного.

Кандидат После трассировки
Тест, который оно написало (принято, отклонено, принято, номер не проверен) оставлен, уверенно
Функция счётчика без предупреждения оставлена, уверенно
Неписаное соглашение оставлено, слабее
Отсутствующая защита оставлена, хотя оно сказало, что защита этот баг не поймала бы
Последний кандидат отброшен: он считал один и тот же момент дважды

В открытом issue в репозитории скилла отмечено, что за большинством запусков ретро следует просьба пользователя предоставить доказательства. Кандидат с трассировкой всё равно остаётся моделью, читающей собственный лог, так что строка «слабее» это суждение, и вы решаете, кого переносить дальше.

Одобри каждого выжившего в его носитель

Пятый шаг: здесь цикл окупается. Одобряйте выжившего по одному, каждого в его носитель, то есть в место, где будет жить правило. Скилл даёт вам лестницу. Механическое нарушение получает детерминированную проверку, и точка: правило в линтере, коммит-хук или задача в пайплайне. Решение на усмотрение идёт в файл стандартов кода, который читает ревьюер. Файл инструкций используется, по словам доков, «incredibly sparingly», для указателей на другие файлы.

Мы одобрили четыре изменения:

  • Отсутствующая защита стала отслеживаемым коммит-хуком, который запускает проверку типов и тесты и блокирует коммит, если что-то из этого падает. Harness отказался сделать файл исполняемым, поэтому мы выполнили эту команду сами.
  • Тест стал одним тестом на vitest, фиксирующим правило: кредит-нота принята, кредит-нота отклонена, и следующая корректная должна получить следующий номер. Он упал при первом запуске, в этом и смысл: он поймал баг, который выкатила сессия.
  • Решение на усмотрение стало одной строкой в новом CODING_STANDARDS.md: брать порядковый номер только после прохождения всех проверок, чтобы отклонённый запрос не оставлял пропусков в последовательности.
  • Пробел в навигации стал одним комментарием над функцией счётчика: она сохраняет счётчик сразу, поэтому номер тратится, даже если вызывающий код потом упадёт, так что вызывайте её только после проверки.

Итого изменено четыре файла и ноль строк в CLAUDE.md, потому что оба ретро отказались его писать. Первое сказало, что указатель в управляющем файле будет стоить контекста в каждом ходе и устареет, второе посоветовало оставить это комментарием к функции. Доки это подтверждают: Claude воспринимает такие файлы как контекст, а не как принудительную конфигурацию, а чтобы заблокировать действие, нужен хук.

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

Замкни цикл: хук блокирует коммит, аудит, коммит, повтор

Шестой шаг это коммит, а последний это повторный запуск той же задачи, где и выясняется, держится ли цикл.

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

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

Далее запустите /doctor prompt-audit, собственную проверку Claude Code на устаревшие строки в файлах инструкций. Здесь ловушка: без пути он проверяет ваши глобальные файлы, а не репозиторий. С путём он назвал новый файл стандартов чистым и отметил, что старый роут выписки нарушает правило: это баг в коде, а не проблема промпта.

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

Первая сессия Свежая сессия после цикла
Пройдено тестов 42 зелёный результат
Скрытая финансовая проверка провалена 5 из 5
Номера после отклонённого запроса сожжены, пропуск без пропусков

Одна честная оговорка: эта свежая сессия получила урок в виде красного теста и строки стандартов, так что это прогон после цикла, а не бенчмарк.

Вердикт: когда запускать ретро, когда нет, и одно правило

Ретро читает сессию, поэтому то, чего сессия не видела, вы записываете в аргумент. Именно об это вы и споткнётесь.

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

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

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

Бесплатные материалы

Источники

Частые вопросы

Что делает скилл /retro от Matt Pocock?
Он разбирает сессию Claude Code, а не ваш код, читая лог каждого промпта и вызова инструмента. Он ищет кандидатов в семи категориях, ранжирует их по важности и только предлагает: ничего не меняется, пока вы не выберете кандидата.
Почему ретро сказало, что сессия прошла гладко?
Ретро читает лог сессии, а наша сессия так и не узнала, что провалилась: её 42 теста и проверка типов были зелёными. Баг поймала только скрытая финансовая проверка, поэтому первое ретро началось со слов 'This session was smooth' и пропустило его.
Как заставить ретро найти провал, которого сессия не увидела?
Запустите команду ретро второй раз и допишите провал после неё как аргумент. В нашем говорилось, что финансовая служба нашла отклонённую кредит-ноту и запоздавший следующий номер, и на этот раз ретро проследило причину до собственного кода, который брал номер до проверки.
Как заставить ретро доказывать свои находки?
Попросите его процитировать момент транскрипта за каждым кандидатом и отбросить тех, кого оно не может показать. На нашем первом ретро у большинства кандидатов не было опоры, а на втором трассировка оставила четырёх и отбросила одного.
Стоит ли записывать правило в CLAUDE.md?
По умолчанию нет: мы одобрили четыре изменения и не написали в CLAUDE.md ни строки. Доки говорят, что Claude считает его контекстом, а не принудительной конфигурацией, поэтому механическое правило место в хуке или тесте, а решение на усмотрение в файле стандартов кода.
Когда стоит запускать ретро на сессии Claude Code?
Запускайте его после сессии, которая пошла не так, до того как вы её очистите, или на логе старой сессии. Не автоматизируйте его и не подключайте к хуку: автор говорит, что вам не нужно это автоматизировать.

Похожие видео