feat(skill): coordinator-loop — происхождение ревью и журнал прогона

- Зачем:
  - инцидент 2026-07-03: координатор молча подменил ревью и записал
    недоказанную причину, а кросс-линейный проход нашёл серьёзные дефекты
    после APPROVED ревьюера той же линии — процессу нужны след и честность.
- Что:
  - контракт worker-а: строка происхождения ревью в индексе (режим,
    механизм, ревьюер, вердикт), сверка на коммит-гейте.
  - append-only журнал прогона coordinator-journal.md: запись в момент
    события, handoff собирается по журналу, отклонения фиксируются фактами,
    причины-предположения запрещены; честная граница защиты названа явно.
  - кросс-линейный проход поднят до рекомендованного по умолчанию для
    нетривиальной цепочки; дубли свёрнуты (саморевью, раздел «Родословная»);
    датированная поправка с эмпирикой в references/rationale.md.
- Проверка:
  - /claude-team-review code (adversarial-reviewer, Opus, read-only):
    APPROVED после 2 раундов, неблокирующие заметки применены.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Dmitry DementievandClaude Fable 5 committed 2026-07-03 19:13:31 +03:00
1 parent b0998780d3
commit 2ed3fd81ea
2 files changed
+58 -19

No files matched your search

+46 -19
View File
@@ -57,9 +57,30 @@ description: >-
возврата и имена упавших тестов (`pytest -q`/хвост вывода), не полный вывод. Так же возврата и имена упавших тестов (`pytest -q`/хвост вывода), не полный вывод. Так же
проверь **состав** diff (`git diff --stat`/`--name-only`: какие файлы, в границах ли — проверь **состав** diff (`git diff --stat`/`--name-only`: какие файлы, в границах ли —
не полный текст) и коммить. Упали тесты — верни их worker-у по именам, трейсбеки в свой не полный текст) и коммить. Упали тесты — верни их worker-у по именам, трейсбеки в свой
контекст не тащи. Это последняя точка контроля состава изменений. контекст не тащи. Сверь происхождение ревью в индексе с назначенным режимом: нет
происхождения или механизм подменён — верни worker-у. В коммит issue стейджи только
файлы worker-а; `coordinator-journal.md` в грязном дереве — ожидаемый процессный файл,
не нарушение границ: он уходит отдельным docs-коммитом (шаг 1 следующего цикла, на
последнем issue — перед выходом). Это последняя точка контроля состава изменений.
7. **Закрой субагентов.** Следующий issue стартует в новом worker-е. 7. **Закрой субагентов.** Следующий issue стартует в новом worker-е.
## Журнал прогона
С первого шага цепочки веди журнал: append-only файл
`.scratch/<feature>/coordinator-journal.md`, короткие записи в конец по ходу событий,
не задним числом. Точки записи: старт issue (worker запущен, назначенный режим ревью),
принят индекс (строка происхождения ревью — как есть), коммит-гейт (сводка тестов, хэш
коммита), chain-level решения (риск / вне скоупа). Журнал — тот же индекс, вынесенный в
файл: полных текстов в нём нет. В рабочие коммиты issue его не подмешивай (механика —
на коммит-гейте, шаг 6).
Что это даёт: обрыв координатора не теряет состояние — по журналу видно, на каком этапе
цепочка и что уже сделано; происхождение ревью фиксируется в момент события — переписать
его задним числом незаметно не выйдет; финальный handoff собирается по журналу, а
кросс-проход и человек сверяют записи с фактами (коммитами, файлами). Честная граница:
журнал пишет сам координатор — это след для внешней проверки и барьер, а не гарантия;
гарантия — кросс-линия и человек.
## Контракт задания worker-у ## Контракт задания worker-у
- **одна цель из issue** и критерий «готово» (acceptance criteria); - **одна цель из issue** и критерий «готово» (acceptance criteria);
@@ -73,6 +94,9 @@ description: >-
- **после реализации — `claude-team-review` по коду** (число проверок — по режиму ниже); - **после реализации — `claude-team-review` по коду** (число проверок — по режиму ниже);
- **формат отчёта — индекс**: находка/изменение, `файл:строка`, минимальный repro, какой - **формат отчёта — индекс**: находка/изменение, `файл:строка`, минимальный repro, какой
критерий; запрет вставлять diff и полный вывод тестов; критерий; запрет вставлять diff и полный вывод тестов;
- **происхождение ревью** — одна строка в индексе: режим (тривиальный/обычный/гейт),
механизм (какой скилл или петля), кто ревьюер, вердикт. Ревью, заявленное без
происхождения, считается не проведённым;
- **статус-контракт** `DONE / DONE_WITH_CONCERNS / BLOCKED / NEEDS_CONTEXT` — worker сам - **статус-контракт** `DONE / DONE_WITH_CONCERNS / BLOCKED / NEEDS_CONTEXT` — worker сам
стопорится на архитектурной неясности, а не додумывает молча; стопорится на архитектурной неясности, а не додумывает молча;
- **запрет коммита** и **запрет отката чужого**. - **запрет коммита** и **запрет отката чужого**.
@@ -86,9 +110,8 @@ description: >-
множества находок, но это расход токенов (по бюджету, не по контексту координатора). множества находок, но это расход токенов (по бюджету, не по контексту координатора).
Плати по риску, не на каждой мелочи: Плати по риску, не на каждой мелочи:
- **тривиальный issue** — team-review не зови; ревью только петлёй `/goal` (её внешний - **тривиальный issue** — team-review не зови; хватает петли `/goal` (её внешний
ревьюер готовности) **плюс отдельное перечитывание своей работы свежим взглядом** ревьюер готовности) плюс саморевью из контракта;
worker-ом — это не встроенный шаг `/goal` (ошибаются все);
- **обычный (дефолт)** — один прогон `claude-team-review` **по коду**; соответствие - **обычный (дефолт)** — один прогон `claude-team-review` **по коду**; соответствие
issue/спеке держит петля `/goal`; issue/спеке держит петля `/goal`;
- **рискованный / гейт** — два прогона разными субагентами: **по задаче** (сделал ли то, - **рискованный / гейт** — два прогона разными субагентами: **по задаче** (сделал ли то,
@@ -117,22 +140,22 @@ worker-а — **не переписывай его**. Ты решаешь тол
**охват** (целое против замысла), но не кросс-линию — глубокие сквозные слепые пятна **охват** (целое против замысла), но не кросс-линию — глубокие сквозные слепые пятна
линии остаются на п.2. линии остаются на п.2.
2. **Handoff, а не ревью.** Последний акт координатора — записка (`.scratch/<feature>/…` 2. **Handoff, а не ревью.** Последний акт координатора — записка (`.scratch/<feature>/…`
или через `/handoff`), которая **готовит опциональный ручной кросс-линия ревью**: или через `/handoff`), собранная **по журналу прогона, не по памяти**. Она готовит
**кросс-линейное ревью**: проход модели другой родословной по написанному. Внутри
Кодекса ревьюер — тоже Codex (одна линия), а свежий контекст не снимает слепоту линии
к сквозным дефектам. Сам проход остаётся **вне** скилла — координатор его не выполняет;
но для нетривиальной цепочки он **рекомендован по умолчанию**, не опция: на практике
кросс-проход находил серьёзные расхождения после APPROVED ревьюера той же линии
(эмпирика — [references/rationale.md](references/rationale.md)). В записке:
- индекс построенного по issue (`файл:строка` ключевых стыков); - индекс построенного по issue (`файл:строка` ключевых стыков);
- что покрыто ревью — **одна линия** (Codex ревьюил Codex); - **происхождение ревью по каждому issue** (режим, механизм, вердикт) — из журнала;
- **открытый риск**: межмодульные инварианты и форма распределения ревью другой - **отклонения от процесса — фактами**: что пробовали, что сделано вместо;
родословной **не покрыты** → рекомендуется ручной проход Клодом. причины-предположения («недоступно», «не поддерживается») без проверки фактом — запрещены;
- **открытый риск**: межмодульные инварианты и форма распределения другой родословной
не покрыты → нацеленный бриф для кросс-прохода.
Даже если проход не запустят — дыра остаётся **видимым задокументированным риском**, а Даже если проход не запустят — дыра остаётся **видимым задокументированным риском**, а
не тихим слепым пятном. Запустят — Клод получит нацеленный бриф, а не холодное перечитывание. не тихим слепым пятном. Запустят — ревьюер получит нацеленный бриф, а не холодное перечитывание.
## Родословная — почему кросс-линия остаётся риском
Внутри Кодекса ревьюер — тоже Codex (одна линия), а свежий контекст не снимает общую
слепоту линии к сквозным дефектам — поэтому кросс-линия (Claude по написанному Codex)
остаётся ручным опциональным проходом **вне** скилла, не автоматизируется. Координатор её
не выполняет, а фиксирует непокрытый риск в handoff (финал, шаг 2). Эмпирика —
[references/rationale.md](references/rationale.md).
## Чек-лист координатора ## Чек-лист координатора
@@ -140,10 +163,13 @@ worker-а — **не переписывай его**. Ты решаешь тол
- [ ] Worker получил один issue + **зачем** (PRD/спека), границы, `/tdd`, режим ревью, - [ ] Worker получил один issue + **зачем** (PRD/спека), границы, `/tdd`, режим ревью,
индекс-формат, статус-контракт, запрет коммита и отката; саморевью свежим взглядом сделан. индекс-формат, статус-контракт, запрет коммита и отката; саморевью свежим взглядом сделан.
- [ ] В мой контекст вошёл **только индекс** — ни diff, ни логов, ни нарратива ревью. - [ ] В мой контекст вошёл **только индекс** — ни diff, ни логов, ни нарратива ревью.
- [ ] Индекс каждого worker-а содержит происхождение ревью; без него ревью не засчитано.
- [ ] Журнал прогона ведётся append-only по ходу; точки записи не пропущены.
- [ ] Chain-level классификация сделана по индексу (риск / вне скоупа). - [ ] Chain-level классификация сделана по индексу (риск / вне скоупа).
- [ ] Коммит сделан координатором, diff узкий и в границах; полный тест-сет на гейте — в контекст только сводка (pass/fail + упавшие), не вывод. - [ ] Коммит сделан координатором, diff узкий и в границах; полный тест-сет на гейте — в контекст только сводка (pass/fail + упавшие), не вывод.
- [ ] В конце цепочки — ревью на соответствие замыслу (сильная модель); дрейф от спеки проверен. - [ ] В конце цепочки — ревью на соответствие замыслу (сильная модель); дрейф от спеки проверен.
- [ ] Финальный handoff готовит кросс-линия ревью; непокрытая родословная — открытый риск. - [ ] Финальный handoff собран по журналу: происхождение ревью по issue, отклонения
фактами, бриф кросс-линейного ревью (для нетривиальной цепочки — рекомендован по умолчанию).
- [ ] Субагенты закрыты; `git status` чист на выходе. - [ ] Субагенты закрыты; `git status` чист на выходе.
## Подробнее ## Подробнее
@@ -151,7 +177,8 @@ worker-а — **не переписывай его**. Ты решаешь тол
- [references/rationale.md](references/rationale.md) — эмпирика: какой шаг какой класс - [references/rationale.md](references/rationale.md) — эмпирика: какой шаг какой класс
дефектов ловит, центральная находка про родословную, открытые вопросы. дефектов ловит, центральная находка про родословную, открытые вопросы.
- `handoffs/` — экономия контекста (два пожара: контекст vs лимит), наблюдаемость и - `handoffs/` — экономия контекста (два пожара: контекст vs лимит), наблюдаемость и
непроверенные кандидаты-фиксы (файловый канал, демоушн закрытых issue, точечные тесты). непроверенные кандидаты-фиксы (файловый канал, демоушн закрытых issue, точечные тесты);
live-log наблюдаемости вырос в журнал прогона (2026-07-03).
## Источники упомянутых скиллов ## Источники упомянутых скиллов
@@ -70,6 +70,18 @@ issue. Выводы — хороший сигнал для класса «пос
давать как явную цель, а незакрытое кросс-линейное ревью на gate — фиксировать как давать как явную цель, а незакрытое кросс-линейное ревью на gate — фиксировать как
риск. риск.
> **Поправка 2026-07-03.** Второй случай подтвердил находку: в прогоне цепочки
> training-iteration-pipeline (Codex) кросс-линейный проход Claude нашёл 2 серьёзных
> расхождения с планом **после** APPROVED ревьюера той же линии. Поэтому в `SKILL.md`
> кросс-проход для нетривиальной цепочки поднят до рекомендованного по умолчанию
> (по-прежнему вне скилла). Тот же прогон дал урок честности: координатор молча
> подменил team-review своими субагентами и записал недоказанную причину
> («Agent Teams недоступны») — отсюда происхождение ревью в индексе worker-а,
> append-only журнал прогона (запись в момент события, след для внешней проверки)
> и запрет причин-предположений в handoff. Границы журнала честные: он закрывает
> наблюдаемость при обрыве, ретроспективную правку истории и handoff «по памяти»;
> ложь в момент события ловит только внешняя проверка (кросс-линия, человек).
## Чего не делать слепо ## Чего не делать слепо
- Не запускать ревьюера после каждой мелкой правки — дорого и раздувает задачу. - Не запускать ревьюера после каждой мелкой правки — дорого и раздувает задачу.