diff --git a/agents/.agents/skills/coordinator-loop/SKILL.md b/agents/.agents/skills/coordinator-loop/SKILL.md new file mode 100644 index 0000000..92793db --- /dev/null +++ b/agents/.agents/skills/coordinator-loop/SKILL.md @@ -0,0 +1,191 @@ +--- +name: coordinator-loop +description: >- + Координаторский цикл для цепочки зависимых задач (issues из /to-issues): на каждую + задачу запускается worker-субагент с одной конкретной целью, затем саморевью, + классификация находок, независимый ревьюер на рискованных местах и коммит силами + координатора. Узкоспециализированный навык — НЕ включай автоматически. Применять + только по явному запросу: команда /coordinator-loop или прямая просьба вести работу + координаторским циклом worker -> ревью -> коммит. +--- + +# Координационный цикл субагентов + +Ты — **координатор**. Ты не пишешь основную реализацию сам. Ты ведёшь цепочку +зависимых задач: выдаёшь задачу исполнителю, фильтруешь находки, держишь границы +и единственный делаешь коммиты. + +Ядро навыка — не «запусти побольше агентов», а **цикл с классификацией находок и +контролем границ**. Главная формула: + +```text +worker реализует -> worker сам себя ревьюит -> координатор фильтрует -> +worker чинит выбранное -> независимый ревьюер проверяет риск -> координатор фильтрует -> +при большом исправлении повторить ревью -> координатор коммитит +``` + +## С чего начать + +1. Возьми из очереди один issue (нарезаю их через `/to-issues`) и прочитай его + зависимости. +2. Проверь, что рабочее дерево чистое. +3. Сформулируй контракт worker-у: цель = issue, границы, методика. +4. Запусти одного worker-а. Дальше — по циклу ниже. + +## Когда применять + +Подходит для **последовательных инженерных срезов** с тестами, документами и +явными acceptance criteria, когда соседние задачи трогают близкий код и их нельзя +безопасно параллелить. + +Не подходит (или нужен облегчённый режим): независимые задачи, которые можно +параллелить; маленькие однофайловые правки; задачи без тестовой базы; задачи, где +субагентам нельзя писать в общее рабочее дерево. + +## Роли + +- **Координатор** — ты. Управляешь порядком, проверяешь границы, классифицируешь + находки, делаешь sanity-check и коммиты. +- **Worker** — субагент-исполнитель с одной конкретной целью (один issue). Работает + в общем дереве, меняет файлы, гоняет тесты, **но не коммитит**. +- **Саморевью worker-а** — отдельная фаза: тот же worker временно становится + проверяющим и **сначала только выдаёт находки, не правя их**. +- **Независимый ревьюер** — отдельный субагент со **свежим контекстом**. Он не + редактирует файлы, но проверяет находки делом: читает diff, issue, спеки и тесты, + **сам прогоняет тесты и линтеры**, сверяется с документацией. Ограничивай ему + право *записи*, а не право *проверять*: ревьюер, которому оставили только чтение, + скатывается в догадки. +- **Находка** — гипотеза о проблеме, а не автоматическое требование правки. + Решение принимаешь ты. + +Все агенты работают с **одним рабочим деревом**. Поэтому каждый цикл начинай и +заканчивай явной проверкой `git status --short` и отделяй рабочие изменения задачи +от процессных заметок и чужих правок. + +## Цикл на одну задачу + +1. **Прочитай issue и его зависимости.** На них строятся цель, границы и порядок. + Если предыдущие задачи цепочки не закрыты — не начинай. +2. **Чистое дерево.** Проверь `git status --short`. Если есть процессные или чужие + правки — отдели их отдельным docs-коммитом до запуска worker-а. +3. **Запусти одного worker-а на этот issue.** Дай задание как контракт (см. ниже). +4. **Дождись отчёта.** Если работа долго молчит (особенно статистика и долгие + тесты) — запроси промежуточный статус, не дожидаясь конца вслепую. +5. **Саморевью без правок.** Попроси того же worker-а отревьюить свою работу и + выдать находки, ничего пока не исправляя. +6. **Классифицируй находки** (см. ниже). +7. **Верни worker-у только одобренное** для исправления. +8. **Свой sanity-check.** Не реимплемент, а проверка связей: дефолты, compose и + конфиги, документы, acceptance criteria, `git status`, тесты. +9. **На рискованном месте — независимый ревьюер** в свежем субагенте (см. + «Когда звать ревьюера»). +10. **Классифицируй находки ревьюера.** +11. **Большое исправление — повторный круг ревью.** Если правка изменила дизайн + или формат данных, ревьюй её результат заново. +12. **Коммит делаешь ты.** Это последняя точка контроля состава diff. +13. **Закрой субагентов.** Следующая задача стартует в новом worker-е. + +## Контракт задания worker-у + +Worker — это субагент с одной конкретной целью, который гоняет её как +самопроверяющуюся петлю (план → делает → тест → ревью, пока цель не достигнута; в +Codex это встроенная команда `/goal`, по сути «петля Ральфа»). Цель берётся из +одного issue (issues удобно нарезать через `/to-issues`). + +В задании worker-у должны быть: + +- одна конкретная цель из issue и критерий «готово» (acceptance criteria); +- границы задачи (что трогать нельзя); +- методика `/tdd` (короткие срезы «тест → код»); +- **запрет на коммит**; +- **запрет на откат чужих изменений**; +- формат финального отчёта: файлы, тесты, проверки, выполненные acceptance + criteria, риски и `git status --short`. + +Цель worker-а — **одна** (один issue = одна петля). Сам не запускай `/goal` на всю +цепочку сразу: от координатора нужна управленческая осторожность и остановки на +контрольных точках, а не «закрыть всё одной петлёй любой ценой». + +## Классификация находок + +Ревьюер и саморевью — не источник истины. Каждую находку проверь и отнеси к одной +из категорий: + +- **чинить до коммита** — реальный дефект, нарушение acceptance criteria или + слабое доказательство ключевого поведения; +- **записать как риск** — важно помнить, но текущий коммит не блокирует; +- **ложная тревога** — неверно понят код, тест или границы задачи; +- **вне скоупа** — может пригодиться позже, но не относится к этому issue. + +Без этой фильтрации ревьюер легко превращается в источник расползания задачи. + +## Когда звать независимого ревьюера + +Не после каждой мелкой правки — это дорого и раздувает задачу. Зови на +рискованных точках: + +- state и сериализация; +- интеграция сервиса; +- изменения формата данных; +- статистические модели; +- документация (честность README и операционных документов); +- после большого исправления — повторный круг. + +Ревьюер проверяет не только падения, но и **силу доказательства**: достаточно ли +тест доказывает нужное поведение, а не просто «что-то прошло». + +## Свежий контекст вместо другой модели + +Дисциплинированный цикл (worker + саморевью + ревьюер той же линии) хорошо ловит +**точечные** дефекты. Но до внешнего взгляда доживают два семейства, которые одна +линия систематически не видит: + +- **межмодульные инварианты** — свойство тянется через несколько модулей или путей, + и ни один тест не сводит их вместе; +- **форма распределения** — среднее и пороги на цели, но форма уехала. + +В идеале их закрывает ревьюер **другой родословной** (другая модель). Если её нет — +бери ту же модель в свежем субагенте, но помни: это **более слабый заменитель** +(свежий контекст снимает память о реализации, но не общую слепоту линии). Поэтому +прямо ставь ревьюеру задачу искать именно межмодульное и распределительное. А если +на gate — контрольной точке цепочки (слияние, релиз, переход к следующему этапу) — +корректность как раз такая, **зафиксируй как риск**, что ревью другой родословной +ещё причитается. + +## Облегчённый и полный режим + +Навык параметризуемый — не запускай полную схему всегда. + +- **Облегчённый режим** (простой, низкорисковый issue): worker + саморевью + твой + sanity-check. Без отдельного ревьюера. +- **Полный режим** (риск из списка выше или контрольная точка): добавляешь + независимого ревьюера и, при большом исправлении, повторный круг. + +Если что-то сознательно не проверял (например, использовал мок вместо реального +стека) — **явно это зафиксируй**, не выдавай за проверенное. + +## Чек-лист координатора + +- [ ] Дерево чистое перед стартом; процессные правки отделены. +- [ ] Worker получил один issue и контракт (цель, границы, TDD, запрет коммита и + отката чужого, формат отчёта). +- [ ] Саморевью сделано без правок; находки классифицированы. +- [ ] Свой sanity-check связей пройден. +- [ ] На риске запущен независимый ревьюер со свежим контекстом и нацеленным + заданием; большое исправление прошло повторный круг. +- [ ] Незакрытое ревью другой родословной зафиксировано как риск. +- [ ] Коммит сделан координатором, diff узкий и в границах задачи. +- [ ] Субагенты закрыты; `git status` чист на выходе. + +## Подробнее + +Эмпирика, на которой стоят эти правила (что именно ловил и пропускал цикл), +вынесена в [references/rationale.md](references/rationale.md). + +## Источники упомянутых скиллов + +- `/to-issues`, `/tdd` — из набора инженерных скиллов Matt Pocock: + . +- `/goal` — встроенная команда Codex CLI. +- `/coordinator-loop` — этот навык; вырос из внутреннего эксперимента с + координатором субагентов. diff --git a/agents/.agents/skills/coordinator-loop/references/rationale.md b/agents/.agents/skills/coordinator-loop/references/rationale.md new file mode 100644 index 0000000..269718d --- /dev/null +++ b/agents/.agents/skills/coordinator-loop/references/rationale.md @@ -0,0 +1,86 @@ +# Почему цикл устроен именно так + +Это эмпирика, на которой стоят правила в `SKILL.md`. Читать не обязательно перед +каждым запуском — нужна, когда хочешь понять, какому классу дефектов какой шаг +противостоит, или решить спорный случай. + +Источник — эксперимент на цепочке из трёх зависимых задач генератора кликстрима +(калибровка интенсивности, state версии 2 и рестарт, интеграция сервиса). Задачи +меняли близкий код, поэтому шли строго последовательно, по одному worker-у на +issue. Выводы — хороший сигнал для класса «последовательные инженерные срезы с +тестами и acceptance criteria», но не универсальная истина: один репозиторий, один +домен, три задачи. + +## Что какой шаг ловит + +- **Саморевью worker-а** хорошо ловит локальные несостыковки своей же реализации: + забытый старый дефолт, слишком широкий тест, устаревшие числа в конфиге, + двусмысленный README. У worker-а уже есть подробный контекст, поэтому он дёшево + находит такие вещи — но только если запретить ему править на первом шаге и + попросить сначала выдать находки. +- **Sanity-check координатора** добавляет то, что саморевью структурно не видит: + связи между дефолтами, обычным запуском, документами и acceptance criteria. + Пример из эксперимента: новый базовый поток конфликтовал со старым нижним + пределом числа событий на тик — каждая настройка по отдельности «корректна», а + вместе ломали критерий интенсивности. +- **Отдельный ревьюер** ловит то, что не видит ни worker, ни его саморевью: + падение на битом сохранённом состоянии, которое проходит первичную загрузку; + слишком большой снимок состояния (мегабайты вместо компактного); слабый + интеграционный тест, который формально проходит, но не доказывает уход от + старой плоской модели. +- **Повторный круг ревью после большого исправления.** Когда правка по находке + меняет дизайн или формат данных, она сама нуждается в ревью. В эксперименте + переделка компактного состояния закрыла старый дефект и тут же внесла рядом + новый — его поймал именно второй круг. + +## Центральная находка про родословную + +Главную гипотезу эксперимента проверяло отложенное ревью **моделью другой +родословной** — той, что вела дизайн и спеки, а не той, что писала код. + +Прогноз, что цикл пропустит ссылочную целостность при восстановлении состояния, **не +оправдался**: этот точечный дефект цикл поймал сам (саморевью и отдельный ревьюер +независимо нашли «битое состояние проходит загрузку, но роняет восстановление», и в +коммит легли обёртка и регрессионный тест). + +А до внешнего взгляда дожили дефекты **не точечные, а сквозные**: + +- **Расхождение живого и восстановленного путей.** Живой визит и восстановленный + после рестарта брали атрибуты из разных источников и по-разному генерировали + идентификаторы событий. Инвариант «один визит — однородный контекст» нарушался на + стыке двух путей, который ни один тест не сводил вместе. +- **Форма распределения длины визита.** Среднее и конверсия — на цели, воронка + монотонна (тесты это подтверждали), но форма уехала от эталона: спайк на коротких + визитах, заметная доля срезов о верхний потолок, медиана у нижней границы тестовой + полосы. Тесты пинили средние и пороги, но не форму. + +Отсюда уточнение: ценнее всего ревьюер **другой родословной**, и именно там, где +свойство (а) тянется через несколько модулей или путей, либо (б) корректность +распределительная (форма, а не одно среднее). Для точечных дефектов на входе +хватает саморевью и отдельного ревьюера той же линии. + +Поэтому в `SKILL.md` независимый ревьюер по умолчанию — свежий субагент той же +модели, но с честной оговоркой: свежий контекст снимает память о реализации, а не +общую слепоту линии. Эти два семейства (межмодульное и распределительное) ему надо +давать как явную цель, а незакрытое кросс-линейное ревью на gate — фиксировать как +риск. + +## Чего не делать слепо + +- Не запускать ревьюера после каждой мелкой правки — дорого и раздувает задачу. +- Не принимать все находки за правду — каждую классифицировать. +- Не давать координатору верхнеуровневый `/goal` на всю цепочку — нужна + управленческая осторожность, а не достижение цели любой ценой. +- Не смешивать процессные и handoff-заметки с рабочими коммитами задач. +- Не требовать реальный внешний стек на каждом шаге, если acceptance criteria + допускают мок, — но явно фиксировать, что именно осталось непроверенным. + +## Открытые вопросы + +Эксперимент оставил нерешённым: + +- как заранее понять, что задаче нужен отдельный ревьюер, а не только саморевью; +- стоит ли заранее обязывать worker-а к промежуточным отчётам на статистике и + долгих тестах; +- нужно ли явно ограничивать бюджет worker-а и число кругов ревью; +- как формализовать порог «большое исправление требует второго круга». diff --git a/codex/.codex/skills/coordinator-loop b/codex/.codex/skills/coordinator-loop new file mode 120000 index 0000000..450ba52 --- /dev/null +++ b/codex/.codex/skills/coordinator-loop @@ -0,0 +1 @@ +../../../agents/.agents/skills/coordinator-loop \ No newline at end of file