# Сценарий «решение»
Способ решения известен, спорно только как. Проводит задачу от постановки до
закрытия и **пишет код**: цикл Spec Driven Development с одним плановым стопом —
объяснением после ревью дизайна.
Сценарий выбирается развилкой на входе скилла ([SKILL.md](../SKILL.md), раздел
«Развилка: какой сценарий») и называется вслух первой репликой. Здесь только его
ход; общее для обоих сценариев — вход, обращение к соседним плагинам, правило
записанного вопроса, правило необратимого — живёт в SKILL.md и тут не
пересказывается.
**OpenSpec — жёсткая предпосылка именно этого сценария** (SKILL.md,
«Предпосылки»): на нём стоят шаги 2, 6 и 8, проход `review-specs` и ревью
дизайна.
Тонкая обёртка над каноническими скиллами `opsx:propose` / `opsx:apply` /
`opsx:archive` — зови их через Skill, не переизобретай их шаги. Ревью — скилл
`av-dev:code-review`; он же держит правило выбора метки, а называет её агент
`review-scope` — один раз на задачу, для обеих стадий ревью.
## Ход работы
```mermaid
flowchart TD
in["сценарий выбран: решение"]
s1["1. прочитать задачу
критерии приёмки выписать сразу"]
s2["2. opsx:propose — change, дельта-спеки, tasks.md"]
s3["3. разметка — review-scope:
размер, сложность, метка, план тем"]
s4["4. ревью дизайна, состав по метке
+ отработка замечаний"]
s5(["5. ЧЕКПОИНТ: объяснение
в чём проблема, как решаем,
чем рискуем"])
s6["6. opsx:apply — код, гейт,
поведенческая верификация"]
s7["7. ревью кода, та же метка
+ отработка замечаний"]
s8["8. opsx:archive"]
s9["9. синк документации — av-dev:doc-sync"]
s10["10. коммит работы — av-dev-git:commit"]
s11["11. закрыть задачу — av-dev:task-track,
вторым коммитом учёта"]
in --> s1
s1 --> s2 --> s3 --> s4 --> s5 --> s6 --> s7 --> s8 --> s9 --> s10 --> s11
s3 -.->|"план задачи: та же метка"| s7
s5 -.->|"скорректировать:
меняются дельта-спеки"| s3
s7 -.->|"находка отменяет дизайн:
меняются дельта-спеки"| s3
```
Схема — **сводка**: содержание каждого шага в его разделе ниже, и при
расхождении прав текст.
## Наблюдаемые исходы сценария
Четыре, и каждый обязан быть назван в докладе прямо:
- **сделана** — определение сделанного выполнено целиком;
- **не доведена** — с причиной и с записанным вопросом; что именно сделано и до
какой границы, названо явно. Сюда же попадает чекпоинт, на котором человек
решение не одобрил;
- **оказалась крупнее задачи** — распознаётся **до заведения change**, иначе его
придётся выбрасывать. Дальше — декомпозиция, и это не работа этого скилла;
- **нужна разведка** — очевидного способа решения нет, и это выяснилось уже в
работе. Стоп с названной причиной; кода не написано ни строки **намеренно**.
Разведка идёт следующим прогоном.
## Определение сделанного
Задача сделана, когда верно всё:
1. гейт проекта зелёный;
2. ревью проведено, **план прогона сверен с исходом по каждой теме**, темы без
отчёта и без дома названы в границах покрытия;
3. решение прошло чекпоинт и не разошлось с одобренным — либо разошлось, и
чекпоинт был пройден заново;
4. change заархивирован, дельты влиты в актуальные спеки;
5. коммит сделан в текущую ветку;
6. **критерии приёмки, если проект их дал, выписаны поимённо, и по каждому назван
оракул и наблюдаемый исход** — «прогнал вот это, увидел вот то». Это **доклад,
а не сертификация: приёмка — не работа этого скилла.** Исполнитель, ставящий
себе галочку «принято», проверяет свою работу своим же взглядом — по границе
это может делать только приёмщик, разведённый с исполнителем. Критерии приходят
снаружи; скилл их не сочиняет и не занижает. Расхождение «по каждому критерию
исход есть, а суть задачи не достигнута» — дефект критериев, и о нём
сообщается, а не молча дорабатывается.
## Шаги
### 1. Прочитать задачу
Прочитай запись и связанные спеки и черновики.
Проект даёт задаче **критерии приёмки** — выпиши их сразу: на шаге 2 они уезжают
в `tasks.md` change. Файл задачи может быть удалён до коммита, а критерии обязаны
его пережить.
Здесь же проверка на «крупнее задачи»: видно, что одним заходом это не
мерджится, — объявляй исход **до** заведения change.
### 2. Завести change — `opsx:propose`
Вызови Skill `opsx:propose`. Получаем `proposal.md`, дизайн, дельта-спеки
(`ADDED`/`MODIFIED`/`REMOVED Requirements`), `tasks.md`. Каждое `### Requirement`
содержит `SHALL`/`MUST`; структурные заголовки английские, сценарии
`GIVEN/WHEN/THEN`. Прогони `openspec validate --strict `.
Критерии приёмки задачи, если они были, копируются в `tasks.md` отдельным блоком.
Задаче предшествовала разведка — её записка и отвергнутые варианты **уже
записаны** в документах канона (`docs/research/`, `docs/adr/`): сошлись на них из
`design.md`, а не переписывай второй раз. Варианты, разобранные без разведки
(способ был очевиден, но у него оказались оттенки), — в `design.md`, с причиной
отказа по каждому отвергнутому.
**`proposal.md` пишется так, чтобы его понял человек, не читавший спек.** Это не
стилистическое пожелание: из него собирается чекпоинт шага 5, и переписывать его
там заново значит завести второй дом для одного объяснения. Требование стоит в
`openspec/config.yaml`, `rules.proposal` — то есть применяется в момент
порождения артефакта, а не вспоминается после.
### 3. Разметка задачи — агент `review-scope`
**Один запуск на всю задачу, и он обслуживает обе стадии ревью.** Запусти
агента `review-scope`, дав ему корень проекта, идентификатор change, базу диффа и
запись задачи. Кода на этот момент нет, и это условие его работы, а не помеха.
Он возвращает **план задачи**:
- **размер** (малое / среднее / крупное) и **сложность** (знакомое /
незнакомое), каждое с обоснованием по факту;
- **метку** как максимум по двум осям: `small`, `medium` или `large`;
- **состав ревью дизайна** — что звать на шаге 4;
- **таблицу тем** «тема → дом → глубина → кто закрывает» — для шага 7;
- разнесение документов проекта по трём категориям и строку про директивы.
**Метку выбираешь не ты.** Раньше состав ревью дизайна называл сам оркестратор —
то есть тот, кто только что довёл предложение до `propose`. Разведённости с
автором в этой точке не было вовсе; теперь есть.
**План держи в контексте до конца задачи.** На диск он не пишется: файл-план стал
бы четвёртым артефактом рядом с `proposal.md`, `tasks.md` и `design.md`, пережил
бы задачу и разошёлся бы с ней молча. Прервался прогон — повтори шаг 3, это самый
дешёвый его проход.
**Разметка повторяется ровно в одном случае** — если правки изменили сами
**дельта-спеки**: план выведен из них, и план по отменённым требованиям назовёт
не те темы. Во всех прочих случаях, включая переделку формы кода на шаге 7,
метка остаётся прежней.
### 4. Ревью дизайна — ДО кода, состав по метке
Вызови Skill **`av-dev:code-review`**, дав ссылку на change ``,
**план разметки с шага 3** и указание, что это ревью дизайна.
Состав приходит планом, а не решается здесь:
| Метка | Проходы на предложении |
|---|---|
| `small` | `specs` |
| `medium` | `specs`, `rubric` |
| `large` | `specs`, `rubric`, `architecture` + вопрос автору о трёх формах решения |
`review-specs` в режиме «дизайн ДО кода» идёт **на каждой задаче**: это самый
дешёвый проход конвейера, и он ловит то, что на готовом коде уже не чинят.
Остальные включаются меткой, потому что стадия стоит на каждой задаче и каждый
лишний проход здесь умножается на число задач.
Смысл стадии: архитектурная находка на готовом коде стоит переписывания и потому
игнорируется — та же находка здесь стоит абзаца обсуждения. Если `review-rubric`
запускался, перенеси его рубрику в `tasks.md` как приёмочные критерии; там же уже
лежат критерии от постановки, если они были.
**Отработка замечаний, и она идёт до чекпоинта, а не после:**
- мелочь и явные улучшения — правь сам в спеках и дизайне;
- развилки (компромисс, scope, инвариант) — **не в запись, а в чекпоинт**: он
следующим шагом, и это ровно то, ради чего он поставлен здесь;
- после правок перепрогони `openspec validate --strict `.
### 5. Чекпоинт: объяснение
**Остановись и объясни человеку, что происходит.** Единственный плановый стоп
этого сценария, и он обязателен для всякой задачи.
Он стоит **после** ревью дизайна намеренно. Человек читает объяснение, уже
просеянное машиной: то, что поймал бы `review-specs`, до него не доходит, а
внимание — самый дорогой ресурс процесса, и тратить его на выловимое машиной
нельзя.
**Объяснение не сочиняется заново — оно собирается из артефактов**, `proposal.md`
и `design.md`. Третий пересказ был бы третьим домом одного и того же и разошёлся
бы с обоими. Что показываешь:
- **в чём проблема** — словами домена из паспорта, без имён модулей и функций;
- **как решаем** — суть одним абзацем. Не пересказ дельта-спек: спека нормирует,
а здесь объясняют;
- **что человек увидит иначе**, когда это будет сделано;
- **чего мы намеренно не делаем** и почему — граница scope ловится хуже всего;
- **чем рискуем и что осталось нерешённым** — сюда съезжаются развилки,
накопленные до этого места, и находки ревью с пометкой `развилка`;
- **что дальше**, если возражений нет.
Проверка на «простой язык» одна и механическая: **в тексте нет `SHALL`, нет имён
файлов и функций там, где вещь называется по-русски, и нет слов, которых нет в
паспорте проекта.** Не проходит — переписывай, а не объясняй, почему иначе
нельзя.
Длина — экран. Длинное объяснение не читают, а пролистывают, и чекпоинт
превращается в ритуал одобрения.
Три исхода:
- **согласен** — идёшь на шаг 6;
- **скорректировать** — правишь спеки и дизайн по сказанному. Изменились
**дельта-спеки** — повтори шаг 3 (разметка выведена из них) и ту часть ревью
дизайна, которой касается правка; затем чекпоинт **заново**. Правка внутри
дизайна без спек — повтори только чекпоинт;
- **не одобрено** — исход «не доведена» с причиной. Change остаётся
незаархивированным, задача не закрывается, ничего не коммитится наполовину.
### 6. Написать код — `opsx:apply`
Вызови Skill `opsx:apply` для реализации `tasks.md`. Код — по конвенциям проекта
(каталог `docs/conventions/`). Меняешь схему — обнови её описание в документации
тем же change, если проект этого требует: гейт обычно это проверяет.
Прогони гейт и добейся зелёного — он же гейт следующего шага.
**Поведенческая верификация.** Если задача меняет реальное поведение (новый
эндпоинт, разбор входа, схема, форма ответа) — зелёных юнит-тестов мало. Подними
изменение вживую командой из раздела команд `CLAUDE.md` и прогони сценарий.
Пропусти только для чисто внутренних правок без наблюдаемого рантайма.
**Сервис не оставляем лежать.** Если запуск упал — почини или откати до конца
шага.
### 7. Ревью кода — та же метка
Вызови Skill **`av-dev:code-review`**, дав ссылку на change ``,
базу диффа, **план разметки с шага 3** и режим запуска.
**Метку ты не выбираешь, и это правило, а не упрощение.** Её назвал
`review-scope` ещё на шаге 3 — по размеру и сложности, с обоснованием по каждой
оси. Причина в разведённости: ты только что написал этот код, и решать, насколько
глубоко его проверять, тебе нельзя — под давлением «я почти закончил» решение
известно заранее. Правило выбора живёт в скилле конвейера —
`av-dev:code-review`, `references/review-levels.md`; проектные
триггеры — в `docs/review.*`, подраздел «Триггеры метки».
**Метка не пересматривается по факту диффа.** Дифф может выйти крупнее, чем
ожидалось при разметке, — это не повод её поднимать: пересмотр означал бы второй
запуск разметчика, ровно то, ради устранения чего он и переехал на шаг 3.
**Считаешь метку заниженной — скажи это в докладе строкой, а не переспорь.**
Разметчик вправе и поднять, и понизить; твоё несогласие это факт для человека, а
не команда конвейеру. Место, где такое несогласие превращается в изменение
правил, — журнал дефектов `docs/review.md`, и только постфактум.
**Плана нет — ревью кода не запускается.** Триаж требует план обязательным
входом: без него он не может сверить, все ли размеченные темы вернули отчёт, а
эта сверка — единственная защита от молчащего пропуска. Потерял план (прервалась
сессия, ушёл контекст) — повтори шаг 3, а не гони прогон без него.
**Режим по умолчанию — `по графу`, и обосновывать его не надо.** Конвейер сам
знает свои рёбра: гейт открывает проходы с мнением, проходы с пометкой «держит
машину» идут цепочкой (иначе замеры портят друг друга и находка выглядит
доказанной), триаж — сток. Просить **`линейно`** нужно только по причине, и она
называется строкой: так сказал оператор; машина занята чем-то ещё; идёт разбор
самого конвейера.
Скилл сам гоняет гейт, нужные проходы и обязательный триаж. Возвращает отчёт с
потолком 7 пунктов, разметкой `Действие: инлайн | развилка` и секцией границ
покрытия.
**Сверь план прогона с исходом, прежде чем коммитить.** Отчёт начинается планом
разметчика — таблицей «тема → дом → глубина → кто закрывает», — и против каждой
темы обязан стоять исход. Тема без отчёта и тема без дома — разные вещи, и обе
должны быть названы. Реестр короткий (шесть тем ядра плюс свои) — сверка стоит
одного взгляда.
#### Отработка, и здесь появляется одно новое правило
Помеченное `инлайн` чини сам и не логируй. `развилка` — вопросом в запись (он уже
сформулирован триажем, его остаётся перенести). После правок — снова гейт.
**Находка, отменяющая одобренный дизайн, отменяет и одобрение.** Признак
проверяемый: **меняются ли дельта-спеки**.
- не меняются — находка внутри дизайна, дожимай сам, это обычная отработка;
- меняются — решение стало другим, а одобрено было прежнее. Повтори шаг 3
(разметка выведена из дельта-спек) и **вернись на чекпоинт шага 5** с тем, что
изменилось и почему.
**Это правило старше правила о развилке.** Находка класса `развилка`, чьё
основание — «надо менять спеку», подпадает под оба; побеждает возврат на
чекпоинт, а вопрос в запись при нём остаётся, но возврата не заменяет. Иначе
одобренный дизайн переделывался бы записанным вопросом, то есть молча.
Тихо переделать утверждённое нельзя. Чекпоинт, который можно обойти находкой
ревью, не значит ничего, а человек при этом уверен, что одобрил именно то, что
уехало в коммит.
**Урожай — списком, не задачами.** Отложенные находки (реальный `major` не для
этого мерджа, развилка, решённая «потом», пачка `nit`) собери в секцию доклада
`Урожай`: формулировка, оракул, провенанс. Задачи из него **заводит не этот
скилл** — их заводит `av-dev:task-track` своим сценарием «задачи из ревью и
аудита»: своя нарезка, свой формат, свои правила дублей. Твоя обязанность — не
потерять и передать.
**Границы покрытия из отчёта не выбрасывай** — они уезжают в финальный доклад
сжатой строкой. Отчёт, из которого исчезло «что проверить было невозможно»,
превращается в ложное ощущение проверенности.
**Отчёт триажа сохрани вместе с change (`openspec/changes//review/`; шаг 8
унесёт его в архив вместе с change) — это обязательно, а не «если удобно».** По
нему потом видно, что было найдено и что из этого осталось в урожае. И это
единственный **независимый** артефакт о составе прогона: своей прозе здесь верить
нельзя — она написана тем же, кто мог проход и пропустить.
### 8. Архивировать — `opsx:archive`
Вызови Skill `opsx:archive`: change уезжает в архив, дельты вливаются в
актуальные спеки. Не пропускай `openspec validate --strict` перед этим.
### 9. Синк документации
**Вызови Skill `av-dev:doc-sync`**: он владеет содержимым документов канона и
ведёт чек-лист синка.
**Правило одно и оно жёсткое: принуждённое отрицание.** Доклад обязан назвать
**каждый** документ канона — либо чем он обновлён, либо «не требуется, потому
что…». Нетронутые группируются одной строкой с общей причиной. Список триггеров
прозой уже проверен на живом проекте и дал 6 записей ADR на 43 изменения;
работает только обязательное отрицание.
**Список документов и их триггеров здесь не дублируется** — он в чек-листе скилла
`av-dev:doc-sync`, и копия уже однажды разошлась с оригиналом, потеряв два
триггера.
**Плагина `av-dev-docs` в проекте нет** — путь в его дерево не разрешится ниоткуда,
поэтому за списком иди в **свой** reference:
[references/project-facts.md](../../review/references/project-facts.md)
конвейера ревью перечисляет все документы канона с их предметом. Пройди по этому
перечню — каждый документ получает строку, отрицание остаётся обязательным.
**Двух домов в том перечне нет намеренно, а синку они нужны: `docs/adr/` и
`docs/research/`.** Проход ревью их не открывает — процессные, — но ADR как раз
**главный выход синка**: решение, принятое по ходу задачи, без этой строки
теряется систематически. Добавь их к перечню руками: `adr/` — решение с ценой,
принятое в этой задаче; `research/` — если по ходу узналось новое о внешнем мире
(записку разведки, предшествовавшей задаче, пишет не этот сценарий).
Триггеры при этом ты знаешь хуже, и это называется в докладе строкой: «синк
сделан по перечню документов, без списка триггеров — плагина `av-dev-docs` нет».
Канона в проекте тоже нет — назови это исходом и предложи `av-dev:doc-canon`.
### 10. Коммит
Коммить **в текущую ветку** (`git rev-parse --abbrev-ref HEAD`), сам ветку не
создавай и не переключай, ничего не пушь.
Сообщение — по-русски, **скиллом `av-dev-git:commit`**: форму сообщения держит
он, и здесь она не пересказывается. Вызов не разрешился — плагина в проекте нет:
напиши сообщение сам и скажи строкой доклада, что форму коммита не сверял никто.
Одна задача — один осмысленный коммит.
### 11. Закрыть задачу — **после коммита, не раньше**
**Вызови Skill `av-dev:task-track`** и попроси закрыть задачу как реализованную —
он владеет форматом и двигает строку индекса сам. Путь к его скрипту не выясняй и
индексы руками не правь: мост между плагинами — вызов скилла, а не путь.
**Порядок обязателен.** Закрытие удаляет файл задачи; сделанное до коммита оно
оставило бы задачу закрытой без единого следа работы, если шаг 10 упадёт.
**Закрытие тоже коммитится — вторым коммитом, тут же.** Удаление файла задачи и
правка индексов (их имена знает `av-dev-tasks`, не ты) — это правки в рабочем
дереве, и оставить их незакоммиченными нельзя: закрытие, не доехавшее до основной
ветки, оставит задачу открытой молча, а опора «индексы под git показывают, что и
когда закрыто» без коммита — пустые слова. Сообщение короткое, про учёт, а не про
работу: `закрыта задача `. Это второй коммит осознанно: правило «одна задача
— один осмысленный коммит» про работу, а учёт — не работа.
Плагина в проекте нет — вызов не разрешится. Тогда **ничего не выдумывай**: скажи
в докладе, что учёт задач остаётся за владельцем, и назови исход.
## Доклад решения
Общее ядро доклада — в SKILL.md; сверх него сценарий решения обязан назвать:
- **что было одобрено на чекпоинте и совпало ли с тем, что уехало в коммит** —
расхождение здесь называется прямо, даже если оно мелкое;
- ссылка на архивный change и хеш коммита;
- по каждому критерию приёмки, если они были: **оракул и наблюдаемый исход** —
это доклад приёмщику, а не отметка «принято»;
- **`Урожай`** — отложенные находки списком (формулировка, оракул, провенанс);
- **одна строка границ покрытия**: какая метка и режим гонялись, какие проходы не
запускались и что проверить было невозможно. Доклад без неё сообщает
«проверено», не сообщая, что именно.
## Тонкости сценария
- Гейт блокирует: пока он красный, проходы с мнением не запускаются. Чинить и
перезапускать, а не «посмотреть заодно».
- Стиль правок — заточка под проект и конвенции, по размеру задачи, без
улучшений заодно.
- **Занизить метку ревью, пропустить тему или проскочить чекпоинт — самый дешёвый
способ «ускориться», и он же самый дорогой по последствиям.** Защита устроена
так, что регулятора у тебя нет: метку выбирает разметчик **до того**, как ты
написал код, план сверяется по темам, непокрытое называется строкой, а
расхождение с одобренным — отдельным пунктом доклада.
- **Заведение задач из урожая ревью — не твоя работа.** Отложенные находки
отдаются **списком**; превращает их в задачи `av-dev:task-track`, у него на
этот вход отдельный сценарий «задачи из ревью и аудита». Плагина нет — урожай
остаётся списком в докладе, и это говорится строкой.
- **Способ решения ты не выбираешь.** Он приходит известным: из постановки, из
разведки, от человека. Выбор между двумя подходами с разной ценой делается в
разведке, у своего чекпоинта, — не по ходу этого сценария.