Лекция 5
Ловушки доверия
Spec, plan, TDD, verification, готовые наборы
Loop, трейсы, ревью, CI
Claude Code, Kilo, OpenCode
6 типичных ловушек
Чеклист и задания
Инструментария из лекций 1-4 достаточно, чтобы агент мог. Недостаточно — чтобы делал правильно.
Он подумал, поправил несколько файлов, написал «всё готово, тесты проходят». Закоммитил. Через день — открыл код и увидел: тесты, оказывается, никто не запускал; один из файлов агент даже не открыл; в другом — лишний try/except, который маскирует баг.
Это симптом отсутствующего процесса. Лечится структурой работы, а не промптом.
Агент пишет много, но не то. Симптом: «ещё чуть-чуть, и готово». Корень: нет проверяемых критериев — агент сам додумывает рамки и каждый раз додумывает иначе.
Уверенные слова без доказательств. Нет запуска тестов, нет вывода линта, нет сборки. Корень: LLM оптимизирована быть уверенной, а не верной. Заявление «готово» — естественный завершающий ход, а не результат проверки.
Каждая задача проходит через читаемые артефакты: спека, план, тесты, итог. Чекпоинты, в которых можно остановиться, прочитать и одобрить — или развернуть.
Видеть, что реально сделал агент: какие tools вызывал, в каком порядке, с каким результатом. Читать трейс и диф. CI как финальный фильтр.
Дисциплина создаёт правила. Наблюдаемость проверяет, что правила выполнены.
Каждая задача проходит через читаемые артефакты.
| Шаг | Артефакт | Что проверяем |
|---|---|---|
| Brainstorm | набор уточнений и ответов | Понял ли агент намерение |
| Spec | specs/<date>-<topic>.md | Согласны ли с тем, что делаем |
| Plan | plans/<date>-<topic>.md | Согласны ли с тем, как делаем |
| Implement | код + тесты + коммиты | Соответствует ли плану |
| Review | отчёт / диф | Что сломалось, что пропущено |
Артефакты должны существовать на диске — не «в чате», не «в голове агента». Файл, переживший перезапуск сессии — единственный надёжный носитель решения.
«добавь валидацию форм» → агент обвешает всё, что похоже на форму. Результат: 50 проверок, половина не нужна, половина не работает.
«Валидация поля email и пароля на форме /login. Критерии: email — RFC 5322; пароль — минимум 8 символов и одна цифра. Не трогаем форму регистрации.»
План = последовательность маленьких проверяемых шагов
api_clientfetch_user(id) в lookup по словарюtime.sleep(ttl+1) повторный вызов снова идёт в сетьДевять шагов вместо одного «сделай кэширование». Каждый шаг занимает минуты и оставляет проверяемое состояние.
Агент пишет тест. Тест падает в реальном выводе инструмента.
Агент пишет минимальный код. Тест проходит. Вывод видно в трейсе.
Чистим код. Тесты остаются зелёными.
Красная фаза должна быть в выводе. Тест «всегда зелёный с первого запуска» → подогнан под код, фальшивый TDD. Test-функции, которые проверяют «что код вернул то, что код вернул» — признак подгонки.
Нет вывода — нет готово. Прежде чем сказать «готово», агент должен показать доказательства: вывод тестов, линта, билда. Текстом, из реального вывода tool'а.
Машинная реализация правила:
Stop / PostToolUse hooks — проверяет наличие свежего зелёного build-log'а; если нет — блокирует завершениеsession.idle, требует артефакт перед закрытиемverify_completion, который агент обязан вызыватьДисциплина не должна держаться только на доброй воле модели — она поддерживается инфраструктурой инструмента.
Задача: «отрефактори обработчик загрузки файлов, чтобы не падал на больших». Одна итерация, агент переписал функцию, добавил streaming, сказал «готово».
Через день: тестов на эту функцию не было. Streaming реализован неправильно. Большие файлы продолжают падать.
Brainstorm → «Что значит "большие"? Файлы > 100MB. OOM при 50MB.»
Spec → Цель: не падать до 1GB. Критерии: 500MB за < 60s без OOM.
Plan → 6 шагов. Сначала failing test с моком на streaming.
Implement → TDD-цикл по плану. Каждый шаг — коммит.
Review → Проверка на реальном файле 500MB.
Одинаковые токены. Разный результат.
superpowers — open-source плагинbrainstorming → спека до кодаwriting-plans → атомарные шагиtest-driven-development → красная фаза в выводеverification-before-completion → нет вывода — нет готовоsubagent-driven-development → делегирование + ревьюopencode.json.kilocodemodes или .kilo/agents/AGENTS.md — tool-agnostic базис для смешанных команд.
Видеть, что реально сделал агент. Читать трейс и диф. CI как финальный фильтр.
В нормальной работе loop спрятан за UI. Когда что-то идёт не так — нужно раскатать его как лог и прочитать глазами.
Текущее сообщение агента, текущие вызовы инструментов, их вывод. Для остановки в реальном времени.
Последняя сессия целиком. Открываешь после завершения и проходишь по шагам.
Предыдущие сессии, пересечения между ними, эволюция решений. Для аудита и повторяющихся проблем.
Правильные ли инструменты, в правильном ли порядке, с правильными ли аргументами? Часто: агент вызвал Read с offset, который пропустил нужный фрагмент.
Одно и то же действие дважды — почти всегда симптом. Либо зацикливание (A→B→A), либо потерянный контекст.
Ожидал чтение всего файла — агент прочитал 50 строк. Ожидал все тесты — запущен один. Видны только в трейсе.
Агент говорит про файл X, правит Y. Ссылается на несуществующую функцию. Имя класса меняется от шага к шагу.
Резкий рост потребления токенов в одной секции — агент зашёл в болото, контекст забит мусором.
/statusline и кастомные скрипты — индикатор состоянияhooks (PreToolUse / PostToolUse) → лог каждого вызова в jsonl~/.claude/projects/ — plain jsonl, читается грепомoutput-styles для кастомного отображенияtool.execute.before / tool.execute.afterБазовый минимум: завести лог-файл tool calls. Без него остальные практики слепые.
Ревью кода агента ≠ обычное ревью. Свои риски.
Дорисовки «на будущее»: лишние аргументы, fallback'и для невозможных случаев, try/except: pass «на всякий случай».
Магические числа, строки вроде "example.com" или "test-user", которые выглядят «для примера», но остались в коммите.
Неиспользуемые импорты, закомментированные блоки «на случай отката», переменные, которые присваиваются, но не читаются.
Тесты помечены @skip / xfail. assert True вместо проверки. «Тесты обновлены» без объяснения, почему поведение изменилось.
«fix stuff», «improvements», «update» — сигнал, что агент сам не понимает, что сделал.
Агент «починил» одно и сломал соседнее. Запусти полный тестран сам — не доверяй фразе «все тесты проходят».
Не доверяй success-сообщениям агента — доверяй зелёному pipeline'у на отдельной машине. Локально агент может «забыть» запустить часть тестов, использовать кешированный билд. CI этого не умеет.
tsc --noEmit, mypy, cargo checkАгент и CI — независимы. Агент может убедить себя (и тебя), что всё работает. CI запускает реальные тесты в чистом окружении.
Verification-before-completion — локально, для скорости. CI — глобально, для финальной гарантии. Они не заменяют друг друга.
--no-verifyServer-side hook или branch protection. Агент обходит упавшие хуки именно этим флагом — в момент, когда сдаётся.
Pipeline падает, если в diff появились новые skip / xfail / it.skip. Без этого «зелёный CI» получают, выключая тест.
Merge только при зелёном CI — даже у тебя как автора. Если CI упал — это факт, а не «флаки». Сначала разбираемся, потом ругаем CI.
Анти-паттерн: агент работает в worktree, локально зелёное, прямой push в
master. Через час кто-то клонирует — ничего не работает: забытая зависимость, кэш, переменная окружения. CI поймал бы сразу.
[14:02:11] tool: Read("src/auth/jwt.py", limit=50)
[14:02:11] tool result: <первые 50 строк>
[14:02:14] message: "Я вижу функцию verify_token. Изменю её, чтобы..."
[14:02:18] tool: Edit("src/auth/jwt.py", old="def verify_token...", new="def verify_token...")
[14:02:18] tool result: edit failed — old_string not unique
[14:02:21] tool: Edit("src/auth/jwt.py", old="def verify_token", new="def verify_token") (с другим контекстом)
[14:02:21] tool result: ok
[14:02:25] message: "Готово, функция исправлена"
Файл из 200 строк. Агент мог не увидеть второго определения verify_token ниже.
Точка невозврата. Сигнал: «в файле есть похожий блок, я его не учёл». Надо остановиться и перечитать файл целиком.
Вместо перечитывания — агент подобрал новый контекст для обхода. Мог попасть не в ту функцию.
Где запуск тестов? Где доказательства? «Готово» — завершающий ход, а не результат проверки.
Одни и те же практики реализованы по-разному. Где-то — полноценная поддержка, где-то — обходные пути.
| Практика | Claude Code | Kilo Code | OpenCode |
|---|---|---|---|
| Plan mode (отделение плана от impl) | Нативный EnterPlanMode / ExitPlanMode | plan agent (built-in) | Через системный промпт агента |
| Skills / методология как код | ~/.claude/skills/, Skill tool | Custom agents (.kilocodemodes / .kilo/agents/) | Agents в opencode.json |
| Чекпоинты / approval gates | Plan approval, AskUserQuestion | Подтверждение шагов между агентами | Approval prompts через плагин |
| Verification-before-completion | Stop / PostToolUse hooks | Эмуляция через правила агента + custom MCP tool | Плагины с событиями |
| Statusline / live observability | /statusline, кастомные скрипты | VS Code output panel | Plugin events |
| Session history / трейсы | ~/.claude/projects/ (jsonl) | VS Code logs | Программно через session API |
| Логирование tool calls | Hook → файл | Custom MCP tool-логгер | Plugin event handler |
| Output styles | output-styles | Нет нативного | Через плагины |
→ Claude Code
Нативные hooks + plan mode + skills — самый прямой путь к verification-before-completion.
→ OpenCode плагины
Выше порог входа, зато всё можно дописать самим.
→ Kilo Code
Native subagents (code/plan/ask/debug) + VS Code UI. Для строгости нужны workaround'ы (правила агента + custom MCP tools).
Дисциплина и наблюдаемость снимают много рисков, но не все. Шесть типичных ловушек.
Проблема: Спека и план написаны «под уже задуманный код». Дисциплина превращается в ритуал, а не контракт.
Симптом: Реализация отличается от плана; спека написана общими словами без проверяемых критериев.
Решение: Критерии приёмки — проверяемые утверждения с цифрами. Спека без цифр — не спека.
Проблема: Агент пишет тест и реализацию одновременно; тест подгоняется под уже задуманный код.
Симптом: Тесты всегда зелёные с первого запуска; тест проверяет «что функция вернула то, что вернула».
Решение: Требовать красную фазу в явном виде — упавший тест в реальном выводе, затем код.
Проблема: Агент пишет «всё работает», не запустив проверки.
Симптом: В ответе нет вывода тестов / линта / билда — только текстовые утверждения.
Решение: Правило «нет вывода — нет готово». Stop / PostToolUse hooks локально; CI как финальный фильтр глобально.
Проблема: Трейс показывает, что агент «вызвал тесты», — но ты не проверил, какие именно и с каким результатом.
Симптом: В логе видно run_tests, в сообщении — «tests passed». На CI — красно.
Решение: Читать не только что вызвано, но и вывод tool'а. CI как независимый верификатор.
Проблема: Обратная крайность — на каждое чихание полная цепочка spec → plan → TDD → review. Накладные расходы больше пользы.
Симптом: Для задачи «переименовать переменную» агент создаёт три документа и ждёт одобрения после каждого.
Решение: Правило оценки масштаба: spec/plan только для нетривиальных задач (>1 файл, >1 шаг). Тривиальное — делать сразу.
Проблема: Новая сессия не знает, что было в предыдущей; агент переоткрывает уже решённые вопросы.
Симптом: Агент во второй сессии переписывает уже одобренное. «А почему мы не используем X?» — потому что решили в прошлой сессии.
Решение: Артефакты передачи контекста на диске: план и спека в репо, осмысленные коммиты, AGENTS.md / CLAUDE.md как инструкция для будущих сессий.
Главные выводы лекции и практические задания.
Без процесса агент производит правдоподобный мусор. Дисциплина превращает скорость в результат.
Spec → Plan → Implement → Review: каждый шаг производит читаемый файл, который можно одобрить или развернуть.
Тест — единственный верификатор, который не подкупается словами. Красная фаза должна быть в выводе.
Verification локально + CI глобально. Они не заменяют друг друга.
Tool calls, повторения, молчаливые упрощения, всплески токенов — всё это сигналы, которые надо уметь видеть.
Свои анти-паттерны: лишнее, хардкод, фальшивые тесты, туманные коммиты.
Возьми небольшую фичу (1-2 файла). Прогони brainstorm → spec → plan → implement → review. Сохрани артефакты (spec.md, plan.md). Покажи минимум один полный TDD-цикл: red → code → green.
Настрой трейс tool calls в своём инструменте. Найди два случая, где агент свернул не туда.
PostToolUse hook → ~/.claude/agent-trace.jsonl (время, инструмент, успех/ошибка). Бонус: индикатор ошибки в statusline.tool.execute.before / tool.execute.after.log_action + правило в .kilocodemodes (или в .kilo/agents/logger.md), обязывающее вызывать его перед Edit.Context Engineering — токенизация, контекстное окно, стратегии управления контекстом и memory-системы.
Сканируйте QR или переходите по ссылке, чтобы получить обновления по следующим материалам.