# Handoff: эксперимент с координатором субагентов Дата: 2026-06-11 Ветка: `feature/data-generator` Жанр: одноразовый handoff по [ADR-0003](../../docs/adr/0003-handoffs-in-scratch.md). ## Зачем нужен этот handoff Пользователь хочет провести эксперимент: не реализовывать следующие задачи самому верхнеуровневому агенту, а использовать его как координатора цепочки субагентов. После эксперимента планируется отдельно отрефлексировать, что сработало, что не сработало и стоит ли закреплять такой процесс. Этот документ фиксирует текущее понимание процесса перед запуском, чтобы не потерять договорённости в новой сессии. ## Текущий рабочий контекст Активная линия работы — переработка steady-stream генератора кликстрима. Задачи лежат в `.scratch/feature-data-generator/issues/`. Уже выполнены и ожидают человеческой приёмки: - `01-minimal-connected-visit.md` - `02-visit-page-path-and-monotonic-time.md` - `02-5-generator-service-cleanup.md` - `03-tick-stream-with-active-visits.md` - `04-user-population-and-returns.md` Оставшаяся последовательность: 1. `05-intensity-and-flow-calibration.md` 2. `06-state-v2-and-restart.md` 3. `07-service-integration-and-docs.md` Задачи зависимы и, вероятно, меняют близкие файлы генератора, поэтому запускать их надо строго последовательно, не параллельно. В рабочем дереве на момент обсуждения была незакоммиченная правка только в `.scratch/feature-data-generator/issues/06-state-v2-and-restart.md`: добавлен комментарий, что задачу 06 нельзя начинать до завершения предыдущих срезов, особенно задачи 05. ## Договорённая схема эксперимента Верхнеуровневый агент не включает для себя `/goal`. Его роль — координатор и gatekeeper, а не непосредственный исполнитель. Для каждой задачи: 1. Координатор запускает нового worker-субагента на ровно один issue. 2. Задание субагенту формулируется в стиле `/goal`: - реализовать конкретный файл задачи; - работать по методике `/tdd`; - не реализовывать следующие задачи; - не коммитить; - не откатывать чужие изменения; - в конце отчитаться по изменённым файлам, тестам, проверкам и рискам. 3. После реализации тот же субагент делает саморевью в отдельной роли: - остановиться; - проверить результат против acceptance criteria, спеки и тестов; - искать ошибки, лишний объём, хрупкость и нарушение учебной читаемости; - сначала выдать находки с важностью, не исправляя их сразу. 4. Координатор решает, какие замечания достаточно важные. 5. Тот же субагент исправляет только одобренные важные замечания. 6. Координатор проверяет верхнеуровневые вещи: - границы задачи; - список изменённых файлов; - честность отметок acceptance criteria; - тесты; - `git status`; - отсутствие смешивания нескольких задач. 7. Коммит делает координатор, не субагент. 8. Координатор закрывает агента и переходит к следующему issue новым worker-субагентом. Для сложных переходов, особенно после задачи 05 перед задачей 06, можно добавить отдельного reviewer-субагента. Это не обязательный шаг на каждую задачу, а контрольная мера, если есть риск, что саморевью исполнителя недостаточно. ## Роль координатора Координатор не должен пытаться заново глубоко реализовывать или полностью повторять работу субагента. Его польза — в управлении процессом: - держать порядок задач; - ограничивать область изменений; - читать отчёты и принимать решения; - запускать исправления только по существенным замечаниям; - делать финальный обзор diff на уровне границ и рисков; - выполнять проверки и коммитить. Главный риск верхнеуровневого `/goal`: он может заставить координатора оптимизировать работу под закрытие большой цели, а не под аккуратное управление этапами. Поэтому для координатора `/goal` не использовать. ## Почему саморевью тем же субагентом допустимо Пользователь отмечает, что на практике субагенты хорошо делают “ревью свежим взглядом” внутри уже накопленного подробного контекста задачи. Это может быть полезнее, чем полностью внешний поверхностный обзор координатора, которому не хватит деталей реализации. Ожидаемая модель: - субагент глубоко понимает сделанную задачу и проверяет её на несостыковки; - координатор не доверяет этому слепо, но оценивает адекватность выводов и границы изменений; - для особо рискованных мест можно подключить отдельного проверяющего агента. ## Suggested skills - `tdd` — должен использовать worker-субагент при реализации каждой задачи. - `conventional-commits` — использовать координатору перед созданием каждого коммита. - `claude-team-review` — опционально после задачи 05 или перед задачей 06, если нужен дополнительный независимый взгляд на модель. - `handoff` — после эксперимента зафиксировать рефлексию: что получилось, что не получилось, какие правила стоит оставить. ## Возможная первая команда субагенту ```text /goal Реализовать .scratch/feature-data-generator/issues/05-intensity-and-flow-calibration.md с использованием /tdd. Работай только в границах этой задачи. Не реализовывай задачи 06-07. Не коммить. Не откатывай чужие изменения. Сначала прочитай сам issue и источники решений, указанные в нём. Работай вертикальными TDD-срезами: один тест на наблюдаемое поведение -> минимальная реализация -> зелёная проверка -> следующий тест. В конце остановись и отчитайся: - какие файлы изменены; - какие тесты добавлены или изменены; - какие проверки запускались и с каким результатом; - какие acceptance criteria закрыты; - какие риски или спорные места остались. ``` После этого координатор должен попросить того же субагента выполнить саморевью результата, не исправляя замечания до отдельного решения координатора. ## Наблюдения во время эксперимента ### Цикл 05: интенсивность и калибровка потока Стартовая задача оказалась дорогой по обратной связи: это не локальный инвариант, а отладка статистической модели на длинных симуляциях. Первый worker долго работал без промежуточного отчёта; координатору пришлось сначала поставить мягкий статус-чек в очередь, затем прервать агента ради статуса. Это не сломало работу, но показало: для статистических задач лучше заранее задавать контрольные точки или ожидать длинный первый цикл. Саморевью того же worker оказалось полезным. Оно нашло несколько реальных несостыковок: - `docker-compose.yml` оставлял старую интенсивность `GEN_LAMBDA_BASE_PER_MIN=200`; - тест межсессионной паузы был слишком широким; - в тестовой конфигурации оставались старые числа; - README мог быть двусмысленным про `GEN_MIN/MAX_EVENTS_PER_TICK`. Координаторская проверка тоже добавила ценность: после саморевью был найден конфликт между новым `GEN_LAMBDA_BASE_PER_MIN=30` и старым нижним пределом `GEN_MIN_EVENTS_PER_TICK=5`. При тике 5 секунд это давало минимум 60 событий в минуту и ломало критерий интенсивности. Worker исправил это отдельной точечной итерацией. Полезная схема цикла: 1. worker реализует задачу; 2. координатор прерывает только если агент слишком долго молчит; 3. worker делает саморевью без правок; 4. координатор выбирает, какие замечания чинить; 5. worker чинит только выбранные пункты; 6. координатор добавляет свой узкий sanity-check по связям между дефолтами, документацией и критерием задачи; 7. координатор коммитит. Результат цикла 05: - коммит `8f1e997 feat(generator): откалиброван поток steady-stream генератора`; - полный прогон: `uv run --with-requirements generator/requirements.txt pytest generator/tests -q` — 96 passed; - `git diff --check` — без замечаний. Промежуточный вывод: тот же субагент действительно хорошо использует подробный контекст задачи для саморевью, но координатор всё равно нужен как внешний проверяющий связей между настройками, обычным запуском и acceptance criteria. ### Reviewer-субагент между задачами После задачи 06 пользователь предложил добавить отдельного reviewer-субагента между задачами. Это выглядит особенно полезно на границах вроде 06 -> 07, где следующая задача будет опираться на уже изменённые состояние, сервисный цикл и документацию. Важное ограничение: reviewer не является источником истины. Его находки нужно рассматривать как гипотезы и классифицировать координатором: - `чинить до коммита` — реальный дефект или риск закрытия acceptance criteria; - `записать как риск` — важно знать, но не блокирует текущую задачу; - `ложная тревога` — reviewer неверно понял код, тест или границы задачи; - `вне скоупа` — может быть полезно позже, но не относится к текущему issue. Только находки из первой группы возвращаются worker-агенту на исправление. Иначе есть риск превратить reviewer-а в источник лишнего объёма и расползания задачи. В цикле 06 это правило сразу пригодилось. Саморевью исполнителя и отдельный reviewer независимо нашли два существенных риска: - битое state v2 с валидным ГПСЧ могло пройти `from_dict_safe`, а затем уронить сервис уже в `restore_state`; - снимок активных визитов сохранялся полными batch-словарями и на верхних лимитах получался порядка мегабайт, хотя спека говорит про компактное состояние. Координатор проверил обе гипотезы локально: `restore_state` действительно падал на битой вложенной структуре, а оценка JSON-снимка при 200 активных визитах и популяции 300 дала около 4.7 MB. Эти находки классифицированы как `чинить до коммита` и возвращены worker-агенту. Низкие замечания про совместимость `generate_tick_batch` и пересечение сервиса с задачей 07 не стали правками: первое оказалось ложной тревогой, второе — допустимым пересечением для восстановления state v2. После крупной переделки по замечаниям reviewer-а нужен второй круг ревью. В цикле 06 это подтвердилось: исправление компактного состояния само изменило дизайн снимка и восстановление активных визитов. Второй reviewer нашёл новый дефект уже в исправленной версии: формально похожий v2-state с `population=[]` или строковым `pending_visit_births` проходил первичную загрузку, но затем оставлял поток без пользователей или ронял следующий тик. Координатор подтвердил это локальной проверкой и вернул worker-агенту как единственный обязательный пункт второго круга.