режимы прогона: ревью параллельно, батч — по одной задаче

Умолчания разошлись по цене шага. Проход ревью читает и рассуждает: он
ничего не поднимает, ни за что не дерётся и по построению не видит
выводов соседа — очередь между проходами добавляет только ожидание.
Задача батча тянет полный цикл пайплайна с гейтом, поднятием сервиса и
вложенным ревью — две такие дерутся за порты, каталоги и железо.

review-pipeline: параллельно внутри стадии — умолчание. Последовательно —
по трём причинам с именем в отчёте: сказал оператор, проходы меряют,
машина занята. Просьба «последовательно» набора не требует. Меряющая пара
adversary + ops стала именованным исключением: она идёт по очереди
всегда, и общее «гони параллельно» этого не отменяет. Ранний выход
переехал на границу стадии.

task-batch: план собирается графом зависимостей и в умолчании
линеаризуется. Параллельно — по просьбе, и просьба разрешает ширину
графа, а не «всё разом»; потолок 2–3 и одиночная волна замеряющей задачи
сохранены как правила этого режима. Режим ревью внутри задачи выводится
из режима батча и называется в charter'е. Финальная сверка гонит
review-specs по capability параллельно.

DECISIONS 14 — с причиной; версия канона не меняется, канон этих скиллов
не описывает.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
av
2026-08-03 20:04:54 +03:00
co-authored by Claude Opus 5
parent 67cfa45162
commit d5cffb2e08
5 changed files with 216 additions and 106 deletions
+53
View File
@@ -941,3 +941,56 @@ HTML-комментарии, невидимые в отрендеренном ma
индекса — переименование не трогает механику, только умолчание и тексты. индекса — переименование не трогает механику, только умолчание и тексты.
55. **Метафора — плохое имя для секции индекса.** Секция читается человеком без 55. **Метафора — плохое имя для секции индекса.** Секция читается человеком без
контекста, часто из вывода `list`, и второго шанса объяснить себя у неё нет. контекста, часто из вывода `list`, и второго шанса объяснить себя у неё нет.
## 14. Умолчания режимов прогона перевёрнуты (2026-08-03)
### Что было
Оба скилла держали одно и то же умолчание — «по очереди», — хотя цена очереди у
них разная. `review-pipeline` гнал проходы последовательно и требовал для
параллельности **двух** условий (явная просьба **и** поимённо названный набор).
`task-batch`, наоборот, планировал волны параллельных задач с потолком 2–3 и
считал параллельность нормой прогона.
Перепутаны оказались уровни. Проход ревью — чтение и рассуждение: он ничего не
поднимает, ни за что не дерётся и по построению не видит выводов соседа. Задача
батча — полный цикл пайплайна: гейт, поднятие сервиса вживую, вложенное ревью,
общие порты и рабочие каталоги. Дешёвое стояло в очереди, дорогое гонялось разом.
### Решено
**UU. В ревью умолчание — параллельно.** Стадии по-прежнему идут по порядку,
параллельность касается только проходов внутри стадии. Последовательно гоняем по
трём особым причинам, и каждая называется в отчёте: сказал оператор; проходы
меряют; машина занята — причём занятость видит вызывающий, а не конвейер. Просьба
«гони последовательно» **набора не требует**: очередь ничего не портит, она
только дольше, и домысливать тут нечего — в отличие от прежнего правила, где
неназванный набор блокировал отступление.
**VV. Меряющая пара — правило стадии, а не решение прогона.** `adversary` и `ops`
идут по очереди всегда: оба доказывают находки числами и оба меряют одно железо, а
испорченный оракул хуже отсутствующего. Общее «гони параллельно» этого не
отменяет; отменяет только прямое слово оператора **про эту пару**, и тогда в
границы покрытия идёт строка про замеры под соседней нагрузкой.
**WW. В батче умолчание — по одной задаче, параллельность — по графу
зависимостей.** План собирается как граф (рёбра — жёсткие зависимости и
сериализуемые пересечения) и в умолчании линеаризуется в один порядок. Просьба
«гони параллельно» разрешает использовать **ширину графа**, а не гнать всё разом:
потолок 2–3, замеряющая задача — волной по одной. Прежние правила волн сохранены
целиком, они просто перестали быть умолчанием.
### Что из этого следует
56. **Режим батча задаёт режим ревью внутри задачи, и его называет charter.**
Батч идёт по одной — машина свободна, сабагент гонит проходы параллельно;
батч идёт волнами — сабагенту предписан последовательный режим с этой самой
причиной. Сабагент своего соседа не видит, поэтому решать это ему нельзя.
57. **Ранний выход из ревью переехал на границу стадии.** Стадии идут по порядку
в любом режиме, так что остановиться между ними можно всегда; остановка
**внутри** стадии осталась побочной выгодой последовательного режима — но не
поводом его выбирать.
58. **Цена параллельного батча проверяется до первой волны.** Тесты, делящие
фиксированный порт или файл БД, и проект, умеющий поднимать один экземпляр, —
основание гнать по одной даже после просьбы, сказанное строкой: просьба была
про параллельность, а не про сломанные тесты.
+50 -47
View File
@@ -1,6 +1,6 @@
--- ---
name: review-pipeline name: review-pipeline
description: Конвейер ревью изменения — детерминированный гейт, сверка с дельта-спеками в обе стороны, враждебные постановки и эксплуатационный постмортем, независимая реализация по триггеру, архитектура и обязательный триаж. Проходы гонятся последовательно; параллельно — только по явной просьбе и с явно названным набором. Проектная специфика приходит из документов канона av-dev-pm. Вызывается из task-pipeline (чекпоинты ревью), из task-batch (финальная сверка) и отдельно — профилем design на предложении ДО кода. description: Конвейер ревью изменения — детерминированный гейт, сверка с дельта-спеками в обе стороны, враждебные постановки и эксплуатационный постмортем, независимая реализация по триггеру, архитектура и обязательный триаж. Проходы внутри стадии гонятся параллельно; последовательно — по особой причине (меряющая пара, занятая машина) или по слову оператора. Проектная специфика приходит из документов канона av-dev-pm. Вызывается из task-pipeline (чекпоинты ревью), из task-batch (финальная сверка) и отдельно — профилем design на предложении ДО кода.
--- ---
# Конвейер ревью # Конвейер ревью
@@ -183,44 +183,42 @@ description: Конвейер ревью изменения — детермин
| Режим | Как | Когда | | Режим | Как | Когда |
|---|---|---| |---|---|---|
| **последовательно** (умолчание) | по одному, следующий стартует после отчёта предыдущего | всегда, пока не попросили иначе | | **параллельно** (умолчание) | проходы стадии — одним сообщением | всегда, пока не сработала особая причина |
| **параллельно** | названные проходы — одним сообщением | только по явной просьбе **и** с явно названным набором | | **последовательно** | по одному, следующий стартует после отчёта предыдущего | по слову оператора **или** по одной из особых причин ниже |
**Умолчание — последовательно, и его не надо обосновывать.** Обосновывается **Умолчание — параллельно, и его не надо обосновывать.** Обосновывается
отступление. отступление. Проходы независимы по построению: ни один не видит выводов другого
(см. ниже), у всех общий вход и разные критерии. Очередь между ними не добавляет
ничего, кроме ожидания, — а ожидание на каждом чекпоинте ревью платится каждой
задачей.
**Параллельный режим включается при двух условиях сразу**, и второе так же **Последовательно гоним в трёх случаях, и каждый называется в отчёте:**
обязательно, как первое:
1. **о нём попросили явно** — «гони параллельно», а не «сделай побыстрее»; 1. **сказал оператор** — «гони последовательно». Набор при этом называть не
2. **названо, что именно гнать параллельно** — поимённый набор проходов обязательно: последовательный прогон ничего не портит, он только дольше, и
`specs` и `code` параллельно») или стадия целиком («стадию 1 параллельно»). домысливать тут нечего;
2. **проходы меряют.** `adversary` и `ops` доказывают находки числами: время
удержания блокировки против её таймаута, пик кучи против размера тела, темп
роста файлов журнала, длительность транзакции. Два меряющих прохода на одной
машине соревнуются за диск, CPU и за саму СУБД и выдают числа, которые не
воспроизведутся. Это не гипотеза: правило выведено из находок, целиком
державшихся на таких замерах, — у каждого проекта они свои и лежат в журнале
`docs/review.md`. Число, снятое под конкурентную нагрузку от соседнего
прохода, — это находка с испорченным оракулом, а её опровержение стоит дороже
всего выигрыша от параллельности. **Эта пара идёт по очереди всегда** — это
правило стадии 2, а не решение прогона (см. её раздел);
3. **машина занята, и знает об этом вызывающий.** Рядом идёт другая задача,
поднят сервис, гоняется гейт или дорогая проверка проекта. Сам конвейер
занятости машины не видит — её обязан назвать тот, кто запускает; так и
делает `av-dev-pipeline:task-batch`, когда ведёт задачи параллельно.
Просьба без набора — **не основание**: гоним последовательно и одной строкой Отдельная причина, не связанная со стоимостью, — **разбор самого конвейера**:
говорим, что набор не был назван. Это не придирка к формулировке. Параллелить когда выясняется, почему проход чего-то не нашёл, порядок и изоляция важнее
можно ровно то, что не мешает друг другу, а знание об этом лежит у того, кто скорости.
просит: он видит, занята ли машина, и ждёт ли он от прогона замеров. Домысливать
набор за него — значит принять решение, которое он оставил себе.
Почему умолчание именно такое: Если меряющие проходы всё же пошли разом — а это бывает только по прямому слову
оператора, — в границы покрытия идёт строка: какие проходы шли одновременно и
- **Замеры.** Проходы `adversary` и `ops` доказывают находки числами: время что замеры этого прогона как оракул слабее.
удержания блокировки против её таймаута, пик кучи против размера тела, темп
роста файлов журнала, длительность транзакции. Два меряющих прохода на одной
машине соревнуются за диск, CPU и за саму СУБД и выдают числа, которые не
воспроизведутся. Это не гипотеза: правило выведено из находок, целиком
державшихся на таких замерах, — у каждого проекта они свои и лежат в журнале
`docs/review.md`. Число, снятое под конкурентную нагрузку от соседнего
прохода, — это находка с испорченным оракулом, а её опровержение стоит дороже
всего выигрыша от параллельности.
- **Машина одна.** Рядом идёт задача, поднят сервис, гоняется гейт или дорогая
проверка проекта.
- **Ранний выход** возможен только при последовательном прогоне (см. ниже).
- **Разбор самого конвейера.** Когда выясняется, почему проход чего-то не нашёл,
порядок и изоляция важнее скорости.
Если параллельный режим всё же включён, в границы покрытия идёт строка: какие
проходы шли разом и что замеры, снятые в этом прогоне, как оракул слабее.
**Чего режим не меняет — и это не подлежит обсуждению.** Проход **не видит** **Чего режим не меняет — и это не подлежит обсуждению.** Проход **не видит**
находок других проходов ни в каком режиме. «Последовательно» значит «по находок других проходов ни в каком режиме. «Последовательно» значит «по
@@ -231,15 +229,17 @@ description: Конвейер ревью изменения — детермин
маскируется под независимое подтверждение. Единственный, кто видит всё, — триаж, маскируется под независимое подтверждение. Единственный, кто видит всё, — триаж,
и это его работа. и это его работа.
**Ранний выход** (последовательный режим делает его возможным — это его побочная **Ранний выход — по границе стадии.** Стадии идут по порядку в любом режиме,
выгода, а не повод его выбирать). Допустимо остановить прогон, не докатив поэтому остановиться между ними можно всегда; последовательный режим добавляет к
остаток, ровно в одном случае: находка требует **переделки формы** изменения, и этому возможность остановиться **внутри** стадии — это его побочная выгода, а не
повод его выбирать. Допустимо остановить прогон, не докатив остаток, ровно в
одном случае: находка требует **переделки формы** изменения, и
остальные проходы будут смотреть на код, которого через час не станет. Тогда: остальные проходы будут смотреть на код, которого через час не станет. Тогда:
- прогон останавливается, находка чинится, конвейер запускается **заново с - прогон останавливается, находка чинится, конвейер запускается **заново с
нулевой стадии** — а не «доезжает» остатком по старому коду; нулевой стадии** — а не «доезжает» остатком по старому коду;
- незапущенные проходы идут в границы покрытия строкой «не запускался: прогон - незапущенные проходы идут в границы покрытия строкой «не запускался: прогон
остановлен на <проход> из-за <находка>», поимённо; остановлен на <проход или стадия> из-за <находка>», поимённо;
- триаж запускается только на полном прогоне. Отчёт триажа по половине проходов - триаж запускается только на полном прогоне. Отчёт триажа по половине проходов
выглядит полным, потому что агрегирует всё, что ему подали, — это тот же выглядит полным, потому что агрегирует всё, что ему подали, — это тот же
молчащий пропуск, что и в разделе «Профили». молчащий пропуск, что и в разделе «Профили».
@@ -248,8 +248,9 @@ description: Конвейер ревью изменения — детермин
(`Действие: инлайн`), **не делается**: дешевле дособрать все находки и починить (`Действие: инлайн`), **не делается**: дешевле дособрать все находки и починить
пачкой, чем гонять конвейер дважды. пачкой, чем гонять конвейер дважды.
Режим объявляется в отчёте наравне с профилем, и если он **параллельный**с Режим объявляется в отчёте наравне с профилем. Параллельный — одним словом.
причиной и составом. Последовательный объявляется одним словом. **Последовательный — с причиной** (какой именно из трёх) и с составом, если по
очереди шла только часть проходов.
## Стадия 0 — Gate (обязательна во всех профилях) ## Стадия 0 — Gate (обязательна во всех профилях)
@@ -275,8 +276,8 @@ description: Конвейер ревью изменения — детермин
## Стадия 1 — Conformance (обязательна во всех профилях) ## Стадия 1 — Conformance (обязательна во всех профилях)
Два applicative-прохода: оба применяют **записанный** критерий, оба дешёвые. Два applicative-прохода: оба применяют **записанный** критерий, оба дешёвые.
Замеров они не делают и потому безобиднее прочих, если параллельный режим Замеров они не делают и не мешают друг другу ничем — это канонический случай
попросят с их именами; сами по себе идут по очереди, как и все. умолчания: оба уходят одним сообщением.
- `review-specs` — критерий взят из **дельта-спек предлагаемого изменения**, а не - `review-specs` — критерий взят из **дельта-спек предлагаемого изменения**, а не
из proposal, сообщения коммита или описания задачи. Сверка двунаправленная; из proposal, сообщения коммита или описания задачи. Сверка двунаправленная;
@@ -296,11 +297,13 @@ Recall обоих равен длине их источника — это и е
- `review-adversary` — находка есть **построенный путь**, а не свойство; - `review-adversary` — находка есть **построенный путь**, а не свойство;
- `review-ops` — постмортем от симптома у владельца сервиса к строке кода. - `review-ops` — постмортем от симптома у владельца сервиса к строке кода.
**Эту пару параллелить не стоит даже по просьбе — переспроси.** Оба доказывают **Эта пара — именованное исключение из умолчания: она идёт по очереди всегда.**
находки замером, и оба меряют одно и то же железо. Запущенные разом, они портят Оба доказывают находки замером, и оба меряют одно и то же железо. Запущенные
числа друг другу, а испорченный оракул хуже отсутствующего: находка выглядит разом, они портят числа друг другу, а испорченный оракул хуже отсутствующего:
доказанной. Если их всё же назвали в параллельном наборе — выполняй, но скажи в находка выглядит доказанной. Очередь здесь не обосновывается — она правило
границах покрытия, что числа этого прогона сняты под соседней нагрузкой. стадии, и на общее «гони параллельно» не отменяется. Если оператор прямо велел
гнать разом **и эту пару** — выполняй, но скажи в границах покрытия, что числа
этого прогона сняты под соседней нагрузкой.
**Эта стадия зарабатывает больше всех остальных вместе, и потому стоит в **Эта стадия зарабатывает больше всех остальных вместе, и потому стоит в
`standard`, а не только в `deep`.** Измерено на пяти задачах подряд: враждебный `standard`, а не только в `deep`.** Измерено на пяти задачах подряд: враждебный
@@ -98,9 +98,8 @@
- **готовые оракулы** — выборка по пометке `пойман ревью`: находка того же - **готовые оракулы** — выборка по пометке `пойман ревью`: находка того же
класса подтверждается ссылкой на запись, а не рассуждением; класса подтверждается ссылкой на запись, а не рассуждением;
- **основание для правил конвейера** — требование называть запущенные проходы - **основание для правил конвейера** — требование называть запущенные проходы
поимённо, отказ от чисел, производных от размера корпуса, и правило поимённо, отказ от чисел, производных от размера корпуса, и правило очереди для
последовательного прогона выведены из конкретных записей, а не из общих меряющих проходов выведены из конкретных записей, а не из общих соображений;
соображений;
- **счётчик обратимости решений** — сузили состав проходов и через месяц поймали - **счётчик обратимости решений** — сузили состав проходов и через месяц поймали
дефект ровно того класса, который перестали проверять: решение пересматривается дефект ровно того класса, который перестали проверять: решение пересматривается
фактом, а не спором. фактом, а не спором.
+105 -50
View File
@@ -1,6 +1,6 @@
--- ---
name: task-batch name: task-batch
description: Проводит несколько задач разом — планирует порядок и пересечения, гонит каждую задачу отдельным сабагентом в своём git worktree через task-pipeline, интегрирует по одной ветке через rebase + fast-forward (линейная история), проверяет полноту ревью каждой ветки и в конце сверяет стыки, возникшие от слияния. Набор задач приходит извне. Использовать, когда просят сделать несколько задач сразу. description: Проводит несколько задач разом — планирует порядок и пересечения, гонит каждую задачу отдельным сабагентом в своём git worktree через task-pipeline (по умолчанию по одной задаче за раз; параллельно по графу зависимостей — по явной просьбе), интегрирует по одной ветке через rebase + fast-forward (линейная история), проверяет полноту ревью каждой ветки и в конце сверяет стыки, возникшие от слияния. Набор задач приходит извне. Использовать, когда просят сделать несколько задач сразу.
--- ---
# Батч задач # Батч задач
@@ -11,6 +11,11 @@ description: Проводит несколько задач разом — пл
и делает финальную сверку. Тонкая обёртка над пайплайном задачи — не и делает финальную сверку. Тонкая обёртка над пайплайном задачи — не
переизобретай её шаги, вызывай как есть. переизобретай её шаги, вызывай как есть.
**По умолчанию задачи идут по одной**, в порядке зависимостей. Параллельно — по
явной просьбе, и тогда параллельность **по графу зависимостей**: одновременно
гонится только то, между чем нет ни зависимости, ни пересечения. Правило и его
цена — в шаге 4.
Работай **максимально автономно**, по тому же принципу, что и одиночный пайплайн: Работай **максимально автономно**, по тому же принципу, что и одиночный пайплайн:
вопрос, который решать не тебе, записывается и не останавливает поток; спрашиваем вопрос, который решать не тебе, записывается и не останавливает поток; спрашиваем
только про **необратимое** (деплой, выкладка наружу, удаление или перезапись только про **необратимое** (деплой, выкладка наружу, удаление или перезапись
@@ -34,7 +39,7 @@ description: Проводит несколько задач разом — пл
`docs/database.md` и `docs/.pm.json` (ключ `migrations`). `docs/database.md` и `docs/.pm.json` (ключ `migrations`).
**Документов канона нет — проект к нему не приведён.** Скажи это строкой и **Документов канона нет — проект к нему не приведён.** Скажи это строкой и
предложи `av-dev-pm:canon` **до первой волны**: иначе каждая задача батча предложи `av-dev-pm:canon` **до первой задачи**: иначе каждая задача батча
заплатит поразрядной деградацией ревью, а имя основной ветки придётся заплатит поразрядной деградацией ревью, а имя основной ветки придётся
угадывать. угадывать.
@@ -56,10 +61,16 @@ description: Проводит несколько задач разом — пл
## Ключевое отличие от одиночного пайплайна ## Ключевое отличие от одиночного пайплайна
`task-pipeline` коммитит **в текущую ветку**, и при ручном запуске это основная `task-pipeline` коммитит **в текущую ветку**, и при ручном запуске это основная
ветка. Здесь так нельзя для параллельных задач, поэтому батч — **осознанное ветка. Здесь так нельзя, поэтому батч — **осознанное исключение**: временные
исключение**: временные ветки и worktree заводятся лишь как средство изоляции, а ветки и worktree заводятся лишь как средство изоляции, а конечное состояние — та
конечное состояние — та же линейная история основной ветки через rebase + же линейная история основной ветки через rebase + fast-forward. Ветки после
fast-forward. Ветки после вливания удаляются. вливания удаляются.
Изоляция нужна **в обоих режимах, а не только в параллельном**: батч не вливает
ветку, пока не проверил полноту её ревью (шаг 5), и упавшая задача обязана
остаться в своём worktree для ручного дожатия (шаг 6), не оставив следа в
основной ветке. В параллельном режиме к этому добавляется вторая причина —
задачи не должны видеть недоделанную работу друг друга.
## Модель исполнения ## Модель исполнения
@@ -87,10 +98,12 @@ fast-forward. Ветки после вливания удаляются.
- **затронутые capability** — по её описанию и по каталогу актуальных спек - **затронутые capability** — по её описанию и по каталогу актуальных спек
(`openspec/specs/`); (`openspec/specs/`);
- **жёсткие зависимости**: задача B строится на результате A → A строго раньше B; - **жёсткие зависимости**: задача B строится на результате A → A строго раньше B;
- **замеряющая задача** — та, чьё ревью будет доказывать находки **числами**, и - **замеряющая задача** — та, чьё ревью будет доказывать находки **числами**. В
потому она гонится в волне **одна** (обоснование — ниже, в шаге 4). Решается последовательном прогоне это ничего не меняет: она и так идёт одна. В
здесь, на планировании, а не во время прогона: состав волны определяется параллельном она гонится в волне **одна** (обоснование — ниже, в шаге 4).
сейчас, а профиль ревью сабагент выберет только внутри задачи, и ключевать Помечается здесь, на планировании, а не во время прогона, и **независимо от
режима**: состав волны определяется сейчас, режим может смениться просьбой уже
после плана, а профиль ревью сабагент выберет только внутри задачи — ключевать
волну на ещё не сделанный выбор нельзя. Триггеры — по фактам о задаче, каждый волну на ещё не сделанный выбор нельзя. Триггеры — по фактам о задаче, каждый
сам по себе достаточен: сам по себе достаточен:
- трогает схему хранилища, миграцию, формат на диске или объём хранимого; - трогает схему хранилища, миграцию, формат на диске или объём хранимого;
@@ -120,7 +133,9 @@ fast-forward. Ветки после вливания удаляются.
**всем** задачам с таким артефактом, независимо от того, в какой волне они **всем** задачам с таким артефактом, независимо от того, в какой волне они
окажутся: раздача ничего не стоит, а её отсутствие ловится только конфликтом на окажутся: раздача ничего не стоит, а её отсутствие ловится только конфликтом на
интеграции. Между волнами проблемы нет — ветка следующей волны берётся от интеграции. Между волнами проблемы нет — ветка следующей волны берётся от
вершины, уже включающей предыдущие; вершины, уже включающей предыдущие; в последовательном прогоне проблемы нет по
той же причине, но номера всё равно раздай: режим может смениться просьбой, а
раздача бесплатна;
- **жёстко сериализуем** (не гоняем одновременно) настоящие пересечения: - **жёстко сериализуем** (не гоняем одновременно) настоящие пересечения:
- **одна capability на несколько задач** — две задачи, правящие одну спеку (тем - **одна capability на несколько задач** — две задачи, правящие одну спеку (тем
более одно и то же `### Requirement`), дают не текстовый, а **семантический** более одно и то же `### Requirement`), дают не текстовый, а **семантический**
@@ -130,39 +145,65 @@ fast-forward. Ветки после вливания удаляются.
правит **свою** строку (индексы, оглавления, списки записей), и спеки разных правит **свою** строку (индексы, оглавления, списки записей), и спеки разных
capability — разные строки и файлы, сливаются сами. capability — разные строки и файлы, сливаются сами.
Собери план: **волны** параллельно-безопасных задач плюс сериализованный хвост Собери план как **граф зависимостей**, а не как плоский список: рёбра — жёсткие
конфликтоопасных, с учётом зависимостей; замеряющие задачи стоят в плане зависимости и сериализуемые пересечения. Дальше по режиму:
отдельными волнами по одной. Покажи план короткой репликой — назвав, какие
задачи признаны замеряющими и по какому триггеру, — и иди дальше. - **последовательно (умолчание)** — линеаризуй граф в один порядок:
топологический, а там, где он оставляет свободу, — раньше то, от чего зависит
больше задач, и раньше то, что правит общие для набора места. Волн нет,
замеряющие задачи ничем не отличаются от прочих;
- **параллельно (по просьбе)** — нарежь граф на **волны**: в одну волну попадают
только задачи, между которыми нет ребра; замеряющие стоят отдельными волнами по
одной.
Покажи план короткой репликой — режим, порядок или состав волн, какие задачи
признаны замеряющими и по какому триггеру, — и иди дальше.
### 3. Свежая база ### 3. Свежая база
Убедись, что рабочее дерево чистое и основная ветка свежая. Зафиксируй базовый Убедись, что рабочее дерево чистое и основная ветка свежая. Зафиксируй базовый
коммит. Новые ветки бери от свежей вершины; ветки следующей волны — от вершины, коммит. Новые ветки бери от свежей вершины; ветку следующей задачи (в
уже включающей результат предыдущих волн. параллельном режиме — ветки следующей волны) — от вершины, уже включающей
результат предыдущих.
### 4. Прогнать волны ### 4. Провести задачи
**Потолок параллелизма — 2–3 задачи одновременно.** Каждая задача тянет полный **Умолчание — по одной задаче за раз, в порядке из шага 2.** Следующая стартует,
цикл пайплайна с вложенным ревью и гейтом, поэтому больше трёх разом душат когда предыдущая вернула отчёт и (если она зелёная) влилась. Обосновывать это не
машину и провоцируют гонки. Волну шире трёх бей на под-пачки по ≤3 и **гони надо — обосновывается отступление. Причина умолчания в том, что задача батча
под-пачки последовательно**: следующая стартует, когда предыдущая вернула отчёты. дороже прохода ревью: каждая тянет полный цикл пайплайна с гейтом, поднятием
Иначе потолок обходится тривиально — шесть задач, запущенных «двумя под-пачками» сервиса и вложенным ревью, и две такие на одной машине дерутся за порты, рабочие
в одном сообщении, это шесть задач разом. каталоги, СУБД и само железо. Последовательный прогон к тому же оставляет ревью
внутри задачи его собственное умолчание — **параллельные проходы**: машина
свободна, и выигрыш берётся там, где он ничего не стоит.
**Волна из одной задачи — не вырожденный случай, а обязательный.** Задача, **Параллельно — по явной просьбе, и параллельность идёт по графу зависимостей.**
признанная на шаге 2 **замеряющей**, гонится в волне одна: соседний прогон на той Одновременно гонится только то, между чем на шаге 2 не нашлось ребра: ни жёсткой
же машине портит числа, а находка с испорченным оракулом хуже отсутствующей — она зависимости, ни общей capability, ни общих исходников. «Гони параллельно» не
выглядит доказанной. Если замеряющая задача всё же пошла в общей волне, её отчёт означает «гони всё разом» — граф остаётся в силе, просьба лишь разрешает
обязан нести строку в границах покрытия: замеры сняты под соседней нагрузкой. использовать его ширину.
Для каждой задачи в под-пачке: В параллельном режиме действуют два ограничения:
- **потолок — 2–3 задачи одновременно.** Больше трёх разом душат машину и
провоцируют гонки. Волну шире трёх бей на под-пачки по ≤3 и **гони под-пачки
последовательно**: следующая стартует, когда предыдущая вернула отчёты. Иначе
потолок обходится тривиально — шесть задач, запущенных «двумя под-пачками» в
одном сообщении, это шесть задач разом;
- **волна из одной задачи обязательна для замеряющей.** Задача, признанная на
шаге 2 **замеряющей**, гонится одна: соседний прогон на той же машине портит
числа, а находка с испорченным оракулом хуже отсутствующей — она выглядит
доказанной. Если замеряющая задача всё же пошла в общей волне, её отчёт обязан
нести строку в границах покрытия: замеры сняты под соседней нагрузкой.
Для каждой задачи (в параллельном режиме — для каждой задачи под-пачки):
1. Заведи worktree и ветку от текущей вершины: 1. Заведи worktree и ветку от текущей вершины:
`git worktree add <path> -b task/<slug> <основная ветка>`. Путь — во временном `git worktree add <path> -b task/<slug> <основная ветка>`. Путь — во временном
каталоге проекта (`./tmp`), не в системном `/tmp`. каталоге проекта (`./tmp`), не в системном `/tmp`.
2. Запусти **по одному сабагенту на задачу, все в одном сообщении**, 2. Запусти сабагента, `subagent_type: general-purpose`: в последовательном режиме
`subagent_type: general-purpose`. Charter сабагента: — одного и дождись отчёта; в параллельном — **по одному на задачу под-пачки,
всех в одном сообщении**. Charter сабагента:
- работай **строго в своём worktree** `<path>`; в другие каталоги и в основную - работай **строго в своём worktree** `<path>`; в другие каталоги и в основную
ветку не лезь; ветку не лезь;
- прогони Skill **`av-dev-pipeline:task-pipeline`** ровно на этой задаче, - прогони Skill **`av-dev-pipeline:task-pipeline`** ровно на этой задаче,
@@ -171,8 +212,12 @@ fast-forward. Ветки после вливания удаляются.
- **профиль ревью выбирается по факту изменения.** Батч не повод понижать - **профиль ревью выбирается по факту изменения.** Батч не повод понижать
профиль: «нас много и мы спешим» — это ровно тот стимул, из-за которого профиль: «нас много и мы спешим» — это ровно тот стимул, из-за которого
проходы пропускают; проходы пропускают;
- **режим прогона проходов — последовательный.** Твой worktree не один на - **режим прогона проходов ревью — от режима батча**, и его называет charter,
машине; а не сабагент: батч идёт по одной задаче → режим умолчательный,
**параллельный** (машина свободна); батч идёт волнами → **последовательный**,
твой worktree не один на машине, и этой причиной ты обязан объяснить режим в
отчёте. Меряющую пару `adversary` и `ops` конвейер держит по очереди сам, в
любом режиме;
- **если вложенные сабагенты недоступны** (движок не даёт запускать агентов из - **если вложенные сабагенты недоступны** (движок не даёт запускать агентов из
агента) — не пропускай ревью и не понижай профиль: проведи его **инлайн** по агента) — не пропускай ревью и не понижай профиль: проведи его **инлайн** по
тем же charter'ам `av-dev-pipeline`, сохранив обязательное — гейт до тем же charter'ам `av-dev-pipeline`, сохранив обязательное — гейт до
@@ -189,6 +234,11 @@ fast-forward. Ветки после вливания удаляются.
архивации — `openspec/changes/archive/<id>/review/`); шло ли ревью архивации — `openspec/changes/archive/<id>/review/`); шло ли ревью
инлайн; границы покрытия. инлайн; границы покрытия.
**Шаги 5 и 6 отрабатываются на вернувшейся задаче до старта следующей** — в
параллельном режиме на вернувшейся волне до старта следующей. Иначе ветка
следующей возьмётся от вершины, не видевшей предыдущую работу, и весь смысл
порядка из шага 2 теряется.
Сабагент, упершийся в вопрос, **не останавливает батч**: он записывает вопрос, Сабагент, упершийся в вопрос, **не останавливает батч**: он записывает вопрос,
режет задачу до остатка и доводит остаток — либо, если остатка нет, возвращает режет задачу до остатка и доводит остаток — либо, если остатка нет, возвращает
исход «не доведена». Оркестратор собирает такие вопросы и выносит их в финальный исход «не доведена». Оркестратор собирает такие вопросы и выносит их в финальный
@@ -296,11 +346,11 @@ rebase в файле X», а не «нераспознанное пересеч
слияния**: слияния**:
- запусти **по одному `review-specs` на каждую затронутую capability**, - запусти **по одному `review-specs` на каждую затронутую capability**,
последовательно. Параллельно — только если человек попросил явно и назвал параллельно — как велит умолчание конвейера: замеров эти проходы не делают,
набор: правило и оба его условия живут в друг другу не мешают, а машина к этому моменту свободна (все сабагенты
`av-dev-pipeline:review-pipeline`, раздел «Режим запуска», и здесь не вернулись). По очереди — только по особой причине из раздела «Режим запуска»
ослабляются. «Замеров не делают» основанием не является; `av-dev-pipeline:review-pipeline`, и причину назови;
- **режим у этих проходов особый, и его надо назвать в задании.** Живого change - **задание у этих проходов особое, и это надо сказать прямо.** Живого change
здесь нет — все заархивированы, дельта-спек не существует. Источник требований здесь нет — все заархивированы, дельта-спек не существует. Источник требований
**актуальные** `openspec/specs/<capability>/spec.md`, а предмет — стык: **актуальные** `openspec/specs/<capability>/spec.md`, а предмет — стык:
требование, которое одна задача выполнила, а соседняя незаметно отменила; два требование, которое одна задача выполнила, а соседняя незаметно отменила; два
@@ -329,8 +379,9 @@ rebase в файле X», а не «нераспознанное пересеч
строкой — иначе задача останется открытой молча. строкой — иначе задача останется открытой молча.
- Доложи кратко: - Доложи кратко:
- **исход по каждой задаче** одним из трёх слов, с хешем коммита; - **исход по каждой задаче** одним из трёх слов, с хешем коммита;
- план волн и порядок интеграции, с пометкой, какие задачи шли по одной как - **режим прогона** — по одной или волнами, и если волнами, то по чьей просьбе;
замеряющие; порядок задач или состав волн, порядок интеграции, с пометкой, какие задачи
шли по одной как замеряющие;
- вопросы, записанные сабагентами, пачкой; - вопросы, записанные сабагентами, пачкой;
- что дозапускалось на шаге 5 и почему; шло ли где-то ревью инлайн; - что дозапускалось на шаге 5 и почему; шло ли где-то ревью инлайн;
- итог финальной сверки и ссылки на архивные change; - итог финальной сверки и ссылки на архивные change;
@@ -343,18 +394,22 @@ rebase в файле X», а не «нераспознанное пересеч
## Тонкости ## Тонкости
- **Изоляция параллельных тестов.** Прежде чем гнать несколько прогонов разом, - **Изоляция параллельных тестов — цена параллельного режима, и проверяется она
убедись, что тесты не делят фиксированный порт или файл БД (обычно берут до первой волны.** Прежде чем гнать несколько прогонов разом, убедись, что
временный каталог и эфемерный порт — тогда ок). Делят — гони такие задачи тесты не делят фиксированный порт или файл БД (обычно берут временный каталог и
последовательно. эфемерный порт — тогда ок). Делят — такие задачи гони по одной, даже если
- Поведенческая верификация внутри сабагента поднимает изменение вживую: следи, просили параллельно, и скажи об этом строкой: просьба про параллельность, а не
чтобы соседние worktree не дрались за порты и рабочие каталоги. Если проект про сломанные тесты. В умолчательном режиме вопрос не встаёт вовсе — это одна
умеет поднимать только один экземпляр — такие задачи в одну волну не ставь. из причин, по которым умолчание такое.
- Поведенческая верификация внутри сабагента поднимает изменение вживую: в
параллельном режиме следи, чтобы соседние worktree не дрались за порты и
рабочие каталоги. Если проект умеет поднимать только один экземпляр — такие
задачи в одну волну не ставь.
- Ревью выполненного — **до** интеграции; это забота - Ревью выполненного — **до** интеграции; это забота
`av-dev-pipeline:task-pipeline` внутри каждого сабагента, дублировать не надо. `av-dev-pipeline:task-pipeline` внутри каждого сабагента, дублировать не надо.
- `openspec validate --strict` тоже внутри пайплайна задачи — не пропускай его - `openspec validate --strict` тоже внутри пайплайна задачи — не пропускай его
своими правками на интеграции. своими правками на интеграции.
- Крупная переработка, предложенная ревью внутри задачи, — развилка: не вливай - Крупная переработка, предложенная ревью внутри задачи, — развилка: не вливай
молча, вынеси в доклад. молча, вынеси в доклад.
- Держи вызывающего в цикле короткими репликами на переходах фаз (план → волны → - Держи вызывающего в цикле короткими репликами на переходах фаз (план → прогон
интеграция → финальная сверка), но не проси подтверждать механику. задач → интеграция → финальная сверка), но не проси подтверждать механику.
@@ -229,12 +229,12 @@ description: Автономно проводит одну задачу чере
последней. Помни ровно одно — **профиль выбирается по факту изменения, а не по последней. Помни ровно одно — **профиль выбирается по факту изменения, а не по
ощущению важности**, и посмотри таблицу перед вызовом. ощущению важности**, и посмотри таблицу перед вызовом.
**Режим по умолчанию последовательный, и обосновывать его не надо.** Параллельно **Режим по умолчанию параллельный, и обосновывать его не надо.** По очереди гоняем
гоняем только тогда, когда об этом попросили явно **и назвали набор** — какие только по особой причине, и она называется строкой: об этом попросил оператор;
именно проходы или какую стадию. Просьба без набора основанием не считается: машина занята чем-то ещё (в том числе соседней задачей батча); идёт разбор самого
гони последовательно и скажи строкой, что набор не был назван. Причина умолчания конвейера. Меряющую пару `adversary` и `ops` конвейер держит по очереди сам, без
— замеры: `adversary` и `ops` доказывают находки числами, а два меряющих прохода твоего участия: оба доказывают находки числами, а два меряющих прохода на одной
на одной машине портят числа друг другу; находка с испорченным оракулом хуже машине портят числа друг другу находка с испорченным оракулом хуже
отсутствующей, потому что выглядит доказанной. отсутствующей, потому что выглядит доказанной.
Скилл сам гоняет гейт, нужные проходы и обязательный триаж. Возвращает отчёт с Скилл сам гоняет гейт, нужные проходы и обязательный триаж. Возвращает отчёт с