task-batch удалён вместе с хвостами
Пайплайн нескольких задач снят с повестки: работаем по одной. Каталог скилла удалён, и с ним всё, что держалось только на нём. Хвосты были не только ссылками. У review-specs исчез третий режим (стык после слияния) — вместе с исключением «живого change нет, берём актуальные спеки источником»: теперь отсутствие дельта-спеки это отказ. У review-triage исчезло единственное исключение из правила «плана нет — не запускаюсь». В каноне и у doc-code-drift имя основной ветки обосновывалось тем, что «в неё вливает батч», — довод заменён на верный.
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
---
|
||||
name: review-pipeline
|
||||
description: "Конвейер ревью изменения, устроенный по темам: документ проекта либо заводит тему ревью, либо питает чужую тему источником, либо процессный и в ревью не читается вовсе. Ядро тем — requirements, autotests, conventions, architecture, security, operations; список тем открытый, свои темы проект заводит документом. Разметка задачи идёт один раз, после propose: агент review-scope выводит размер и сложность, из их максимума — метка, и раздаёт темы проходам обеих стадий. Метка правит и ревью дизайна (small — только specs; medium — плюс rubric; large — плюс architecture), и ревью кода (small — гейт, спеки, код, триаж; medium — плюс приёмник тем; large — плюс доказательство: враждебные постановки, эксплуатационный постмортем, архитектурный проход на широком входе). Триаж обязателен всегда. Порядок прогона — граф зависимостей: гейт открывает опиниативные проходы, проходы с пометкой «держит машину» идут цепочкой, триаж — единственный сток. Проектная специфика приходит из документов канона av-dev-docs. Вызывается из task-pipeline (чекпоинты ревью) и из task-batch (финальная сверка)."
|
||||
description: "Конвейер ревью изменения, устроенный по темам: документ проекта либо заводит тему ревью, либо питает чужую тему источником, либо процессный и в ревью не читается вовсе. Ядро тем — requirements, autotests, conventions, architecture, security, operations; список тем открытый, свои темы проект заводит документом. Разметка задачи идёт один раз, после propose: агент review-scope выводит размер и сложность, из их максимума — метка, и раздаёт темы проходам обеих стадий. Метка правит и ревью дизайна (small — только specs; medium — плюс rubric; large — плюс architecture), и ревью кода (small — гейт, спеки, код, триаж; medium — плюс приёмник тем; large — плюс доказательство: враждебные постановки, эксплуатационный постмортем, архитектурный проход на широком входе). Триаж обязателен всегда. Порядок прогона — граф зависимостей: гейт открывает опиниативные проходы, проходы с пометкой «держит машину» идут цепочкой, триаж — единственный сток. Проектная специфика приходит из документов канона av-dev-docs. Вызывается из скилла resolve — двумя чекпоинтами: ревью дизайна до кода и ревью кода после apply."
|
||||
---
|
||||
|
||||
# Конвейер ревью
|
||||
@@ -58,7 +58,7 @@ description: "Конвейер ревью изменения, устроенны
|
||||
- **Документы канона** — см. следующий раздел.
|
||||
- **Проектные копии этих скиллов и агентов удаляются при установке.** Если в
|
||||
проекте уже лежат свои `.claude/skills/review-pipeline`,
|
||||
`.claude/skills/task-pipeline`, `.claude/skills/task-batch` или
|
||||
`.claude/skills/task-pipeline`, `.claude/skills/resolve` или
|
||||
`.claude/agents/<проект>-review-*.md` — снеси их. Иначе короткое имя разрешится
|
||||
в устаревшую проектную копию, молча и без признаков подмены.
|
||||
|
||||
@@ -94,8 +94,8 @@ description: "Конвейер ревью изменения, устроенны
|
||||
<!-- /копия: граница-плагинов -->
|
||||
|
||||
Своих скиллов это касается ровно так же: `av-dev-pipeline:review-pipeline`,
|
||||
`av-dev-pipeline:task-pipeline`, `av-dev-pipeline:task-batch` — подменяется
|
||||
короткое имя, а не чужое.
|
||||
`av-dev-pipeline:resolve`, `av-dev-pipeline:openspec` — подменяется короткое имя,
|
||||
а не чужое.
|
||||
|
||||
## Темы, источники и процессные документы
|
||||
|
||||
@@ -560,8 +560,7 @@ flowchart TD
|
||||
ничего не портит, он только дольше, и домысливать тут нечего;
|
||||
2. **машина занята, и знает об этом вызывающий.** Рядом идёт другая задача,
|
||||
поднят сервис, гоняется дорогая проверка проекта. Сам конвейер занятости
|
||||
машины не видит — её обязан назвать тот, кто запускает; так и делает
|
||||
`av-dev-pipeline:task-batch`, когда ведёт задачи параллельно;
|
||||
машины не видит — её обязан назвать тот, кто запускает;
|
||||
3. **разбор самого конвейера** — когда выясняется, почему проход чего-то не
|
||||
нашёл, порядок и изоляция важнее скорости.
|
||||
|
||||
@@ -956,8 +955,8 @@ flowchart TD
|
||||
Он единственное, по чему потом видно, что было найдено и что из этого не
|
||||
заведено: нулевой урожай при непустом отчёте виден сразу.
|
||||
**Вместе с изменением он и переезжает:** после `opsx:archive` его адрес —
|
||||
`openspec/changes/archive/<id>/review/`. Кто ищет отчёт после архивации (батч
|
||||
на финальной сверке, приёмщик на сессии), смотрит **оба** пути; «отчёта нет»
|
||||
`openspec/changes/archive/<id>/review/`. Кто ищет отчёт после архивации
|
||||
(приёмщик на сессии, разбор дефекта), смотрит **оба** пути; «отчёта нет»
|
||||
объявляется, только когда пуст и архивный, иначе самый дорогой сценарий
|
||||
«состав ревью неизвестен, гоняем заново» срабатывает на каждой доведённой
|
||||
задаче.
|
||||
|
||||
@@ -1,518 +0,0 @@
|
||||
---
|
||||
name: task-batch
|
||||
description: Проводит несколько задач разом — планирует порядок и пересечения, гонит каждую задачу отдельным сабагентом в своём git worktree через task-pipeline (по умолчанию по одной задаче за раз; параллельно по графу зависимостей — по явной просьбе), интегрирует по одной ветке через rebase + fast-forward (линейная история), проверяет полноту ревью каждой ветки и в конце сверяет стыки, возникшие от слияния. Набор задач приходит извне. Использовать, когда просят сделать несколько задач сразу.
|
||||
---
|
||||
|
||||
# Батч задач
|
||||
|
||||
Оркестратор **набора** задач. Планирует порядок, раскидывает задачи по
|
||||
изолированным worktree, каждую проводит через полный цикл
|
||||
`av-dev-pipeline:task-pipeline`, затем сводит в основную ветку линейной историей
|
||||
и делает финальную сверку. Тонкая обёртка над пайплайном задачи — не
|
||||
переизобретай её шаги, вызывай как есть.
|
||||
|
||||
**По умолчанию задачи идут по одной**, в порядке зависимостей. Параллельно — по
|
||||
явной просьбе, и тогда параллельность **по графу зависимостей**: одновременно
|
||||
гонится только то, между чем нет ни зависимости, ни пересечения. Правило и его
|
||||
цена — в шаге 4.
|
||||
|
||||
Работай **максимально автономно**, по тому же принципу, что и одиночный пайплайн:
|
||||
вопрос, который решать не тебе, записывается и не останавливает поток; спрашиваем
|
||||
только про **необратимое** (деплой, выкладка наружу, удаление или перезапись
|
||||
рабочих данных). Механику — планирование, worktree, rebase, интеграцию, чистку —
|
||||
делаем без спроса.
|
||||
|
||||
## Предпосылки
|
||||
|
||||
- **OpenSpec и скиллы `opsx:*`** — на них стоит цикл внутри каждого сабагента и
|
||||
проход `review-specs` финальной сверки. Проекта без OpenSpec это касается так
|
||||
же, как одиночного пайплайна (см. его раздел «Предпосылки»).
|
||||
- **Проектные копии этих скиллов и агентов при установке плагина удаляются.**
|
||||
|
||||
### Обращение к соседним плагинам
|
||||
|
||||
**Копия.** Дом — `shared/plugin-boundary.md` в репозитории плагинов. Правится
|
||||
дом, а не этот файл.
|
||||
|
||||
<!-- копия: граница-плагинов из shared/plugin-boundary.md -->
|
||||
|
||||
Плагины `av-dev` ставятся порознь, и ни один не вправе считать, что сосед на
|
||||
месте.
|
||||
|
||||
**Чужой скилл зовётся полным именем** — `av-dev-docs:canon`,
|
||||
`av-dev-tasks:tasks`, `av-dev-pipeline:review-pipeline`. Короткое имя может
|
||||
разрешиться в устаревшую проектную копию из `.claude/skills/`, и подмены не будет
|
||||
видно ни в докладе, ни в поведении.
|
||||
|
||||
**Путь в дерево чужого плагина не пишется никогда.** `$CLAUDE_PLUGIN_ROOT` ведёт
|
||||
только в свой плагин; вычисленный от него путь к соседу либо не откроется, либо
|
||||
откроет чужую установку. Нужен чужой справочник — зови владеющий им скилл, он
|
||||
прочитает его сам.
|
||||
|
||||
**Вызов не разрешился — плагина в проекте нет.** Это исход, а не поломка: назови
|
||||
строкой доклада, чего теперь не делает никто, и продолжай работу. Молчать нельзя,
|
||||
пропуск неотличим от сделанного; выдумывать обходной путь нельзя тоже.
|
||||
|
||||
**Присутствие узнаётся вызовом или следом в проекте, но не объявлением.** Перечня
|
||||
установленных плагинов проект не ведёт — он разошёлся бы с действительностью
|
||||
молча. Что сосед здесь работал, видно по заведённому им файлу: `docs/.pm.json` —
|
||||
канон, `<каталог задач>/.tasks.json` — задачи, `openspec/config.yaml` — конвейер.
|
||||
|
||||
<!-- /копия: граница-плагинов -->
|
||||
|
||||
**У батча правило строже одним пунктом: полное имя обязательно и в charter'е
|
||||
сабагента.** Сабагент твоего контекста не видит, короткое имя разрешает у себя, и
|
||||
подмена на устаревшую проектную копию случится там, куда ты уже не смотришь.
|
||||
|
||||
Перед стартом прочитай `CLAUDE.md` проекта: оттуда берутся **имя основной
|
||||
ветки** (оно подставляется в каждую команду git ниже), команда и семантика
|
||||
гейта, инварианты и что запускать запрещено. Раскладка нумерованных артефактов —
|
||||
`docs/database.md` и `docs/.pm.json` (ключ `migrations`).
|
||||
|
||||
**Документов канона нет — проект к нему не приведён.** Скажи это строкой и
|
||||
предложи `av-dev-docs:canon` **до первой задачи**: иначе каждая задача батча
|
||||
заплатит поразрядной деградацией ревью, а имя основной ветки придётся
|
||||
угадывать.
|
||||
|
||||
## Границы
|
||||
|
||||
- **Набор задач приходит извне.** Батч его не формирует: не выбирает из беклога,
|
||||
не приоритизирует, не решает, что важнее. Набор не задан — попроси его у
|
||||
вызывающего и остановись.
|
||||
- **Батч не владеет спринтом и целями.** Он сообщает исход по каждой задаче в тех
|
||||
же трёх словах, что и `task-pipeline`: сделана / не доведена / оказалась крупнее
|
||||
задачи.
|
||||
- **Задачи закрывает пайплайн внутри каждого сабагента**, шагом 12 — после
|
||||
коммита работы и **отдельным коммитом учёта**, вызовом Skill `av-dev-tasks:tasks`.
|
||||
Батч сам записей учёта не трогает: он не знает, чем кончилась приёмка, и
|
||||
дублировать закрытие ему незачем. Но грязное дерево после сабагента — **его**
|
||||
проблема: на нём откажут и `rebase`, и `worktree remove` (см. шаг 6). Урожай ревью батч
|
||||
отдаёт списком, а задачи из него заводит тот, кто ведёт задачи проекта.
|
||||
|
||||
## Ключевое отличие от одиночного пайплайна
|
||||
|
||||
`task-pipeline` коммитит **в текущую ветку**, и при ручном запуске это основная
|
||||
ветка. Здесь так нельзя, поэтому батч — **осознанное исключение**: временные
|
||||
ветки и worktree заводятся лишь как средство изоляции, а конечное состояние — та
|
||||
же линейная история основной ветки через rebase + fast-forward. Ветки после
|
||||
вливания удаляются.
|
||||
|
||||
Изоляция нужна **в обоих режимах, а не только в параллельном**: батч не вливает
|
||||
ветку, пока не проверил полноту её ревью (шаг 5), и упавшая задача обязана
|
||||
остаться в своём worktree для ручного дожатия (шаг 6), не оставив следа в
|
||||
основной ветке. В параллельном режиме к этому добавляется вторая причина —
|
||||
задачи не должны видеть недоделанную работу друг друга.
|
||||
|
||||
## Модель исполнения
|
||||
|
||||
- Каждая задача = **один автономный сабагент** (`general-purpose`, чтобы иметь
|
||||
доступ к Skill и Agent для вложенных чекпоинтов ревью), работающий **только в
|
||||
своём worktree** и прогоняющий `task-pipeline` целиком на этой задаче.
|
||||
- Оркестратор кода задач не пишет: он планирует, заводит worktree, запускает
|
||||
сабагентов, проверяет полноту их ревью, интегрирует ветки и делает финальную
|
||||
сверку.
|
||||
- Стиль правок внутри — заточка под проект и конвенции, right-size, без
|
||||
золочения.
|
||||
|
||||
## Шаги
|
||||
|
||||
### 1. Прочитать набор
|
||||
|
||||
Набор задан списком (слаги, файлы, описания) — прочитай файл каждой задачи и
|
||||
связанные спеки и черновики. Сырьё (в терминах `av-dev-tasks` — запись типа
|
||||
`research` с пустым разделом «Вопрос») включается, но помни: сабагент проведёт
|
||||
его сперва через `opsx:explore`, это тяжелее и чаще упирается в вопрос.
|
||||
|
||||
### 2. Спланировать порядок и пересечения (автономно)
|
||||
|
||||
Для каждой задачи определи:
|
||||
|
||||
- **затронутые capability** — по её описанию и по каталогу актуальных спек
|
||||
(`openspec/specs/`);
|
||||
- **жёсткие зависимости**: задача B строится на результате A → A строго раньше B;
|
||||
- **замеряющая задача** — та, чьё ревью будет доказывать находки **числами**. В
|
||||
последовательном прогоне это ничего не меняет: она и так идёт одна. В
|
||||
параллельном она гонится в волне **одна** (обоснование — ниже, в шаге 4).
|
||||
Помечается здесь, на планировании, а не во время прогона, и **независимо от
|
||||
режима**: состав волны определяется сейчас, режим может смениться просьбой уже
|
||||
после плана, а метка ревью назовёт разметчик уже внутри пайплайна задачи,
|
||||
после `propose`, — ключевать волну на ещё не сделанный выбор нельзя. Триггеры — по фактам о задаче, каждый
|
||||
сам по себе достаточен:
|
||||
- трогает схему хранилища, миграцию, формат на диске или объём хранимого;
|
||||
- трогает конкурентность: транзакции, блокировки, фоновые циклы, общее
|
||||
состояние;
|
||||
- трогает размер тела, буфер, память, сжатие, ретеншен, темп потока;
|
||||
- её тема названа в журнале `docs/review.md` как место, где уже ломалось.
|
||||
|
||||
Ни один триггер не сработал — задача не замеряющая, даже если её ревью
|
||||
окажется `large`. Метка про глубину проверки, замеряющая — про соревнование за
|
||||
железо; это разные вопросы, и совпадают они не всегда. Обратное тоже бывает и
|
||||
тоже законно: помеченная задача, чьё ревью пошло меткой `small` или
|
||||
`medium`, машину не займёт вовсе — меряющие проходы живут только в `large`.
|
||||
Пометка от этого не снимается: она ставится **до** разметки, и перестраховка
|
||||
здесь стоит одной волны, а ошибка — испорченных чисел;
|
||||
- **нумерованные артефакты — номера раздаёт оркестратор заранее.** Если проект
|
||||
нумерует миграции (путь — `docs/.pm.json`, ключ `migrations`), посмотри последний
|
||||
номер и **раздай номера всем задачам, которые, вероятно, их добавят**, до
|
||||
запуска. Номер уходит в charter сабагента, и он берёт назначенный, а не
|
||||
«следующий свободный».
|
||||
|
||||
**Это отдельная механика от правила волны, и она ему не служит** — их раньше
|
||||
путали, и они тянули в разные стороны. Правило волны отвечает на вопрос «кто с
|
||||
кем гонится одновременно», предраздача — на вопрос «какой номер берёт задача».
|
||||
Раздача нужна там, где **две задачи одной под-пачки** добавляют нумерованный
|
||||
артефакт: каждая считает «следующий свободный» по основной ветке, которая ещё
|
||||
не видела соседку, и обе берут один номер. Миграции под это почти не попадают —
|
||||
миграция и так триггер замеряющей задачи, а замеряющая идёт одна; но
|
||||
нумерованные артефакты бывают не только миграциями. Поэтому номера раздаются
|
||||
**всем** задачам с таким артефактом, независимо от того, в какой волне они
|
||||
окажутся: раздача ничего не стоит, а её отсутствие ловится только конфликтом на
|
||||
интеграции. Между волнами проблемы нет — ветка следующей волны берётся от
|
||||
вершины, уже включающей предыдущие; в последовательном прогоне проблемы нет по
|
||||
той же причине, но номера всё равно раздай: режим может смениться просьбой, а
|
||||
раздача бесплатна;
|
||||
- **жёстко сериализуем** (не гоняем одновременно) настоящие пересечения:
|
||||
- **одна capability на несколько задач** — две задачи, правящие одну спеку (тем
|
||||
более одно и то же `### Requirement`), дают не текстовый, а **семантический**
|
||||
конфликт при архивации; сериализуем по смыслу, а не только по файлам;
|
||||
- пересечение по одним и тем же исходникам;
|
||||
- **мягкие конфликты** сериализовать не надо: файлы-перечни, где каждая задача
|
||||
правит **свою** строку (индексы, оглавления, списки записей), и спеки разных
|
||||
capability — разные строки и файлы, сливаются сами.
|
||||
|
||||
Собери план как **граф зависимостей**, а не как плоский список: рёбра — жёсткие
|
||||
зависимости и сериализуемые пересечения. Дальше по режиму:
|
||||
|
||||
- **последовательно (умолчание)** — линеаризуй граф в один порядок:
|
||||
топологический, а там, где он оставляет свободу, — раньше то, от чего зависит
|
||||
больше задач, и раньше то, что правит общие для набора места. Волн нет,
|
||||
замеряющие задачи ничем не отличаются от прочих;
|
||||
- **параллельно (по просьбе)** — нарежь граф на **волны**: в одну волну попадают
|
||||
только задачи, между которыми нет ребра; замеряющие стоят отдельными волнами по
|
||||
одной.
|
||||
|
||||
Рёбра у графа двух видов, и путать их не надо: **зависимость** направлена (B без
|
||||
результата A не делается), **пересечение** — нет (кто первый, неважно, лишь бы не
|
||||
разом). Тот же словарь у графа проходов ревью — см. «Порядок прогона» в
|
||||
`av-dev-pipeline:review-pipeline`.
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A["A: схема хранилища<br/>(замеряющая)"]
|
||||
B["B: эндпоинт поверх A"]
|
||||
C["C: формат лога"]
|
||||
D["D: правит ту же capability, что C"]
|
||||
|
||||
A -->|зависимость| B
|
||||
C -. пересечение — одна capability .- D
|
||||
```
|
||||
|
||||
Этот граф даёт: **последовательно** — `A → B → C → D` (или `A → C → B → D`, обе
|
||||
линеаризации законны); **параллельно** — волна 1 `A` одна (замеряющая), волна 2
|
||||
`B` и `C`, волна 3 `D`.
|
||||
|
||||
Схемы в этом скилле — **пример и сводка**, правила ставит текст: при расхождении
|
||||
прав он. (В `av-dev-pipeline:review-pipeline` наоборот — там граф прогона и есть
|
||||
алгоритм, и старший он.)
|
||||
|
||||
Покажи план короткой репликой — режим, порядок или состав волн, какие задачи
|
||||
признаны замеряющими и по какому триггеру, — и иди дальше.
|
||||
|
||||
### 3. Свежая база
|
||||
|
||||
Убедись, что рабочее дерево чистое и основная ветка свежая. Зафиксируй базовый
|
||||
коммит. Новые ветки бери от свежей вершины; ветку следующей задачи (в
|
||||
параллельном режиме — ветки следующей волны) — от вершины, уже включающей
|
||||
результат предыдущих.
|
||||
|
||||
### 4. Провести задачи
|
||||
|
||||
**Умолчание — по одной задаче за раз, в порядке из шага 2.** Следующая стартует,
|
||||
когда предыдущая вернула отчёт и (если она зелёная) влилась. Обосновывать это не
|
||||
надо — обосновывается отступление. Причина умолчания в том, что задача батча
|
||||
дороже прохода ревью: каждая тянет полный цикл пайплайна с гейтом, поднятием
|
||||
сервиса и вложенным ревью, и две такие на одной машине дерутся за порты, рабочие
|
||||
каталоги, СУБД и само железо. Последовательный прогон к тому же оставляет ревью
|
||||
внутри задачи его собственное умолчание — **параллельные проходы**: машина
|
||||
свободна, и выигрыш берётся там, где он ничего не стоит.
|
||||
|
||||
**Параллельно — по явной просьбе, и параллельность идёт по графу зависимостей.**
|
||||
Одновременно гонится только то, между чем на шаге 2 не нашлось ребра: ни жёсткой
|
||||
зависимости, ни общей capability, ни общих исходников. «Гони параллельно» не
|
||||
означает «гони всё разом» — граф остаётся в силе, просьба лишь разрешает
|
||||
использовать его ширину.
|
||||
|
||||
В параллельном режиме действуют два ограничения:
|
||||
|
||||
- **потолок — 2–3 задачи одновременно.** Больше трёх разом душат машину и
|
||||
провоцируют гонки. Волну шире трёх бей на под-пачки по ≤3 и **гони под-пачки
|
||||
последовательно**: следующая стартует, когда предыдущая вернула отчёты. Иначе
|
||||
потолок обходится тривиально — шесть задач, запущенных «двумя под-пачками» в
|
||||
одном сообщении, это шесть задач разом;
|
||||
- **волна из одной задачи обязательна для замеряющей.** Задача, признанная на
|
||||
шаге 2 **замеряющей**, гонится одна: соседний прогон на той же машине портит
|
||||
числа, а находка с испорченным оракулом хуже отсутствующей — она выглядит
|
||||
доказанной. Если замеряющая задача всё же пошла в общей волне, её отчёт обязан
|
||||
нести строку в границах покрытия: замеры сняты под соседней нагрузкой.
|
||||
|
||||
Для каждой задачи (в параллельном режиме — для каждой задачи под-пачки):
|
||||
|
||||
1. Заведи worktree и ветку от текущей вершины:
|
||||
`git worktree add <path> -b task/<slug> <основная ветка>`. Путь — во временном
|
||||
каталоге проекта (`./tmp`), не в системном `/tmp`.
|
||||
2. Запусти сабагента, `subagent_type: general-purpose`: в последовательном режиме
|
||||
— одного и дождись отчёта; в параллельном — **по одному на задачу под-пачки,
|
||||
всех в одном сообщении**. Charter сабагента:
|
||||
- работай **строго в своём worktree** `<path>`; в другие каталоги и в основную
|
||||
ветку не лезь;
|
||||
- прогони Skill **`av-dev-pipeline:task-pipeline`** ровно на этой задаче,
|
||||
полный цикл SDD с обоими чекпоинтами ревью;
|
||||
- если задаче назначен **номер артефакта** — используй строго его;
|
||||
- **метка ревью выбирает разметчик конвейера, а не ты и не сабагент.** Он
|
||||
идёт внутри пайплайна задачи, шагом 4, сразу после `propose`, и его план
|
||||
обслуживает оба чекпоинта. Метка в вызов не передаётся вовсе. Батч не
|
||||
повод её понижать: «нас много и
|
||||
мы спешим» — ровно тот стимул, из-за которого проходы пропускают, и он снят
|
||||
тем, что регулятор не в руках у автора;
|
||||
- **режим прогона проходов ревью — от режима батча**, и его называет charter,
|
||||
а не сабагент: батч идёт по одной задаче → режим умолчательный, **`по
|
||||
графу`** (машина свободна); батч идёт волнами → **`линейно`**, твой worktree
|
||||
не один на машине, и этой причиной ты обязан объяснить режим в отчёте.
|
||||
Внутренние рёбра графа — цепочку проходов, держащих машину — конвейер
|
||||
соблюдает сам, в любом режиме;
|
||||
- **если вложенные сабагенты недоступны** (движок не даёт запускать агентов из
|
||||
агента) — не пропускай ревью и не понижай метка: проведи его **инлайн** по
|
||||
тем же charter'ам `av-dev-pipeline`, сохранив обязательное — разметку первой
|
||||
(план с темами и меткой), гейт до опиниативных проходов, состав по плану,
|
||||
триаж последним. И **скажи в отчёте прямым текстом, что ревью шло инлайн**:
|
||||
инлайновый проход видит контекст автора и потому разведён с ним слабее — а
|
||||
инлайновая разметка вдобавок означает, что метка выбрал автор, и это
|
||||
отдельная строка;
|
||||
- **вернуть отчёт**, в котором обязательно: исход задачи одним из трёх слов;
|
||||
**план прогона: метка с обоснованием, темы и их глубины**, и режим; что сделано; какие вопросы
|
||||
записаны и куда; изменённые файлы; добавлялся ли нумерованный артефакт и с
|
||||
каким номером; затронутые capability; состояние гейта; **перечень
|
||||
тем с исходом по каждой**; **путь к
|
||||
сохранённому отчёту триажа** (`openspec/changes/<id>/review/`, после
|
||||
архивации — `openspec/changes/archive/<id>/review/`); шло ли ревью
|
||||
инлайн; границы покрытия.
|
||||
|
||||
**Шаги 5 и 6 отрабатываются на вернувшейся задаче до старта следующей** — в
|
||||
параллельном режиме на вернувшейся волне до старта следующей. Иначе ветка
|
||||
следующей возьмётся от вершины, не видевшей предыдущую работу, и весь смысл
|
||||
порядка из шага 2 теряется.
|
||||
|
||||
Сабагент, упершийся в вопрос, **не останавливает батч**: он записывает вопрос,
|
||||
режет задачу до остатка и доводит остаток — либо, если остатка нет, возвращает
|
||||
исход «не доведена». Оркестратор собирает такие вопросы и выносит их в финальный
|
||||
доклад пачкой.
|
||||
|
||||
### 5. Проверить полноту ревью — до интеграции
|
||||
|
||||
**Ветка, чей отчёт не называет план прогона, не вливается.** Пропуск не отличим
|
||||
от прохода без находок, и на уровне батча это ещё опаснее: отчётов много, каждый
|
||||
выглядит полным, а сверять их некому, кроме тебя.
|
||||
|
||||
Сверка идёт в три шага, и порядок важен:
|
||||
|
||||
1. **Возьми план прогона** из отчёта задачи — таблицу «тема → дом → глубина → кто
|
||||
закрывает» с меткой и обоснованием; он затем и заказан в обязательных полях
|
||||
шага 4. Плана в отчёте нет — сверять не с чем; это само по себе основание не
|
||||
вливать, пока сабагент не покажет план разметки задачи.
|
||||
2. **Сверяй с независимым артефактом, а не с прозой отчёта.** Перечень проходов
|
||||
бери из **сохранённого отчёта триажа** (`openspec/changes/<id>/review/` или
|
||||
`openspec/changes/archive/<id>/review/` — задача доведена, change заархивирован) —
|
||||
пайплайн обязан его туда положить. Проза сабагента написана тем же, кто мог
|
||||
проход и пропустить: она подтверждает сама себя. Отчёта триажа на месте нет —
|
||||
считай, что состав неизвестен, и дозапускай ревью целиком.
|
||||
3. **Сверь план с исходом**: против каждой темы плана обязан стоять отчёт либо
|
||||
названная причина его отсутствия. Раскладка «тема → кто закрывает с этой меткой» — в скилле `av-dev-pipeline:review-pipeline`.
|
||||
|
||||
Расхождение — не повод отменять задачу: дозапусти недостающие проходы **на
|
||||
ветке**, в её worktree, через `av-dev-pipeline:review-pipeline`, и только потом
|
||||
интегрируй.
|
||||
|
||||
**Передай в дозапуск тот же план.** Триаж требует его обязательным входом — без
|
||||
плана он не может сверить, все ли размеченные темы вернули отчёт, а эта сверка и
|
||||
есть то, ради чего дозапуск затевается. Плана не осталось (сабагент не сохранил
|
||||
его в отчёте) — пусть повторит разметку задачи: это самый дешёвый проход
|
||||
конвейера, и он дешевле, чем прогон, который нечем сверить.
|
||||
|
||||
**Находки дозапуска — такие же находки, и зелёный гейт их не отменяет.** Правило
|
||||
интеграции «вливаем только зелёные» смотрит на гейт, а дозапущенный `critical`
|
||||
гейт не красит: он был бы пропущен молча, если это не сказать прямо. Поэтому:
|
||||
|
||||
- `critical` или `major` из дозапуска — **вливание этой ветки останавливается**.
|
||||
Помеченное `инлайн` чинится в её worktree, после починки — гейт, затем
|
||||
интеграция. Помеченное `развилка` — вопрос в запись, задача режется до остатка
|
||||
ровно так же, как это сделал бы пайплайн внутри;
|
||||
- остатка нет — ветка не вливается и уходит в доклад как провалившаяся, со своим
|
||||
worktree;
|
||||
- `minor` и `nit` из дозапуска — в урожай доклада, вливанию не мешают.
|
||||
|
||||
Отчёт дозапуска приложи к отчёту задачи и назови в докладе (шаг 9), почему он
|
||||
понадобился: систематический пропуск одного и того же прохода — находка о самом
|
||||
конвейере, а не о задаче.
|
||||
|
||||
### 6. Интегрировать — rebase + fast-forward, по одной ветке
|
||||
|
||||
Сводим ветки **строго последовательно** (линейная история), в порядке
|
||||
зависимостей. Вливаем **только зелёные**.
|
||||
|
||||
**Ветка задачи занята её worktree, и это определяет форму команд.** Пока worktree
|
||||
жив (а удаляется он последним, после зелёного гейта), ветка `task/<slug>`
|
||||
checkout'нута в нём, и `git rebase <основная> task/<slug>` из главного worktree
|
||||
**падает**: `fatal: 'task/<slug>' is already used by worktree at …`. Поэтому
|
||||
rebase делается **внутри worktree задачи**, а ff-слияние — из главного.
|
||||
|
||||
Для каждой готовой ветки `task/<slug>`:
|
||||
|
||||
- `git -C <path> rebase <основная>` — перенос ветки задачи на текущую вершину,
|
||||
выполняется в её собственном worktree;
|
||||
- резолв конфликтов (их почти нет — конфликтоопасное сериализовано, номера
|
||||
розданы заранее). Неавтоматический конфликт — **не форсируй**: прерви
|
||||
(`git -C <path> rebase --abort`), оставь ветку и worktree как есть, вынеси это
|
||||
в доклад как нераспознанное пересечение;
|
||||
- **дерево сабагента обязано быть чистым.** `git -C <path> status --porcelain`
|
||||
до `rebase`: непусто — значит сабагент не довёл шаг 12 до коммита учёта (или
|
||||
оставил мусор). Не форсируй и не коммить за него: назови задачу в докладе
|
||||
недоведённой и оставь ветку с worktree. Молчаливый `rebase` на грязном дереве
|
||||
всё равно откажет, но с сообщением про unstaged changes — а причина другая;
|
||||
- **ненулевой код `rebase` относится к этой ветке и только к ней.** Прерванный
|
||||
rebase в чужом worktree не трогает ни главное дерево, ни остальные ветки:
|
||||
проверь `git -C <path> status` и `git status` — обе чистые. Уводить весь батч
|
||||
в провалившиеся из-за одного ненулевого кода запрещено: это ложная причина,
|
||||
из-за которой зелёные задачи не доедут до основной ветки. Провалилась одна —
|
||||
провалилась одна;
|
||||
- из главного worktree (он стоит на основной ветке — проверь
|
||||
`git rev-parse --abbrev-ref HEAD`): `git merge --ff-only task/<slug>`. Ветку в
|
||||
главном дереве **не переключай** — `git checkout task/<slug>` тоже упрётся в
|
||||
занятость;
|
||||
- после каждой интеграции — **гейт на основной ветке**. Красное — **откати эту
|
||||
интеграцию** (`git reset --hard` на прошлую вершину), ветку с worktree сохрани,
|
||||
задачу перечисли в докладе. Основная ветка **никогда** не остаётся
|
||||
полузелёной;
|
||||
- только после зелёного: `git worktree remove <path>` и
|
||||
`git branch -d task/<slug>` — в этом порядке, иначе ветка снова занята.
|
||||
|
||||
**Политика частичного провала.** Упавшая задача (исход «не доведена», красные
|
||||
тесты в её worktree, конфликт при rebase, невлитая из-за находок дозапуска)
|
||||
**не блокирует остальные**: интегрируем все зелёные, упавшую оставляем в её
|
||||
worktree и ветке нетронутой — ничего не удаляем, — и перечисляем в докладе с
|
||||
причиной, отчётом и путём к worktree. Причина называется **настоящая**: «конфликт
|
||||
rebase в файле X», а не «нераспознанное пересечение» на всякий случай.
|
||||
|
||||
### 7. Финальный гейт
|
||||
|
||||
На основной ветке после всех интеграций — гейт целиком. Зелёное обязательно; пока
|
||||
красное, шаг 8 не начинается.
|
||||
|
||||
### 8. Финальная сверка — только то, чего не видел никто
|
||||
|
||||
Каждая задача уже прошла полный конвейер в своём worktree. Повторять его на
|
||||
интегрированном диффе бессмысленно: те же проходы на тех же файлах дадут те же
|
||||
находки и удорожат триаж. Здесь проверяется **только то, что появилось от
|
||||
слияния**:
|
||||
|
||||
- запусти **по одному `review-specs` на каждую затронутую capability**, все
|
||||
разом — граф здесь плоский: машину эти проходы не держат, ребра между ними нет,
|
||||
а сама машина к этому моменту свободна (все сабагенты вернулись). Линейно —
|
||||
только по причине из раздела «Порядок прогона»
|
||||
`av-dev-pipeline:review-pipeline`, и причину назови;
|
||||
- **задание у этих проходов особое, и это надо сказать прямо.** Живого change
|
||||
здесь нет — все заархивированы, дельта-спек не существует. Источник требований
|
||||
— **актуальные** `openspec/specs/<capability>/spec.md`, а предмет — стык:
|
||||
требование, которое одна задача выполнила, а соседняя незаметно отменила; два
|
||||
архивных change, по-разному описавшие одно поведение. Скажи проходу это прямо,
|
||||
иначе он пойдёт искать дельты и не найдёт ничего;
|
||||
- если задачи пересекались по файлам, добавь один `review-architecture` на
|
||||
интегрированный дифф с вопросом «не появился ли второй способ делать то, что
|
||||
уже делается» — именно он возникает, когда две задачи независимо решали
|
||||
похожее;
|
||||
- **заверши триажем.** Он единственный, кто агрегирует, и без него у находок нет
|
||||
ни оракула, ни пометки `инлайн`/`развилка` — а следующий абзац на неё
|
||||
опирается. Прогон из двух проходов без триажа — это сырые находки, выданные за
|
||||
разобранные;
|
||||
- **план триажу собери сам, здесь, — разметчика на этой сверке нет.** Триаж
|
||||
требует план обязательным входом: он сверяет размеченное с пришедшим, и без
|
||||
плана эта сверка не выполняется вовсе. Разметка задачи сюда не годится — она
|
||||
описывала одну задачу, а сверка идёт по интегрированной ветке. План здесь
|
||||
короткий и составляется по факту запуска:
|
||||
|
||||
```
|
||||
метка: не применяется — сверка стыка, а не ревью изменения
|
||||
тема дом глубина закрывает
|
||||
requirements openspec/specs/<capability-1>/ разбор specs (стык)
|
||||
requirements openspec/specs/<capability-2>/ разбор specs (стык)
|
||||
architecture docs/architecture.md разбор architecture
|
||||
+ источник docs/passport.md
|
||||
```
|
||||
|
||||
Темы, которых в этом списке нет (`autotests`, `conventions`, `security`,
|
||||
`operations`, свои темы проекта), назови строкой «не проверяется на сверке
|
||||
стыка: закрыто прогонами отдельных задач». Это не формальность — без такой
|
||||
строки отчёт сверки читается как полное ревью ветки.
|
||||
|
||||
Граф этой сверки — веер в один сток, и он такой же, как у обычного прогона:
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
merged["основная ветка после всех интеграций<br/>(финальный гейт зелёный)"]
|
||||
s1["review-specs: capability 1<br/>режим «стык после слияния»"]
|
||||
s2["review-specs: capability 2<br/>режим «стык после слияния»"]
|
||||
arch["review-architecture на интегрированном диффе<br/>(если задачи пересекались по файлам)"]
|
||||
tri["review-triage — сток"]
|
||||
|
||||
merged --> s1 --> tri
|
||||
merged --> s2 --> tri
|
||||
merged --> arch --> tri
|
||||
```
|
||||
|
||||
Замечания отрабатывай как одиночный пайплайн: `инлайн` чини сам, `развилка` —
|
||||
вопросом в запись; после правок — снова гейт.
|
||||
|
||||
### 9. Прибраться и доложить
|
||||
|
||||
- Убери worktree и ветки **только успешно влитых** задач, в конце
|
||||
`git worktree prune`. Worktree и ветки **провалившихся** не трогай — они нужны
|
||||
для ручного дожатия.
|
||||
- **Записей учёта батч не трогает** — их правит пайплайн внутри сабагента на
|
||||
шаге 12. Батч сообщает исход по каждой задаче; если какой-то сабагент дошёл до
|
||||
коммита, но закрытия не сделал (плагина нет, вызов не разрешился), скажи это
|
||||
строкой — иначе задача останется открытой молча.
|
||||
- Доложи кратко:
|
||||
- **исход по каждой задаче** одним из трёх слов, с хешем коммита;
|
||||
- **режим прогона** — по одной или волнами, и если волнами, то по чьей просьбе;
|
||||
порядок задач или состав волн, порядок интеграции, с пометкой, какие задачи
|
||||
шли по одной как замеряющие;
|
||||
- вопросы, записанные сабагентами, пачкой;
|
||||
- что дозапускалось на шаге 5 и почему; шло ли где-то ревью инлайн;
|
||||
- итог финальной сверки и ссылки на архивные change;
|
||||
- **`Урожай`** — отложенные находки всех задач одним списком, с провенансом.
|
||||
Задачи из него заводит тот, кто ведёт задачи проекта, а не батч;
|
||||
- **отдельно — провалившиеся** задачи с настоящей причиной и путём к
|
||||
оставленному worktree;
|
||||
- **границы покрытия сводной строкой**, включая задачи, чьи замеры снимались в
|
||||
общей волне, и ветки, где ревью шло инлайн.
|
||||
|
||||
## Тонкости
|
||||
|
||||
- **Изоляция параллельных тестов — цена параллельного режима, и проверяется она
|
||||
до первой волны.** Прежде чем гнать несколько прогонов разом, убедись, что
|
||||
тесты не делят фиксированный порт или файл БД (обычно берут временный каталог и
|
||||
эфемерный порт — тогда ок). Делят — такие задачи гони по одной, даже если
|
||||
просили параллельно, и скажи об этом строкой: просьба про параллельность, а не
|
||||
про сломанные тесты. В умолчательном режиме вопрос не встаёт вовсе — это одна
|
||||
из причин, по которым умолчание такое.
|
||||
- Поведенческая верификация внутри сабагента поднимает изменение вживую: в
|
||||
параллельном режиме следи, чтобы соседние worktree не дрались за порты и
|
||||
рабочие каталоги. Если проект умеет поднимать только один экземпляр — такие
|
||||
задачи в одну волну не ставь.
|
||||
- Ревью выполненного — **до** интеграции; это забота
|
||||
`av-dev-pipeline:task-pipeline` внутри каждого сабагента, дублировать не надо.
|
||||
- `openspec validate --strict` тоже внутри пайплайна задачи — не пропускай его
|
||||
своими правками на интеграции.
|
||||
- Крупная переработка, предложенная ревью внутри задачи, — развилка: не вливай
|
||||
молча, вынеси в доклад.
|
||||
- Держи вызывающего в цикле короткими репликами на переходах фаз (план → прогон
|
||||
задач → интеграция → финальная сверка), но не проси подтверждать механику.
|
||||
Reference in New Issue
Block a user