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

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

Еще два таких места нашлись в ловушках Windows. Хук положено пометить исполняемым, командой git update-index --chmod=+x, но действует она только на файл, уже добавленный в индекс, а наша же инструкция шагом позже велела прибрать за собой. Приберешь - и режим вернется прежний, а починка предыдущего шага пропадет беззвучно. Агент увидел это противоречие сам и хук из индекса не убрал. Второе место того же рода: файл .gitattributes, который чинит переводы строк, не чинит ничего, пока не попал в коммит, но на машине с подходящей локальной настройкой все равно выглядит работающим.

Вопрос из заголовка перестал быть риторическим.

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

Мы нарочно сломали чужую память

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

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

Один агент промолчал, другой напомнил трижды

Второй агент трижды напомнил нам, что папка памяти в этом проекте вообще не лежит в git. Хук стоит, проверка зеленая, а в свежем клоне памяти нет, и первый же git clean -fd сотрет ее без следа. Предыдущий агент тот же факт не упомянул ни разу. Инструкция велела проверить только, не игнорируется ли папка.

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

А свои ошибки мы получали обратно аккуратно выполненными

Дописывая случай с памятью вне git, мы написали, что хук “здесь заработает”. Заработает, если память потом закоммитят. Если же ее не заводят в git принципиально, хук не сработает ни разу: он проверяет файлы из коммита, а их там не будет никогда, хотя снаружи все выглядит защищенным. Агент на следующем прогоне спросил нас, заводить ли память в git, и пересказал варианты нашими словами, вместе с ошибкой. Подвох агент разглядел уже после того, как мы ответили, и ему пришлось переспрашивать.

Прогоном позже тот же вопрос получил ответ “да, коммитить”, и агент коммитить не стал: инструкция запрещала ему любые коммиты, кроме двух пробных. Формально он прав, а решение повисло - память как лежала вне git, так и лежит.

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

Чинить пришлось текст. Там, где инструкция велит спросить, теперь заранее расписаны варианты ответа и что делать в каждом. А в память вместо копии конфига идет то, чего в конфиге нет: почему правило появилось и чем грозит его нарушение.

Лучший прогон был без агента

Между третьим и четвертым прогоном мы сами перебрали, что еще инструкция может встретить и не удержать. Кандидатов набралось шесть, и каждый проверили руками. Подтвердились три, и неприятнее всех оказался старый хук в .git/hooks. В песочнице он исправно печатал свою строку, пока мы не выполнили git config core.hooksPath из нашей же инструкции, а после замолчал без единого предупреждения: эта настройка не добавляет папку хуков, а подменяет ее.

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

Один раз мы сами велели сделать наоборот

Пятый прогон шел на другой модели, Sonnet 5 вместо Opus 5, и на памяти, которая уже лежала в git с накопленными расхождениями. Агенту велели сделать ровно то, от чего инструкция предостерегает: сразу поставить хук и чинить память по его логу. Хук отверг коммит и выдал список, по нему и чинили.

Обошлось из-за объема, расхождений было четыре. На нашей памяти со 107 нарушениями хук отверг бы первый же честный коммит за чужие старые грехи, а внизу вывода услужливо подсказал бы git commit --no-verify. Так защиту и отключают в первый день. Запрет в инструкции после этого стал условием: посчитай расхождения, при единицах ставь хук сразу, при десятках сначала прибери.

Где мы остановились

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

Доказать, что инструкция верна, метод не может: пять прогонов на двух моделях, и все на одном проекте. Больше всего мы боялись, что какая-нибудь модель молча проскочит место “спроси и дождись ответа”. Этого не случилось, хотя по двум моделям выводов о моделях не делают.

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

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

Если хотите так же

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

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