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