feat(skill): coordinator-loop — топология ревью под Codex и эскалация

- Зачем:
  - боевой прогон цепочки 07-11 показал: worker в Codex не может запускать
    субагентов, ревью шло пятью кругами без ограничителя, финальный handoff
    и закрытие issue выпадали из цикла.
- Что:
  - ревьюеров запускает координатор (наблюдатели, ограничение промптом),
    триаж находок и флаг «спор» — в worker-е; политика кругов с потолком.
  - две ручки стоимости: модель по роли и уровень мышления, таблица
    references/effort-levels.md; шаблон references/reviewer-prompt.md —
    скилл самодостаточен, без файлов claude-team-review.
  - журнал с метками времени; финал: PRD до ревью, Status: done
    docs-коммитом, handoff — условие выхода; handoff пакета правок.
- Проверка:
  - адверсарное ревью пакета свежим субагентом (2 блокера и 7 important
    закрыты) плюс саморевью; следующий боевой прогон цепочки — замер.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
ddadminandClaude Fable 5 committed 2026-07-04 20:09:35 +03:00
1 parent 2ed3fd81ea
commit 2d9fc7eadb
6 files changed
+542 -77

No files matched your search

+156 -66
View File
@@ -3,7 +3,7 @@ name: coordinator-loop
disable-model-invocation: true
description: >-
Координаторский цикл по цепочке готовых issue: на каждый — worker-субагент по TDD
с ревью через claude-team-review, коммит делает координатор. Контекст координатора
с независимым ревью, коммит делает координатор. Контекст координатора
держится чистым — в него входит только индекс находок, не diff. Узкий навык, только
по явному вызову /coordinator-loop.
---
@@ -20,7 +20,7 @@ description: >-
контексте быть не должно — их читают субагенты у себя, а тебе возвращают индекс.
Верификацию находок делает ревьюер, не ты. (Исключение — состав diff на коммит-гейте:
`git diff --stat`/`--name-only`, какие файлы и в границах ли; это не полный текст, см.
шаг 6.) Проверяй себя каждый цикл: *в мой контекст попал полный текст вместо индекса?
шаг 7.) Проверяй себя каждый цикл: *в мой контекст попал полный текст вместо индекса?
Если да — это баг процесса.* Так контекст не пухнет, не компактится и не начинает
косячить — это главная болезнь, которую навык лечит.
@@ -33,46 +33,80 @@ description: >-
## Роли
- **Координатор** — ты. Порядок issue, богатый контракт, chain-level классификация по
индексу, коммит-гейт, финальный handoff. **Код ради верификации не читаешь** — это
ревьюер; на коммит-гейте смотришь лишь **состав** diff (не текст, см. шаг 6).
- **Координатор** — ты. Порядок issue, богатый контракт, запуск ревьюеров, политика
кругов ревью, chain-level классификация по индексу, коммит-гейт, финальный handoff.
**Код ради верификации не читаешь** — это ревьюер; на коммит-гейте смотришь лишь
**состав** diff (не текст, см. шаг 7).
- **Worker** — субагент с одной целью (один issue). Гоняет `/goal` (петля
план→код→тест→проверка готовности внешним ревьюером), меняет файлы, **не коммитит и не откатывает чужое**.
Возвращает индекс + статус.
- **Ревьюер** — свежий субагент, которого запускает **сам worker** внутри `/goal` через
`claude-team-review`. Читает код сам, докладу не верит. Триаж находок встроен в
team-review (лид чинит нужное, отклоняет противоречащее требованиям). Нарративы ревью
живут в контексте worker-а, до тебя доходит только его финальный индекс.
план→код→тест), меняет файлы, **не коммитит и не откатывает чужое**. Триажит находки
ревью: чинит или аргументированно отклоняет. Возвращает индекс + статус.
- **Ревьюер** — свежий субагент-**наблюдатель**, которого запускаешь **ты** (см.
«Контракт ревьюеру»): репозиторий и среду не меняет, но инструменты у него полные —
ограничение промптом, не урезанием субагента. Читает код сам, докладу worker-а не
верит, возвращает индекс находок. `claude-team-review` как механизм допустим только там, где его может
запустить **сам worker** (владелец правок): лид team-review чинит код сам, а второй
писатель в дереве недопустим — координатору team-review запускать нельзя.
**Факт среды Codex (проверено 2026-07-04 диагностом с `agent_type=worker`):** worker не
может запускать субагентов — `spawn_agent` недоступен, `tool_search` не находит ни
spawn, ни `claude-team-review`. Поэтому ревьюеров запускает координатор и пересылает
worker-у их индексы **дословно**, без своих интерпретаций. Не перепроверяй этот факт на
каждой цепочке — жечь токены; перепроверь только при сигнале обратного (например,
`tool_search` вдруг нашёл spawn).
## Цикл на одну задачу
1. **Чистое дерево.** `git status --short` до старта. Чужие правки — стоп, спроси
пользователя. Свои процессные — отдели docs-коммитом.
2. **Прочитай issue и зависимости.** Предыдущие в цепочке не закрыты — не начинай.
3. **Контракт worker-у** (см. ниже) и запусти **одного** worker-а.
3. **Назначь режим ревью** по порогу риска (см. «Режимы ревью») и запиши в журнал;
если срез может задеть порог по ходу — задай условие эскалации (например, «worker
тронул state-схему → перевести в гейт»). Затем **контракт worker-у** (см. ниже) и
запусти **одного** worker-а.
4. **Дождись индекса.** Долго молчит — запроси промежуточный статус, не жди вслепую.
Пришло push-уведомление — сразу обрабатывай, не крути опрос по кругу.
5. **Классифицируй по индексу — только chain-level** (см. «Классификация»).
6. **Коммит-гейт.** Прогони полный тест-сет, но в контекст возьми **только сводку**: код
5. **Ревью-гейт** (worker вернул `DONE`/`DONE_WITH_CONCERNS`; `BLOCKED` и
`NEEDS_CONTEXT` разбирай до ревью — гонять ревьюеров по незавершённой работе
бессмысленно). По назначенному режиму запусти ревьюеров; запуск и вердикт каждого
фиксируй в журнале в момент события. Индекс находок перешли worker-у **дословно**,
его триаж прими индексом же. Rerun после правок по гейт-находкам назначаешь **ты**,
автоматически — это не concern worker-а. **Круг** — одна итерация «прогон(ы) ревью →
триаж worker-а»; пара «по задаче + по коду» на гейте — один круг. Гейт закрыт, когда
все назначенные прогоны вернули `APPROVED`. Политика кругов (тождество находок между
кругами судит worker в триаже, не ты — по индексам оно не определяется):
- worker пометил **«спор»** (ревьюер снова поднял вопрос, уже аргументированно
отклонённый через контракт и тест) → не общий rerun, а **узкий гейт** по спорному
вопросу на усиленном уровне мышления;
- спор пережил и узкий усиленный гейт → стоп, решение человека;
- независимо от споров больше **четырёх** кругов ревью на issue → стоп, вынеси
человеку вопрос «дробить issue или принимать риск».
6. **Классифицируй по индексу — только chain-level** (см. «Классификация»).
7. **Коммит-гейт.** Прогони полный тест-сет, но в контекст возьми **только сводку**: код
возврата и имена упавших тестов (`pytest -q`/хвост вывода), не полный вывод. Так же
проверь **состав** diff (`git diff --stat`/`--name-only`: какие файлы, в границах ли —
не полный текст) и коммить. Упали тесты — верни их worker-у по именам, трейсбеки в свой
контекст не тащи. Сверь происхождение ревью в индексе с назначенным режимом: нет
происхождения или механизм подменён — верни worker-у. В коммит issue стейджи только
файлы worker-а; `coordinator-journal.md` в грязном дереве — ожидаемый процессный файл,
не нарушение границ: он уходит отдельным docs-коммитом (шаг 1 следующего цикла, на
последнем issue — перед выходом). Это последняя точка контроля состава изменений.
7. **Закрой субагентов.** Следующий issue стартует в новом worker-е.
контекст не тащи. Сверь по журналу, что назначенный режим ревью выполнен: каждый
запуск и вердикт записаны в момент события; нет записи — ревью не проведено. В коммит
issue стейджи только файлы worker-а; файл issue и `coordinator-journal.md` —
процессные, не файлы worker-а: после коммита переведи в файле issue `Status: done`,
и оба уходят отдельным docs-коммитом (шаг 1 следующего цикла, на последнем issue —
перед выходом). Это последняя точка контроля состава изменений.
8. **Закрой субагентов.** Следующий issue стартует в новом worker-е.
## Журнал прогона
С первого шага цепочки веди журнал: append-only файл
`.scratch/<feature>/coordinator-journal.md`, короткие записи в конец по ходу событий,
не задним числом. Точки записи: старт issue (worker запущен, назначенный режим ревью),
принят индекс (строка происхождения ревью — как есть), коммит-гейт (сводка тестов, хэш
коммита), chain-level решения (риск / вне скоупа). Журнал — тот же индекс, вынесенный в
файл: полных текстов в нём нет. В рабочие коммиты issue его не подмешивай (механика —
на коммит-гейте, шаг 6).
не задним числом. Каждую запись начинай с времени `HH:MM` (дата — в заголовке дня;
время бери вызовом `date`, сама модель его не знает) — так по журналу восстанавливается
длительность этапов и границы issue. Точки записи: старт issue (worker запущен,
назначенный режим ревью), принят индекс worker-а, **запуск каждого ревью** (механизм,
кто запускал, уровень мышления) и **его вердикт**, коммит-гейт (сводка тестов, хэш
коммита), chain-level решения (риск / вне скоупа). Происхождение ревью пишешь ты сам —
в момент запуска и в момент вердикта. Мельче этих точек (каждая команда, каждый
прочитанный файл) не пиши — метки времени не должны превратить журнал в спам. Журнал —
тот же индекс, вынесенный в файл: полных текстов в нём нет. В рабочие коммиты issue его
не подмешивай (механика — на коммит-гейте, шаг 7).
Что это даёт: обрыв координатора не теряет состояние — по журналу видно, на каком этапе
цепочка и что уже сделано; происхождение ревью фиксируется в момент события — переписать
@@ -90,65 +124,110 @@ description: >-
- методика **`/tdd`** (короткие срезы тест→код); точечные тесты в петле;
- **саморевью свежим взглядом** перед сдачей (отдельно от петли `/goal`) — worker
критически перечитывает свою работу и правит очевидное. Базовый минимум даже без
team-review: ошибаются все;
- **после реализации — `claude-team-review` по коду** (число проверок — по режиму ниже);
независимого ревью: ошибаются все;
- **триаж находок ревью**: независимое ревью организует координатор и присылает индекс
находок; worker каждую находку чинит или **аргументированно отклоняет** — через
контракт и тест, не голословно. Вопрос, который ревьюер поднял снова после
аргументированного отклонения, worker помечает в своём индексе флагом **«спор»**
с отсылкой к прежнему обоснованию;
- **формат отчёта — индекс**: находка/изменение, `файл:строка`, минимальный repro, какой
критерий; запрет вставлять diff и полный вывод тестов;
- **происхождение ревью** — одна строка в индексе: режим (тривиальный/обычный/гейт),
механизм (какой скилл или петля), кто ревьюер, вердикт. Ревью, заявленное без
происхождения, считается не проведённым;
- **статус-контракт** `DONE / DONE_WITH_CONCERNS / BLOCKED / NEEDS_CONTEXT` — worker сам
стопорится на архитектурной неясности, а не додумывает молча;
стопорится на архитектурной неясности, а не додумывает молча. `BLOCKED` — только про
саму работу; недоступная в среде worker-а стендовая проверка (docker, сеть, стенд) —
это `DONE_WITH_CONCERNS` с фактом («docker отсутствует: <вывод>») и **готовой
командой**, которую координатор прогонит сам (не прошла и у координатора — он
фиксирует в журнале, где и как проверка прошла фактически);
- **запрет коммита** и **запрет отката чужого**.
Цель worker-а — **одна** (один issue = одна петля). Не запускай `/goal` на всю цепочку
сразу: от координатора нужна остановка на контрольных точках, а не «закрыть всё любой ценой».
## Контракт ревьюеру
Симметричен контракту worker-а, короче:
- **наблюдатель с полными инструментами**: код читает сам, докладу worker-а не верит;
может запускать тесты, воспроизводить находки, смотреть документацию и сеть —
верификация требует инструментов. Ограничение — **промптом, не урезанием субагента**:
не менять репозиторий и среду (правки файлов, git-операции, установка пакетов —
нельзя), так в дереве нет второго писателя;
- **зачем**: те же ссылки на issue/PRD/спеку, что у worker-а, плюс фокус проверки
(по задаче или по коду); на гейте — явная цель по двум семействам, слепым для одной
линии: межмодульные инварианты и форма распределений;
- **формат отчёта — индекс**: находка, `файл:строка`, какой критерий нарушен,
минимальный repro; вердикт одной строкой (`APPROVED` / `CHANGES_REQUESTED`); запрет
вставлять diff, полный вывод тестов и нарратив рассуждений;
- модель и уровень мышления задаёт координатор при запуске (см. «Режимы ревью»).
Готовый шаблон промпта — [references/reviewer-prompt.md](references/reviewer-prompt.md)
(адаптация из `claude-team-review`); скилл самодостаточен, внешних файлов не требует.
## Режимы ревью — рычаг стоимости
Две проверки **разными субагентами** — по задаче и по коду — ловят непересекающиеся
множества находок, но это расход токенов (по бюджету, не по контексту координатора).
Плати по риску, не на каждой мелочи:
множества находок, но это расход токенов (бюджет; в твой контекст при этом идут только
индексы находок). Плати по риску, не на каждой мелочи:
- **тривиальный issue** — team-review не зови; хватает петли `/goal` (её внешний
ревьюер готовности) плюс саморевью из контракта;
- **обычный (дефолт)** — один прогон `claude-team-review` **по коду**; соответствие
- **тривиальный issue** — независимое ревью не зови; хватает петли `/goal` плюс
саморевью из контракта (в среде без вложенных субагентов внешняя проверка готовности
внутри `/goal` тоже недоступна — саморевью остаётся единственной проверкой, это
осознанная цена режима);
- **обычный (дефолт)** — один прогон независимого ревью **по коду**; соответствие
issue/спеке держит петля `/goal`;
- **рискованный / гейт** — два прогона разными субагентами: **по задаче** (сделал ли то,
что в issue/спеке) + **по коду** (тонкие баги, межмодульное). Проверку по задаче можно
на дешёвой модели — модель по роли.
что в issue/спеке) + **по коду** (тонкие баги, межмодульное).
Порог риска: state и сериализация, формат данных, интеграция сервиса, статистические
модели, честность документации, межмодульные инварианты.
**Две ручки стоимости, не одна.** *Модель по роли* — какая модель на какой роли:
проверка по задаче тянет дешёвую, финальное chain-ревью требует сильную. *Уровень
мышления* — отдельная ось, глубина рассуждений той же модели. Три относительных уровня,
без привязки к именам: **экономный** (ступень вниз — task-lens ревью, диагностика,
разбор логов), **рабочий** (дефолт — worker, обычное code review), **усиленный**
(ступень вверх — эскалация споров по политике кругов, межмодульные инварианты и форма
распределений, финальное chain-ревью). Соответствие ролей конкретным моделям и уровням
хоста — датированная таблица [references/effort-levels.md](references/effort-levels.md);
в логике скилла имён нет, вышла новая модель — правится таблица, не правила. Дефолт —
рабочий уровень; вверх — только по триггеру (шаг 5), не «на всякий случай». Хост без
управляемых уровней: эскалация вырождается в свежего субагента — слабее, но не пусто.
## Классификация находок
Per-finding триаж («реально / ложно / чинить») уже делает `claude-team-review` внутри
worker-а — **не переписывай его**. Ты решаешь только **на уровне цепочки**, читая индекс:
Per-finding триаж («реально / ложно / чинить») делает **worker** — у него контекст кода
и «зачем» из контракта; **не переписывай его**. Ты решаешь только **на уровне цепочки**,
читая индекс:
- **записать риском** — важно помнить, текущий коммит не блокирует (реестр рисков цепочки);
- **вне скоупа** — пригодится позже, отдать в следующий issue.
## Финал цепочки
1. **Ревью на соответствие замыслу** (рекомендуется для любой нетривиальной цепочки).
В самом конце — один прогон субагента-ревьюера **сильной моделью** (не дешёвой):
читает **всю** реализацию против **исходной спеки/PRD** и проверяет, не разъехалась ли
поэтапная реализация с замыслом. Возвращает индекс. Один прогон добавляет к общей
стоимости немного, а ловит дрейф, который per-issue срезы не видят — ни одно ревью
отдельной задачи не сверяло целое с целым замыслом. Это Codex (одна линия): берёт
**охват** (целое против замысла), но не кросс-линию — глубокие сквозные слепые пятна
линии остаются на п.2.
2. **Handoff, а не ревью.** Последний акт координатора — записка (`.scratch/<feature>/…`
или через `/handoff`), собранная **по журналу прогона, не по памяти**. Она готовит
**кросс-линейное ревью**: проход модели другой родословной по написанному. Внутри
Кодекса ревьюер — тоже Codex (одна линия), а свежий контекст не снимает слепоту линии
к сквозным дефектам. Сам проход остаётся **вне** скилла — координатор его не выполняет;
но для нетривиальной цепочки он **рекомендован по умолчанию**, не опция: на практике
кросс-проход находил серьёзные расхождения после APPROVED ревьюера той же линии
(эмпирика — [references/rationale.md](references/rationale.md)). В записке:
1. **Приведи документы до ревью.** Обнови PRD/трекер: сделанное — в сделанное, остаток
актуален, статусы issue переведены (шаг 7). Иначе финальное ревью предсказуемо найдёт
этот дрейф вместо настоящего.
2. **Ревью на соответствие замыслу** (рекомендуется для любой нетривиальной цепочки).
Один прогон субагента-ревьюера **сильной моделью на усиленном уровне** (обе ручки
вверх — см. «Режимы ревью»): читает **всю** реализацию против **исходной спеки/PRD**
и проверяет, не разъехалась ли поэтапная реализация с замыслом. Возвращает индекс.
Один прогон добавляет к общей стоимости немного, а ловит дрейф, который per-issue
срезы не видят — ни одно ревью отдельной задачи не сверяло целое с целым замыслом.
Это Codex (одна линия): берёт **охват** (целое против замысла), но не кросс-линию —
глубокие сквозные слепые пятна линии остаются на п.3.
3. **Handoff — условие выхода, а не пожелание.** Для нетривиальной цепочки цикл не
считается завершённым без записки, собранной **по журналу прогона, не по памяти**.
Место и формат — по конвенции репозитория для handoff (AGENTS.md, ADR), если она
есть; иначе `.scratch/<feature>/…`. Записка готовит **кросс-линейное ревью**: проход
модели другой родословной по написанному. Внутри Кодекса ревьюер — тоже Codex (одна
линия), а свежий контекст не снимает слепоту линии к сквозным дефектам. Сам проход
остаётся **вне** скилла — координатор его не выполняет; но для нетривиальной цепочки
он **рекомендован по умолчанию**, не опция: на практике кросс-проход находил
серьёзные расхождения после APPROVED ревьюера той же линии (эмпирика —
[references/rationale.md](references/rationale.md)). В записке:
- индекс построенного по issue (`файл:строка` ключевых стыков);
- **происхождение ревью по каждому issue** (режим, механизм, вердикт) — из журнала;
- **происхождение ревью по каждому issue** (режим, механизм, кто запускал, уровень,
вердикт) — из журнала;
- **отклонения от процесса — фактами**: что пробовали, что сделано вместо;
причины-предположения («недоступно», «не поддерживается») без проверки фактом — запрещены;
- **открытый риск**: межмодульные инварианты и форма распределения другой родословной
@@ -160,16 +239,25 @@ worker-а — **не переписывай его**. Ты решаешь тол
## Чек-лист координатора
- [ ] Дерево чистое перед стартом; чужие правки согласованы, процессные отделены.
- [ ] Worker получил один issue + **зачем** (PRD/спека), границы, `/tdd`, режим ревью,
индекс-формат, статус-контракт, запрет коммита и отката; саморевью свежим взглядом сделан.
- [ ] Worker получил один issue + **зачем** (PRD/спека), границы, `/tdd`, индекс-формат,
триаж находок ревью (с флагом «спор»), статус-контракт, запрет коммита и отката;
саморевью свежим взглядом сделан.
- [ ] В мой контекст вошёл **только индекс** — ни diff, ни логов, ни нарратива ревью.
- [ ] Индекс каждого worker-а содержит происхождение ревью; без него ревью не засчитано.
- [ ] Журнал прогона ведётся append-only по ходу; точки записи не пропущены.
- [ ] Ревью-гейт: индексы находок пересланы worker-у дословно; rerun назначал я;
политика кругов соблюдена (спор → узкий усиленный гейт; больше четырёх кругов →
человек).
- [ ] Происхождение каждого ревью (механизм, кто запускал, уровень, вердикт) записано
мной в журнал в момент события; нет записи — ревью не засчитано.
- [ ] Журнал ведётся append-only по ходу, каждая запись с меткой `HH:MM`; точки записи
не пропущены.
- [ ] Chain-level классификация сделана по индексу (риск / вне скоупа).
- [ ] Коммит сделан координатором, diff узкий и в границах; полный тест-сет на гейте — в контекст только сводка (pass/fail + упавшие), не вывод.
- [ ] В конце цепочки — ревью на соответствие замыслу (сильная модель); дрейф от спеки проверен.
- [ ] Финальный handoff собран по журналу: происхождение ревью по issue, отклонения
фактами, бриф кросс-линейного ревью (для нетривиальной цепочки — рекомендован по умолчанию).
- [ ] Статусы закрытых issue переведены в `done` и ушли docs-коммитом вместе с журналом.
- [ ] PRD/трекер приведены **до** финального ревью; ревью на соответствие замыслу —
сильная модель на усиленном уровне; дрейф от спеки проверен.
- [ ] Финальный handoff собран по журналу и по конвенции репозитория: происхождение
ревью по issue, отклонения фактами, бриф кросс-линейного ревью. Для нетривиальной
цепочки без него из цикла не выходить.
- [ ] Субагенты закрыты; `git status` чист на выходе.
## Подробнее
@@ -178,9 +266,11 @@ worker-а — **не переписывай его**. Ты решаешь тол
дефектов ловит, центральная находка про родословную, открытые вопросы.
- `handoffs/` — экономия контекста (два пожара: контекст vs лимит), наблюдаемость и
непроверенные кандидаты-фиксы (файловый канал, демоушн закрытых issue, точечные тесты);
live-log наблюдаемости вырос в журнал прогона (2026-07-03).
live-log наблюдаемости вырос в журнал прогона (2026-07-03); топология ревью под Codex,
политика кругов и уровни мышления — по боевому прогону (2026-07-04).
## Источники упомянутых скиллов
- `/to-issues`, `/tdd`, `/claude-team-review` — инженерные скиллы (набор Matt Pocock и внутренние).
- `/goal` — встроенная петля Codex (план→код→тест→проверка готовности внешним ревьюером).
- `/goal` — встроенная петля Codex (план→код→тест; её внешняя проверка готовности в
среде без вложенных субагентов недоступна).