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

@@ -21,9 +21,9 @@ coordinator-loop — исполнительное звено в середине
↓
узкие проверяемые issues (/to-issues)
↓
coordinator-loop каждый issue: worker (/goal + /tdd + claude-team-review)
→ индекс → коммит координатора; в финале — ревью на
соответствие замыслу + handoff
coordinator-loop каждый issue: worker (/goal + /tdd) + независимое ревью
(запускает координатор) → индекс → коммит координатора;
в финале — ревью на соответствие замыслу + handoff
↓
приёмка ручной кросс-линия ревью (обычно Claude) + проверка человеком
```
@@ -33,10 +33,12 @@ coordinator-loop каждый issue: worker (/goal + /tdd + claude-team
основывать. Затем `/to-issues` режет её на узкие задачи. Именно здесь
закладывается проверяемость результата (см. «Что получается»).
- **Скилл — исполнение.** Берёт **готовые** issues по одной и проводит каждую через
цикл worker (`/goal` + `/tdd` + `claude-team-review`) → индекс → chain-level
классификация → коммит координатора. Контекст координатора держится на индексах, не
на diff'ах. В финале цепочки координатор прогоняет ревью на соответствие замыслу
(целое против исходной спеки, сильной моделью) и пишет handoff, готовящий приёмку.
цикл worker (`/goal` + `/tdd`) → независимое ревью (ревьюеры-наблюдатели, запускает
координатор; триаж находок — в worker-е) → индекс → chain-level классификация →
коммит координатора. Контекст координатора держится на индексах, не на diff'ах.
В финале цепочки координатор прогоняет ревью на соответствие замыслу (целое против
исходной спеки, сильной моделью на усиленном уровне) и пишет handoff, готовящий
приёмку.
- **После скилла — приёмка.** Ревью другой модельной линией (Codex ревьюил Codex, так
что кросс-линия — обычно ручной проход Клодом) плюс проверка человеком. Скилл её не
автоматизирует — только передаёт эстафету с зафиксированным открытым риском.
@@ -63,7 +65,7 @@ coordinator-loop каждый issue: worker (/goal + /tdd + claude-team
- **финальный отчёт worker-а**: какие файлы, какие тесты прогнаны, какие acceptance
criteria закрыты, риски, `git status`;
- **chain-level классификация** (риск / вне скоупа); per-finding триаж («реально /
ложно / чинить») делает `claude-team-review` внутри worker-а.
ложно / чинить») делает worker по индексам ревьюеров.
Один issue = один проверяемый коммит плюс отчёт — так пост-цикловое ревью и ручная
проверка остаются посильными.
@@ -88,7 +90,7 @@ coordinator-loop каждый issue: worker (/goal + /tdd + claude-team
Экспериментальный — прямое продолжение эксперимента с координатором субагентов,
будет дорабатываться. Открытые вопросы (когда нужен отдельный ревьюер, обязательные
промежуточные отчёты, бюджет кругов ревью) собраны в разделе «Открытые вопросы»
промежуточные отчёты, бюджет worker-а) собраны в разделе «Открытые вопросы»
файла [references/rationale.md](references/rationale.md).
## Что читать рядом
+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 (план→код→тест; её внешняя проверка готовности в
среде без вложенных субагентов недоступна).
@@ -0,0 +1,210 @@
# Handoff: топология ревью под Codex, эскалация и дисциплина финала
Дата: 2026-07-04 MSK
Статус: пакет правок по итогам боевого прогона; прошёл адверсарное ревью свежим
субагентом (2 блокера, 7 important, 4 minor — все закрыты правкой этого текста).
В `SKILL.md` вносится следом.
## Зачем этот handoff
Зафиксировать решения по итогам первого боевого прогона переписанного скилла
(цепочка issue 07 → 11 фичи `generator-model-time-startup-history`,
репозиторий `~/sources/clickstream-ch-kafka-superset-demo`) до правки `SKILL.md`.
Источник фактов — журнал прогона
`.scratch/generator-model-time-startup-history/coordinator-journal.md`
(коммиты `d2899e9`, `5081319`, `0a240e3`): отдельного handoff'а координатор не
написал, диагностика лежит в журнале.
## Что показал прогон
Хорошее: дисциплина «индекс, не полный текст» удержалась; журнал фиксировал
происхождение ревью в момент события; финальное chain-ревью поймало дрейф PRD.
Контекст координатора, по впечатлению пользователя, не страдал (прерывания и
дополнительные вопросы прогон пережил) — но это наблюдение, не замер:
числа-ориентиры июня (пик % окна, объём diff-чтений, число тест-прогонов) на
этом прогоне не сняты, сырьё в `~/.codex` ротируется. Пункт остаётся открытым.
Проблемы:
1. **Worker не может запускать субагентов в среде Codex.** У субагентов нет
`multi_agent_v1.spawn_agent`; `tool_search` не находит ни spawn, ни
`claude-team-review`. Проверено дважды: read-only диагностом и отдельным
диагностом с `agent_type=worker` (журнал, записи «Диагностика nested review
tools»). Ключевое допущение дизайна («ревьюера запускает сам worker внутри
`/goal`») в этой среде не работает. Координатор импровизировал: запускал
ревьюеров сам и возвращал worker-у индекс находок — сработало.
2. **Пинг-понг ревью без ограничителя.** Issue 07 прошёл пять кругов code
review; спорная находка (raw-сериализация) продержалась два круга, пока
координатор не изобрёл «узкий гейт на xhigh» по одной находке (усиленный
уровень понадобился на двух кругах из пяти плюс на финальном chain-ревью —
и по делу). Ограничителя и правил эскалации в скилле нет — открытые вопросы
rationale стали боевыми.
3. **Статус-контракт смешивает «работа заблокирована» и «шаг процесса
недоступен»**: worker по issue 11 вернул `BLOCKED` при готовой реализации —
заблокирован был только механизм ревью. Со стендовыми проверками так же:
docker недоступен в песочнице worker-а (07).
4. **Финальный handoff не написан** — шаг «Финал цепочки, п.2» тихо выпал,
бриф для кросс-прохода никто не получил.
5. **Закрытие issue делалось, но внутри feature-коммитов**: статусы 07 и 11
переведены в `done` в коммитах `3c38465` и `4f8f992` — процессная правка
смешана с рабочим diff. Прошлая цепочка (01–06) хуже: статусы остались
неверными («ready-for-human от глючившего координатора», триаж 2026-07-04).
Правила в скилле нет — каждый прогон решает по-своему.
6. **Журнал без меток времени** — длительность этапов и границы issue по
времени не восстановить. Метка времени была в дизайне live-log
(`2026-06-14-observability-design.md`) и потерялась, когда live-log «вырос
в журнал» (2026-07-03).
## Решения (пакет правок)
1. **Датированный факт среды вместо preflight-пробы.** В `SKILL.md` — короткая
врезка: «Среда Codex (проверено 2026-07-04): worker не может запускать
субагентов; ревьюеров запускает координатор». Не перепроверять каждый
прогон — только при сигнале обратного (например, `tool_search` нашёл spawn).
Гонять диагностику на каждой цепочке — жечь токены и время.
2. **Топология ревью: запуск у координатора, триаж у worker-а.**
- Координатор запускает reviewer-субагентов-**наблюдателей** и пересылает
worker-у индекс находок дословно, без своих интерпретаций (он не читает
код и судить не может). Наблюдатель — не read-only субагент: инструменты
полные (тесты, воспроизведение, поиск), ограничение «не менять репозиторий
и среду» держится промптом — как в `claude-team-review`.
- `claude-team-review` запускает только **владелец правок** — worker, в
средах, где worker может запускать субагентов. Координатору запускать
team-review нельзя: его лид чинит код сам, а это второй писатель в дереве
и слом границы «координатор кода не трогает». Под Codex механизм —
reviewer-субагент координатора с ревью-промптом; промпт адаптирован в
`references/reviewer-prompt.md` самого скилла (из `claude-team-review`) —
скилл самодостаточен, внешних файлов не требует.
- Триаж находок остаётся в worker-е: у него контекст кода и «зачем» из
контракта. Worker вправе аргументированно отклонить находку — через
контракт и тест, не голословно (приём из прогона).
- Бонус топологии: координатор видит зацикливание ревью (см. п.4).
- Цена: индексы ревью идут через контекст координатора, по кругу на каждый
rerun. Прямого замера этого трафика нет (июньские 2,6 КБ — замер
финальных отчётов worker-ов, не пер-раундового трафика ревью), но порядок
тот же — килобайты. Если на длинной цепочке начнёт пухнуть — готовый
фолбэк: файловый канал из `2026-06-14-observability-design.md` (ревьюер
пишет индекс в файл, координатору — путь и вердикт). Сейчас не вносим.
3. **Контракт ревьюеру** (новый, симметричен контракту worker-а): наблюдатель
с полными инструментами (ограничение «не менять репозиторий и среду» —
промптом), код читает сам и докладу worker-а не верит; возвращает
**индекс** — находка,
`файл:строка`, какой критерий нарушен, минимальный repro; вердикт одной
строкой (`APPROVED` / `CHANGES_REQUESTED`); запрет вставлять diff, полный
вывод тестов и нарратив рассуждений. Уровень мышления и модель задаёт
координатор при запуске (см. п.5).
4. **Политика кругов ревью.** Тождество находок между кругами судит не
координатор (по индексам оно не определяется — формулировки и `файл:строка`
между кругами плывут, что видно по прогону 07), а **worker в триаже**: если
ревьюер снова поднимает вопрос, который worker уже аргументированно
отклонял, worker помечает это в своём индексе флагом **«спор»** с отсылкой
к прежнему обоснованию. Координатор реагирует на флаг и на общий счётчик:
- **спор** → не общий rerun, а узкий гейт по спорному вопросу на усиленном
уровне (паттерн «xhigh narrow gate» из прогона);
- спор пережил и узкий усиленный гейт → **стоп, решение человека**;
- независимо от споров: больше **четырёх** кругов ревью на issue → стоп,
координатор выносит человеку вопрос «дробить issue или принимать риск»
(потолок взят по прогону 07 — пять кругов прошли без управления);
- rerun после правок по гейт-находкам назначает координатор автоматически —
это больше не concern worker-а (в прогоне дважды висело «rerun ещё не
выполнен»).
5. **Две ручки стоимости: модель по роли и уровень мышления.** Это разные оси,
не смешивать: «модель по роли» в скилле уже есть (дешёвая на task-lens,
сильная на финале), прогон же эскалировал **уровень рассуждений** (xhigh)
на той же модели. Вводим три относительных уровня без имён:
*экономный* (ступень вниз: task-lens ревью, диагностика, разбор логов),
*рабочий* (дефолт: worker, обычное code review), *усиленный* (ступень
вверх: эскалация по п.4, находки про межмодульные инварианты и форму
распределений, финальное chain-ревью — усиленный уровень на сильной
модели). Соответствие ролей конкретным моделям и уровням хоста — датированная
таблица `references/effort-levels.md`; логика скилла имён не знает. Дефолт —
рабочий уровень, вверх только по триггеру. Хост без управляемых уровней:
эскалация вырождается в «свежий субагент». Уровень фиксируется в записи
журнала о запуске ревью.
6. **Происхождение ревью пишет координатор в журнал** — в момент запуска и в
момент вердикта: режим, механизм, кто запускал, уровень, вердикт. Worker
больше не автор этой строки (факты «кто запускал» и «уровень» знает только
координатор); в индексе worker-а остаются саморевью и триаж (включая флаг
«спор»). Честная граница прежняя: журнал — самозапись координатора,
append-only след для внешней проверки; ложь в моменте ловит кросс-линия и
человек, не сам журнал.
7. **Метка времени в журнале.** Каждая запись начинается с `HH:MM` (дата — в
заголовке дня; время брать вызовом `date`, модель его не знает). Порог
записей прежний — точки записи из раздела «Журнал прогона»; мельче
(каждая команда, каждый прочитанный файл) не писать, чтобы метки не
превратили журнал в спам. Heartbeat worker-а в пакет **не входит**: журнал
пишет только координатор, файлового канала нет, а слать сигналы в контекст
координатора — противоречить его экономии. Если когда-нибудь вносим
файловый канал — heartbeat возвращается вместе с ним (дизайн готов в
observability-handoff).
8. **Статус-контракт: недоступность стендовой проверки ≠ `BLOCKED`.** Если
проверка (docker, стенд, сеть) недоступна в среде worker-а, он возвращает
`DONE_WITH_CONCERNS` с фактом («docker отсутствует: <вывод>») и **готовой
командой**, которую координатор прогоняет сам. `BLOCKED` — только про саму
работу. Оговорка по прогону: команда может не пройти и у координатора
(на коммит-гейте 11 `snap-confine` ломал dry-run в sandbox — перегоняли вне
sandbox); тогда координатор фиксирует в журнале, где и как проверка
прошла фактически. Случай «ревью недоступно worker-у» из контракта уходит
совсем — worker ревью больше не запускает (п.2).
9. **Дисциплина финала.**
- Обновить PRD/трекер **до** финального chain-ревью, чтобы оно проверяло
приведённое состояние (low finding прогона — предсказуемый класс).
- После коммит-гейта issue — `Status: done` в файле issue, **docs-коммитом
вместе с журналом**, не в feature-коммите. Это смена фактического
поведения (прогон 07/11 закрывал статусы внутри feature-коммитов):
файл issue — процессный, как и журнал, и на границе шага 6 «только файлы
worker-а» он файлом worker-а не считается.
- Финальный handoff обязателен для нетривиальной цепочки и является
**условием выхода из цикла**, а не пунктом-пожеланием; место и формат — по
конвенции репозитория (AGENTS.md / ADR), если она есть.
## Куда править
- `SKILL.md`:
- frontmatter `description` («с ревью через claude-team-review» — убрать);
- «Роли» — ревьюер: запускает координатор, наблюдатель, контракт по п.3;
- врезка про среду Codex (п.1);
- «Цикл» — шаги 4–6: приём индекса ревью, политика кругов и rerun (п.4),
происхождение в журнале (п.6), закрытие issue (п.9);
- «Журнал прогона» — метка времени (п.7), происхождение пишет координатор;
- «Контракт задания worker-у» — убрать запуск team-review worker-ом,
добавить триаж находок ревью + флаг «спор», статус-контракт по п.8;
- новый раздел «Контракт ревьюеру» (п.3);
- «Режимы ревью» — две ручки (модель по роли + уровень мышления), таблица
`references/effort-levels.md` (п.5);
- «Классификация находок» — триаж делает worker, не «team-review внутри
worker-а»;
- «Финал цепочки» — порядок: PRD/трекер → chain-ревью (усиленный уровень на
сильной модели) → handoff как условие выхода (п.9);
- чек-лист — привести к новым ролям (происхождение в журнале, уровни,
handoff обязателен, закрытие issue).
- `README.md`: строка потока и раздел «Что получается» («/goal + /tdd +
claude-team-review», «per-finding триаж делает claude-team-review внутри
worker-а»), «сильной моделью» в описании финала, раздел «Статус и что
дальше» — открытый вопрос «бюджет кругов ревью» закрывается п.4.
- `references/rationale.md`: датированная поправка 2026-07-04 — факт среды
Codex, боевое подтверждение вопросов про круги ревью, закрытие вопроса
«бюджет кругов» политикой п.4.
- `references/effort-levels.md`: новая датированная таблица уровней (п.5).
## Чего сознательно не делаем
- Файловый канал / `coordinator-runs/` — не вносим, зафиксирован как фолбэк
(п.2) и носитель heartbeat (п.7).
- Preflight-проба среды на каждый прогон — отвергнута (расход без пользы).
- Автоматизация кросс-линейного прохода — по-прежнему вне скилла.
- Замер чисел-ориентиров июня — не сделан в этом прогоне и не закрыт; снять
на следующей цепочке, пока сырьё в `~/.codex` не ротировалось.
## Suggested skills
- `conventional-commits` — коммиты в dotfiles.
- `coordinator-loop` — следующий боевой прогон (цепочка 12 или 08) как замер.
@@ -0,0 +1,35 @@
# Уровни мышления и модели по ролям
Обновлено: 2026-07-04. Логика скилла оперирует относительными уровнями
(экономный / рабочий / усиленный) и «моделью по роли»; здесь — привязка к
конкретным настройкам хостов. Вышла новая модель или переименовались уровни —
правится этот файл, не `SKILL.md`.
## Codex CLI (проверено на боевом прогоне 2026-07-04)
Ручка уровня — reasoning effort субагента (`low` / `medium` / `high` / `xhigh`).
| Роль | Уровень | Настройка |
|---|---|---|
| task-lens ревью, диагностика, разбор логов | экономный | ступень ниже дефолта сессии |
| worker, обычное code review | рабочий | дефолт сессии |
| узкий гейт по спору, финальное chain-ревью | усиленный | `xhigh` |
Модель по роли: во всех ролях — модель сессии; отдельной дешёвой модели для
субагентов в текущей конфигурации нет, экономия достигается уровнем.
## Claude Code (если прогон под этим хостом)
Ручки: effort субагента (`low` / `medium` / `high` / `xhigh` / `max`) и model
(`haiku` / `sonnet` / `opus`).
| Роль | Уровень | Настройка |
|---|---|---|
| task-lens ревью, диагностика, разбор логов | экономный | модель ступень ниже, effort `low`–`medium` |
| worker, обычное code review | рабочий | модель сессии, effort по умолчанию |
| узкий гейт по спору, финальное chain-ревью | усиленный | сильная модель, effort `xhigh`–`max` |
## Хост без управляемых уровней
Эскалация вырождается в запуск свежего субагента — слабее, но не пусто
(см. `SKILL.md`, «Режимы ревью»).
@@ -82,6 +82,16 @@ issue. Выводы — хороший сигнал для класса «пос
> наблюдаемость при обрыве, ретроспективную правку истории и handoff «по памяти»;
> ложь в момент события ловит только внешняя проверка (кросс-линия, человек).
> **Поправка 2026-07-04.** Боевой прогон цепочки 07 → 11 (генератор кликстрима) дал два
> уточнения. Первое — факт среды: в Codex worker не может запускать субагентов
> (проверено диагностом с `agent_type=worker`), поэтому топология изменена — ревьюеров
> запускает координатор, а триаж находок остаётся в worker-е (см. `SKILL.md` и handoff
> `2026-07-04-codex-topology-and-escalation.md`). Второе — вопросы про число кругов
> ревью из списка ниже стали боевыми: issue 07 прошёл пять кругов без ограничителя, а
> спор с ревьюером разрешил изобретённый по ходу «узкий гейт на xhigh». Ответ закреплён
> политикой кругов в `SKILL.md`: флаг «спор» в триаже worker-а, узкий гейт на усиленном
> уровне, потолок четыре круга на issue, дальше — человек.
## Чего не делать слепо
- Не запускать ревьюера после каждой мелкой правки — дорого и раздувает задачу.
@@ -99,5 +109,7 @@ issue. Выводы — хороший сигнал для класса «пос
- как заранее понять, что задаче нужен отдельный ревьюер, а не только саморевью;
- стоит ли заранее обязывать worker-а к промежуточным отчётам на статистике и
долгих тестах;
- нужно ли явно ограничивать бюджет worker-а и число кругов ревью;
- как формализовать порог «большое исправление требует второго круга».
- нужно ли явно ограничивать бюджет worker-а (число кругов ревью закрыто политикой
кругов — поправка 2026-07-04);
- как формализовать порог «большое исправление требует второго круга» (частично
закрыто: rerun после правок по гейт-находкам координатор назначает автоматически).
@@ -0,0 +1,116 @@
# Шаблон промпта ревьюеру
Координатор заполняет плейсхолдеры и передаёт текст как промпт
reviewer-субагенту. Адаптирован из `reviewer-prompt.md` скилла
`claude-team-review` (2026-07-04) под топологию coordinator-loop: чинящего
лида здесь нет — правит worker по индексу находок, круги считает координатор.
---
## Шаблон
```text
Ты — старший адверсарный ревьюер. Твоя работа — подорвать доверие к изменению,
а не подтвердить его. Скепсис по умолчанию: считай, что в работе есть дыры,
пока доказательства не показали обратное. Не засчитывай добрые намерения и
«допилят следом». Работает только на happy path — это настоящая слабость.
## Фокус проверки
{FOCUS}
# по коду — тонкие баги, межмодульные инварианты, форма распределений
# по задаче — сделано ли то, что требует issue/спека (acceptance criteria)
# узкий гейт — только спорный вопрос: {SPOR_SUMMARY}
# chain — вся реализация цепочки против исходной спеки/PRD (дрейф целого)
## Что проверяем
{ARTIFACT}
# для issue: текст issue, ссылки на PRD/спеку/смежное — «зачем».
# Работа worker-а НЕ закоммичена: смотри рабочее дерево целиком —
# `git status --short` (новые файлы untracked, в diff их нет!) плюс
# `git diff`; закоммиченная история — контекст, не объект ревью
# для chain: ключевые пути реализации + исходная спека/PRD;
# объект — закоммиченная реализация цепочки
## Круг
{ROUND} # 1 — первичное ревью; N — rerun после правок worker-а
{PREVIOUS_FINDINGS_BLOCK}
# Только на rerun (свежий субагент не знает прошлого круга): дословно находки
# прошлого круга; что worker исправил; что отклонил и с каким обоснованием
# (контракт/тест). Отклонённое оценивай по существу: обоснование верно —
# признай; неверно — переформулируй находку с контраргументом и новым
# доказательством, а не повторением прежней формулировки.
## Что можно
- Читать любые файлы репозитория; git-историю, диффы, ветки.
- Запускать команды: тесты, линтеры, сборку, воспроизведение находок.
- Искать в сети и документации (Context7) для проверки предположений.
## Что нельзя
- Создавать, менять или удалять файлы проекта; менять среду (git-операции с
записью, установка пакетов, правка конфигов).
- Чинить находки — это работа worker-а. Ты аудитор, не участник.
## Планка находки
Каждая находка отвечает на четыре вопроса:
1. Что сломается? — конкретный сценарий, не гипотеза.
2. Почему уязвимо? — `файл:строка` или раздел.
3. Последствия — что и насколько плохо (потеря данных > простой > деградация).
4. Рекомендация — конкретный фикс, достаточный worker-у для работы.
Вне скоупа: стиль и нейминг; спекуляции без конкретного сценария; «неплохо
бы» без связи с корректностью или безопасностью.
Перед докладом верифицируй находку: прогони тесты, сверь документацию,
воспроизведи путь. Одна проверенная находка стоит десяти догадок; ссылки на
доки и upstream-issue давай точно — их проверят.
## Калибровка
- Одна сильная находка лучше нескольких слабых.
- Серьёзность: critical (данные/безопасность) > high (баг в проде) >
medium (крайний случай).
- Работа крепкая — так и скажи: ложные тревоги подрывают доверие.
## Формат ответа — индекс, не нарратив
**Findings:** на каждую — `[severity]`, `файл:строка`, какой критерий нарушен,
минимальный repro, рекомендация. Без diff, без полного вывода тестов, без
нарратива рассуждений. Нет находок — «No actionable findings».
Последняя строка ответа — ровно одна из:
VERDICT: APPROVED
VERDICT: CHANGES_REQUESTED
APPROVED — находок нет или все medium без нарушения acceptance criteria.
CHANGES_REQUESTED — есть high/critical или нарушен критерий issue/спеки.
## Язык
Отвечай на русском. Severity, заголовки полей и строку VERDICT оставляй
латиницей как есть.
```
---
## Заметки по запуску
- Координатор собирает бриф сам — ревьюер не наследует историю сессии;
передавай только нужное.
- Модель и уровень мышления — по [effort-levels.md](effort-levels.md):
обычное ревью — рабочий уровень, узкий гейт по спору и chain-ревью —
усиленный на сильной модели.
- **Не запускай ревьюера в урезанном/read-only субагенте**: тесты и
воспроизведение требуют исполнения команд. Ограничение «не менять
репозиторий и среду» держит промпт (раздел «Что нельзя») — как в
`claude-team-review`.
- На узком гейте `{SPOR_SUMMARY}` — формулировка спора из индекса worker-а
(находка + его обоснование отклонения) дословно, без интерпретаций
координатора.