Spec-first: как организовать команду AI-агентов, чтобы ревью длилось минуты, а не часы
Большинство команд не планировали становиться «командами AI-агентов». Один разработчик начал пользоваться coding agent, другой подключил агента в CI, и через квартал половина PR в репозитории пишется машинами. Код приходит быстрее, чем кто-либо успевает решить, что именно должно быть построено, и проверить, что было построено на самом деле. Spec-first-подход устраняет этот дисбаланс: он перемещает усилия человека туда, где агенты не могут его заменить — формулировка намерения и проверка результата.
Проблема: узкое место сместилось, а процесс — нет
До появления coding agents самое медленное звено — написание кода, поэтому процессы оптимизировали под пропускную способность разработчика. С агентами реализация почти бесплатна, и два других этапа становятся ограничением: решение, что именно строить, и подтверждение, что результат соответствует задумке.
При старом процессе это ощущается как специфическая боль: PR накапливаются быстрее, чем ревьюеры успевают их читать. Два агента решают пересекающиеся задачи несовместимыми способами. Промпт, который жил только в чате одного разработчика, породил продуктовое решение, которое никто не утверждал. Проблема не в агентах — проблема в том, что намерение команды не существует в форме, которую агент или ревьюер может проверить. Ответ spec-first: сделать намерение долговечным.
Пять этапов рабочего процесса
Подход работает с Claude Code, Cursor, Copilot и любыми другими агентами, потому что контракт живёт в файлах, а не в памяти инструмента.
| Этап | Владелец | Артефакт | Критерий прохода |
|---|---|---|---|
| 1. Спецификация | Владелец фичи | spec.md |
Цель, не-цели и acceptance criteria утверждены человеком |
| 2. Декомпозиция | Техлид или planning agent | tasks.md |
У каждой задачи есть write scope и проверяемый результат |
| 3. Реализация | Один агент на задачу | Diff в изолированной ветке | Diff не выходит за границы write scope |
| 4. Сбор доказательств | Тот же агент | evidence.md |
Тесты, логи и проверки, названные в спецификации, существуют и проходят |
| 5. Ревью | Человек-ревьюер | PR со связанными артефактами | Проверка по чек-листу, а не по ощущениям |
Этап 1: спецификация
Вход — тикет вроде «дать админам поддержки возможность повторять упавшие экспорты». Выход — одностраничный spec-пакет, который фиксирует четыре вещи: цель в наблюдаемых терминах, не-цели, ограничивающие изменение, acceptance criteria, которые может проверить тест, и доказательства, которые потребует ревьюер.
Пакет пишется до выбора агента-исполнителя. Именно здесь продуктовая неоднозначность разрешается человеком, а не утекает в предположения агента. Самая важная дисциплина — не-цели: «никаких изменений схемы, никаких правок email-шаблонов, никаких новых зависимостей» — это убирает три самых распространённых способа, которыми агенты услужливо расширяют scope.
Этап 2: декомпозиция на ограниченные задачи
Надёжная единица работы агента — задача, которую один агент может выполнить, а один человек — отревьюить за один присест. Каждая задача в tasks.md требует трёх полей помимо описания:
- Write scope — список файлов, которые агенту разрешено менять.
- Acceptance criteria — скопированные или выведенные из пакета.
- Требование к доказательствам — название теста или проверки, подтверждающей завершение.
Задачи, которые используют одни и те же файлы, не могут выполняться параллельно. Если две задачи требуют правок в billing/index.ts, их нужно либо объединить, либо сериализовать явной зависимостью. Конфликты слияния между агентами — это не проблема инструментов, это проблема декомпозиции.
Этап 3: параллельный запуск агентов в рамках write scope
Каждый агент получает одну задачу, её пакет и изолированную ветку. Write scope — это линия принуждения: агент, отредактировавший файл за пределами scope, получает отклонение диффа до ревью, без обсуждений.
Критически важна оговорка «остановись и сообщи»: если задача требует трогать что-то вне scope, агент должен остановиться и доложить, а не редактировать молча. Самая дорогая ошибка агента — не неправильная реализация, а тихое решение: лишняя колонка, переименованная функция, новая зависимость, закопанная в правдоподобном диффе.
Этап 4: сбор доказательств до запроса ревью
Заявление агента о завершении работы ничего не стоит — ценность имеет цепочка артефактов. Перед открытием PR агент заполняет evidence.md: какие тесты добавлены и их вывод, какое acceptance criterion покрывает каждый тест, и любые логи, скриншоты или проверки контрактов, которые требовал пакет.
Именно здесь умирает галлюцинаторная полнота. Агент, который говорит «все тесты проходят», но не может вставить вывод запуска для export_retry_idempotent, не закончил. Команды, внедрившие evidence-гейты, сообщают, что гейт отлавливает больше плохих слияний, чем само код-ревью, потому что он механический: названный тест либо существует и проходит, либо нет.
Этап 5: человеческое ревью по чек-листу
Человеческое ревью — самый дефицитный ресурс, поэтому тратьте его только на то, что предыдущие гейты не могут проверить: соответствует ли дифф намерению и не проскользнуло ли что-то незаявленное. Ревьюер подтверждает, что дифф остаётся в scope, сопоставляет каждое изменение с задачей, выборочно проверяет evidence и специально ищет изменения, которых не требовала ни одна задача.
Ревью ускоряется по мере улучшения артефактов. Когда ревьюер видит критерий, тест и дифф рядом, утверждение ограниченной задачи занимает минуты. Когда чего-то из трёх не хватает, ревью вырождается в обратный вывод спецификации из кода — ровно та работа, которую процесс и призван устранить.
Рабочий пример: одна фича, три агента
Фича: «админы поддержки могут повторить упавший экспорт данных». Пакет фиксирует политику (только админы, один повтор за раз, без редизайна схемы) и планку доказательств (тест на идемпотентность, запись в аудит-лог, отсутствие изменений формата экспортного файла).
- Задача 1 (агент A): колонка состояния retry + миграция, scope:
db/migrations,models/export.ts - Задача 2 (агент B): эндпоинт retry + идемпотентность, scope:
src/exports/retry.ts+ тест - Задача 3 (агент C): кнопка retry в админской консоли, scope:
console/exports/*.tsx+ тест
После слияния задачи 1 задачи 2 и 3 запускаются параллельно. Общее время ревью — около 40 минут на всю фичу.
Показательный сбой: агент B добавил полезную колонку retry_count в модель, выйдя за write scope. Проверка scope отловила это до ревью. Команда решила, что счётчик действительно полезен, оформила его как follow-up задачу и отклонила out-of-scope правку. Процесс сработал: хорошая идея выжила, непроверенное решение — нет.
Что измерять в первые 30 дней
Внедряйте процесс на одном потоке фич, а не на всей команде, и отслеживайте три метрики:
- Время ревью на агентский PR — должно падать от недели к неделе по мере стандартизации артефактов.
- Out-of-scope правки, пойманные до ревью — сначала должно быть ненулевое значение (гейт работает), затем снижаться (промпты учатся).
- Доля переделок — PR, которым потребовался второй проход реализации после ревью. Это число оправдывает процесс перед скептиками.
Типичные сбои
| Симптом | Причина | Исправление |
|---|---|---|
| Агенты создают конфликтующие диффы | Задачи используют одни файлы | Перекроить write scope или сериализовать |
| Спецификация занимает больше времени, чем реализация | Слишком большой scope пакета | Один пакет на обозримый срез фичи, а не на эпик |
| Evidence-логи превращаются в формальность | Критерии не тестируемы | Переписать acceptance criteria как наблюдаемые исходы до декомпозиции |
| Ревьюеры штампуют зелёные чек-листы | Чек-лист заменил суждение вместо фокусировки | Ревьюер лично отвечает на вопрос «что никто не просил?» в каждом PR |
Установившийся режим негламурный: спецификации короткие, задачи скучные, агенты взаимозаменяемы, ревью быстрое. Именно так выглядит процесс, когда люди тратят время на намерение и доказательства, а машины — на всё, что между ними.