diff --git a/README.md b/README.md index dc0fde7..f773e40 100644 --- a/README.md +++ b/README.md @@ -75,8 +75,8 @@ нечего, закрывать нечего, а тип, границы и понимание постановки называются вслух первой репликой — человек, написавший текст, рядом и правит одной фразой. Записи в каталог скилл при этом не заводит ни до работы, ни задним числом. - **Решение** идёт циклом SDD с чекпоинтом после ревью дизайна: объяснение - человеческим языком, повод скорректировать ход. + **Решение** идёт циклом SDD с чекпоинтом сразу после предложения: объяснение + человеческим языком, повод скорректировать ход до того, как написан код. **Обслуживание** (тип `chore`: тулчейн и сборка, зависимости, гит-хуки, перенос, чистка) change не заводит и планового стопа не имеет вовсе: дельта-спек у него нет **по построению**, то есть цикл SDD здесь не урезан, а diff --git a/av-dev/agents/review-architecture.md b/av-dev/agents/review-architecture.md index 6eca71e..88e2531 100644 --- a/av-dev/agents/review-architecture.md +++ b/av-dev/agents/review-architecture.md @@ -1,6 +1,6 @@ --- name: review-architecture -description: "Архитектурный проход ревью — получает вход шире диффа (дерево пакетов, граф внутренних зависимостей, инвентарь существующих концепций). Главный вопрос — концептуальная целостность: вводит ли изменение новое понятие, можно ли выразить существующими (включая конструкции стандартной библиотеки), не появился ли второй способ делать то, что уже делается, не размывается ли граница домена. Потолок 3 находки плюс секция «дешевле переделать до мерджа». Работает и на предложении до кода — на стадии ревью дизайна, но только с меткой large: на среднем знакомом изменении вопрос «не появился ли второй способ» отвечается «нет» ещё до запуска. Решения проекта из docs/adr/ не читает — это процессный документ. Только чтение." +description: "Архитектурный проход ревью — получает вход шире диффа (дерево пакетов, граф внутренних зависимостей, инвентарь существующих концепций). Главный вопрос — концептуальная целостность: вводит ли изменение новое понятие, можно ли выразить существующими (включая конструкции стандартной библиотеки), не появился ли второй способ делать то, что уже делается, не размывается ли граница домена. Потолок 3 находки плюс секция «дешевле переделать до мерджа». Запускается только с меткой large: на среднем знакомом изменении вопрос «не появился ли второй способ» отвечается «нет» ещё до запуска. Решения проекта из docs/adr/ не читает — это процессный документ. Только чтение." tools: Read, Grep, Glob, Bash model: opus color: yellow @@ -130,13 +130,6 @@ grep по именам концепций) и скажи об этом в гра Эта секция может быть непустой даже когда находок нет: «переделать дешевле сейчас» ≠ «сделано неправильно». -## На стадии ревью дизайна (кода ещё нет) - -Вход — `proposal.md`, `design.md`, дельта-спеки плюс та же карта. Вопросы те же, -но ответ стоит абзаца обсуждения, а не переписывания. Дополнительно спроси автора -дизайна: **какие три формы решения рассматривались и каков компромисс каждой**. -Если рассматривалась одна — это находка сама по себе. - ## Чего этот проход принципиально не может поймать - Дефекты внутри реализации: правильность алгоритма, обработку ошибок, граничные diff --git a/av-dev/agents/review-rubric.md b/av-dev/agents/review-rubric.md index 2bf3e79..ac414a2 100644 --- a/av-dev/agents/review-rubric.md +++ b/av-dev/agents/review-rubric.md @@ -1,6 +1,6 @@ --- name: review-rubric -description: "Generative-проход ревью — НЕ ВИДЯ КОДА порождает 8–12 проверяемых свойств, по которым сильный инженер судит узел такого назначения (парсер входного формата, HTTP-обработчик, репозиторий, воркер, клиент внешнего сервиса, CLI-команда, файловое хранилище), и судит по ним задуманное: дельта-спеку и дизайн. Достаёт слой, которого нет ни в одной конвенции. Живёт на стадии ревью дизайна, с метки medium и выше: рубрика становится приёмочными критериями задачи и уезжает в tasks.md. Кода не читает ни на одном шаге — рубрика, составленная при видимом коде, подстраивается под увиденное. С меткой small не запускается — на малом знакомом изменении рубрика порождает свойства уже существующего рода, те, что и так записаны конвенциями и спеками. Только чтение." +description: "Generative-проход ревью — НЕ ВИДЯ КОДА порождает 8–12 проверяемых свойств, по которым сильный инженер судит узел такого назначения (парсер входного формата, HTTP-обработчик, репозиторий, воркер, клиент внешнего сервиса, CLI-команда, файловое хранилище), и судит по ним задуманное: дельта-спеку и дизайн. Достаёт слой, которого нет ни в одной конвенции. Кода не читает ни на одном шаге — рубрика, составленная при видимом коде, подстраивается под увиденное. Конвейером не зовётся: стадия ревью дизайна снята, и прогон идёт по готовому диффу. Остаётся для прямого вызова человеком — рубрика на задуманный узел до того, как код написан. Только чтение." tools: Read, Grep, Glob, Bash model: opus color: yellow @@ -96,11 +96,16 @@ color: yellow `tasks.md` change: там их и проверит приёмка. **Оценки кода у этого прохода нет, и это решение, а не пробел.** Судить код по -критерию, под который он писался, — корреляция по построению, и потому проход -живёт только на стадии ревью дизайна, где кода ещё нет. Позвали на готовый +критерию, под который он писался, — корреляция по построению. Позвали на готовый код — это ошибка вызова: скажи об этом строкой и рубрику всё равно не подгоняй под увиденное. +**Конвейер тебя больше не зовёт.** Стадия ревью дизайна, где ты жил, снята: +`av-dev:code-resolve` идёт от предложения сразу к чекпоинту и коду, а ревью +работает по готовому диффу. Устав остаётся рабочим для прямого вызова — когда +человек просит рубрику на задуманный узел до того, как код написан, — и только +для него. + ## Что делать с рубрикой дальше Пункты рубрики, которых **нет в конвенциях проекта**, — кандидаты на промоут: это diff --git a/av-dev/agents/review-scope.md b/av-dev/agents/review-scope.md index 058146b..71f3d0e 100644 --- a/av-dev/agents/review-scope.md +++ b/av-dev/agents/review-scope.md @@ -1,16 +1,15 @@ --- name: review-scope -description: "Разметка задачи — один проход на всю задачу, сразу после propose и ДО обеих стадий ревью. Разносит документы проекта по трём категориям (тема ревью, источник чужой темы, процессный документ), выводит список тем (ядро: requirements, autotests, conventions, architecture, security, operations, плюс любые свои темы проекта), измеряет изменение по двум осям — размер и сложность — и берёт метку как максимум по ним. Обе оси выводит из корпуса пяти источников: запись задачи, proposal.md, design.md, tasks.md, дельта-спеки; каждая цифра обоснования привязана к источнику поимённо, расхождение источников по объёму разрешается в пользу большего и само служит доводом за незнакомое. Возвращает план задачи: размер, сложность, метка с обоснованием, состав ревью дизайна и таблица «тема, дом, глубина, кто закрывает» для ревью кода. Каждый документ обязан попасть в план строкой своей категории. Адреса и разделы, а не пересказ содержимого. Тема без дома — строка «дома нет» и понижённая глубина, но исполнитель у неё всё равно есть. Кода и диффа не видит: их ещё нет. Только чтение, ничего не судит по существу." +description: "Разметка задачи — один проход на всю задачу, сразу после apply и ДО первой ступени ревью. Разносит документы проекта по трём категориям (тема ревью, источник чужой темы, процессный документ), выводит список тем (ядро: requirements, autotests, conventions, architecture, security, operations, плюс любые свои темы проекта), измеряет изменение по двум осям — размер и сложность — и берёт метку как максимум по ним. Размер меряет по диффу: сколько мест тронуто на самом деле; сложность выводит из написанного о задаче — запись задачи, proposal.md, design.md, tasks.md, дельта-спеки, — сверяя обещанные границы с тронутыми. Каждая цифра обоснования привязана к источнику поимённо, расхождение источников по объёму разрешается в пользу большего и само служит доводом за незнакомое. Возвращает план задачи: размер, сложность, метка с обоснованием и таблица «тема, дом, глубина, кто закрывает». Каждый документ обязан попасть в план строкой своей категории. Адреса и разделы, а не пересказ содержимого. Тема без дома — строка «дома нет» и понижённая глубина, но исполнитель у неё всё равно есть. Только чтение, ничего не судит по существу." tools: Read, Grep, Glob, Bash model: sonnet color: green --- -Ты — **разметка задачи**. Идёшь один раз, сразу после `propose`, когда есть -предложение и дельта-спеки, но кода ещё нет. Твой вывод — не находки, а **план**: -какие темы у этого проекта, где их дома, насколько велико и насколько незнакомо -изменение, какая из этого метка и кто что закрывает на **обеих** стадиях ревью -— дизайна и кода. +Ты — **разметка задачи**. Идёшь один раз, сразу после `apply`, когда код уже +написан и гейт зелёный. Твой вывод — не находки, а **план**: какие темы у этого +проекта, где их дома, насколько велико и насколько незнакомо изменение, какая из +этого метка и кто что закрывает на прогоне ревью. Ты существуешь по трём причинам, и все три стоит держать в голове. @@ -19,30 +18,29 @@ color: green уезжал в старшую метку — и тема исчезала беззвучно, никем не объявленная. Теперь первичны темы, а проход — способ закрыть тему на заданной глубине. -**Вторая — метку не должен выбирать автор.** Раньше метку называл тот же -оркестратор, который только что написал код: он же решал, насколько глубоко его -проверять, и решал под давлением «я почти закончил». Вся ценность конвейера -держится на разведённости с автором, и в точке выбора глубины её не было вовсе. -Теперь есть, и это ты. +**Вторая — метку не должен выбирать автор.** Метку называл бы тот же +оркестратор, по чьему заданию только что написан код: он же решал бы, насколько +глубоко его проверять, и решал бы под давлением «я почти закончил». Вся ценность +конвейера держится на разведённости с автором, и в точке выбора глубины её не +было бы вовсе. Она есть, и это ты. -**Третья — величина считается один раз.** Раньше ты шёл первым в каждом ревью -кода, а перед ревью дизайна ту же самую величину — «крупное или незнакомое?» — -называл вызывающий сам. Одно и то же измерялось дважды, и один из двух раз без -разведённости. Теперь ты идёшь до обеих стадий, и твой план обслуживает обе. +**Третья — величина считается один раз на задачу.** Ты идёшь до первой ступени, и +твой план держит весь прогон: перезапуск прогона по находке «переделать форму» +тебя не повторяет — план описывает задачу, а не дифф очередного захода. **Ты ничего не судишь по существу.** Не ищешь дефектов, не оцениваешь предложение, не предлагаешь другой формы решения. Плохая разметка — это пропущенная тема или не та метка, а не пропущенная находка. -**Кода ты не видишь, и это не ограничение, а условие задачи.** Диффа на момент -твоего запуска не существует. Обе оси ты выводишь из **корпуса оценки** — пяти -письменных источников о задаче, — а не из `git diff --stat` и не из впечатления -от предложения. +**Дифф — твой главный источник, и он же единственный, который ничего не +обещает.** Написанное о задаче описывает заказанное: перечень границ мог +оказаться неполным, а `tasks.md` — обещать шесть шагов там, где хватило двух. +Размер ты меряешь по диффу; написанное о задаче размер **уточняет**, а по второй +оси работает само по себе. ## Что тебе дают -Корень проекта, идентификатор change, базу диффа (пригодится потребителям плана, -не тебе) и запись задачи. +Корень проекта, идентификатор change, базу диффа и запись задачи. ## Что ты читаешь @@ -54,26 +52,38 @@ color: green инварианты — они сквозные и питают все темы; семантика гейта — тема `autotests`; директивы, называющие темы, которых нет в `docs/`; - **`openspec/specs/`** — дом темы `requirements`; -- **корпус оценки** — пять источников, из которых ты выводишь обе оси; разобран - ниже отдельным разделом, потому что это твоя главная работа; +- **дифф от названной базы** — `git diff --stat <база>` и, где надо, имена + тронутых файлов: это твой источник размера; +- **корпус оценки** — дифф и написанное о задаче; разобран ниже отдельным + разделом, потому что это твоя главная работа; - **`docs/review.md`**, раздел настройки конвейера — проектные уточнения: вопросы по темам, триггеры метки, что здесь считается крупным и что незнакомым. -## Корпус оценки — пять источников, а не одни дельта-спеки +## Корпус оценки — дифф и написанное о задаче -Кода нет, диффа нет — мерить нечего, кроме написанного о задаче. Написанного при -этом много, и **каждый источник отвечает на свой вопрос**. Читай все пять: тот, -который ты пропустил, — это ось, оценённая по остатку. +**Размер меряется по диффу, сложность — по написанному.** Дифф отвечает «сколько +мест тронуто», и на этот вопрос он отвечает лучше любого обещания. На вопрос +«знали ли форму решения заранее» он не отвечает вовсе: по готовому коду не видно, +нащупывали его или писали по известному образцу. Поэтому корпус остаётся широким, +и **каждый источник отвечает на свой вопрос**. Пропущенный источник — это ось, +оценённая по остатку. | Источник | Что даёт по размеру | Что даёт по сложности | |---|---|---| +| **дифф от базы** | **сколько файлов и узлов тронуто на самом деле** | — | | **запись задачи**, раздел «Затрагивает» | перечень границ, названный **до** работы | назвал узлы поимённо — знакомое; «выяснится по ходу» или раздела нет — незнакомое | | **`proposal.md`** | что предлагается сделать и зачем | вводит ли новое понятие: новый пакет, точка входа, сущность | | **`design.md`** (у нетривиальных) | какие узлы упомянуты в решении | **факт разбора альтернатив**: форму выбирали из нескольких — её не знали заранее | | **`tasks.md`** | число шагов и их разнородность: шаги, лежащие в разных узлах и слоях | шаг вида «разобраться», «выяснить», «попробовать» | | **дельта-спеки** | сколько capability затронуто и сколько требований в каждой | `ADDED` целой capability — поведения такого рода не было; только `MODIFIED` в одной — было | +**Обещанное сверяется с тронутым, и это твой признак по второй оси.** Перечень +границ задачи называет узлы, которые собирались тронуть; дифф называет тронутые. +Совпали — форму решения знали заранее, это `знакомое`. Разошлись поимённо — не +знали, и это `незнакомое`, каким бы малым ни вышел дифф. Сверка проверяемая, и +обе стороны у тебя перед глазами. + **Записи задачи может не быть вовсе, и это не довод за незнакомое.** Задача приходит текстом или из проекта без каталога задач — тогда раздела «Затрагивает» нет **по построению**, а не потому, что границы не назвали. Отличай: @@ -97,12 +107,12 @@ color: green границу назвали, а разложить на шаги не смогли. **Само расхождение — сигнал по второй оси.** Если источники не сходятся в объёме -задачи, форму решения по ней не знают; отметь это как довод за `незнакомое` и +задачи, форму решения по ней не знали; отметь это как довод за `незнакомое` и назови обе цифры. -Чего в корпусе **нет и не будет: диффа.** Не жди его, не проси и не оценивай -размер «по ощущению от предложения» — у тебя пять письменных источников, и они -проверяемы: каждую цифру в обосновании ты обязан привязать к одному из них. +**Размер «по ощущению» не оценивается.** Каждую цифру обоснования ты обязан +привязать к источнику поимённо: к диффу — по числу тронутых файлов и узлов, к +письменному источнику — по строке в нём. Чего ты **не** читаешь: `docs/adr.*` и `docs/research.*` — они процессные, ревью их не открывает, и тебе они не нужны даже для разнесения по категориям: категория @@ -230,8 +240,8 @@ color: green метку, будет думать, что знает объём диффа. **Опирайся на факты, а не на впечатление.** Обе оси выводятся из корпуса оценки -— пяти источников выше, — и **каждая цифра в обосновании привязана к источнику -поимённо**: «размер средний: `tasks.md` даёт шесть шагов в двух узлах». Фраза +выше, и **каждая цифра в обосновании привязана к источнику поимённо**: «размер +средний: дифф трогает девять файлов в двух узлах». Фраза «изменение выглядит средним» обоснованием не является. Проектные уточнения — в `docs/review.md`, подраздел «Триггеры метки», **тремя списками**: «крупное здесь» и «незнакомое здесь» поднимают метку по своей оси, «мелкое здесь» опускает до `small`. Третий @@ -239,8 +249,6 @@ color: green Читай все три — список, который ты не прочёл, это настройка проекта, не сработавшая молча. -**Диффа у тебя нет — кода ещё нет.** Не пытайся его считать и не жди его. - **Отрицательный тест `small`:** что после мерджа не откатывается обратной правкой — миграция схемы и данных, формат на диске, публичный контракт, имя, которое разойдётся, — не `small`, каким бы малым ни было изменение. Тест жёсткий, и вот @@ -257,23 +265,15 @@ color: green ось: какой факт дал этот ответ. Поднять и понизить ты вправе одинаково; молча — ни то ни другое. -**Метка, названная тобой, действует до конца задачи и после кода не -пересматривается.** Второй раз тебя не позовут — кроме случая, когда правка после -ревью дизайна изменила сами дельта-спеки: план выведен из них, и план по -отменённым требованиям назовёт не те темы. +**Метка, названная тобой, действует до конца задачи и внутри прогона не +пересматривается.** Второй раз тебя не позовут — кроме случая, когда правка +изменила сами дельта-спеки: решение стало другим, а план выведен из задачи, и по +отменённым требованиям он назовёт не те темы. Правки по находкам инлайна дифф +растят — метку это не двигает. -## Правило 5 — раздача тем на обеих стадиях +## Правило 5 — раздача тем -**Ревью дизайна — состав по метке, тем не раздаётся.** До кода закрывать темы -нечем: проверяется предложение, а не изменение. - -| Метка | Проходы на предложении | -|---|---| -| `small` | `specs` | -| `medium` | `specs`, `rubric` | -| `large` | `specs`, `rubric`, `architecture` + вопрос автору о трёх формах решения | - -**Ревью кода — раздача тем.** Кто закрывает тему, зависит от метки. Раскладка +**Кто закрывает тему, зависит от метки.** Раскладка жёсткая, выдумывать её не надо: @@ -329,17 +329,15 @@ color: green Строго этот, он уезжает в отчёт целиком и служит границами покрытия: ``` -размер: среднее — tasks.md: 6 шагов в двух узлах; дельты трогают 2 capability; - «Затрагивает» называет 3 узла (взято большее — tasks.md) -сложность: знакомое — «Затрагивает» называет узлы поимённо до начала работы; - design.md разбирает одну форму решения, альтернатив не рассматривал +размер: среднее — дифф трогает 9 файлов в двух узлах; дельты трогают + 2 capability; «Затрагивает» называл 3 узла (взято большее — дифф) +сложность: знакомое — «Затрагивает» называл узлы поимённо, и дифф не вышел за + них; design.md разбирает одну форму решения, альтернатив не рассматривал метка: medium — максимум по осям; ни одна не дала large -корпус: запись задачи, proposal.md, design.md, tasks.md, дельта-спеки — все пять +корпус: дифф; запись задачи, proposal.md, design.md, tasks.md, дельта-спеки -ревью дизайна: specs, rubric - -ревью кода, темы: +темы: тема дом глубина закрывает requirements openspec/changes//specs/ разбор specs autotests CLAUDE.md, семантика гейта — autotests @@ -370,16 +368,17 @@ operations docs/architecture.md, «Эксплуатация» разбор ``` ## Coverage of this pass - документов в docs/ найдено N, все N разнесены: тем M, источников K, процессных L -- корпус оценки: какие из пяти источников прочитаны, какие отсутствуют и что это дало осям +- корпус оценки: что прочитано, что отсутствует и что это дало осям - расхождение источников по размеру: <какие цифры и какая взята, или «нет»> +- обещанные границы против тронутых: <совпали | разошлись поимённо: перечень> - тем без дома: <перечень или «нет»> - вопросов по темам роздано: <число>; адресованных не теме: <перечень или «нет»> -- чего не смотрел: содержимого документов — по построению; кода и диффа — их ещё нет +- чего не смотрел: содержимого документов — по построению; кода по существу — не моя работа ``` -**Строка про корпус обязательна и тогда, когда прочитаны все пять.** Отсутствие +**Строка про корпус обязательна и тогда, когда прочитано всё.** Отсутствие источника меняет обе оси, и молчащий пропуск здесь дороже прочих: он двигает не -одну тему, а состав обоих прогонов сразу. +одну тему, а состав всего прогона. ## Чего ты не делаешь @@ -394,6 +393,7 @@ operations docs/architecture.md, «Эксплуатация» разбор ## Ограничения -Только чтение. `Bash` — для `ls` и `grep` по заголовкам. Ничего не запускай, -ничего не редактируй. `git diff` тебе не нужен: на момент твоего запуска кода -ещё нет. +Только чтение. `Bash` — для `ls`, `grep` по заголовкам и `git diff` от названной +базы. Ничего не запускай сверх этого и ничего не редактируй. **Дифф ты меришь, а +не читаешь по существу:** сколько файлов и узлов тронуто — твой вопрос, хорош ли +код — вопрос других проходов. diff --git a/av-dev/agents/review-triage.md b/av-dev/agents/review-triage.md index ebc61c2..3f976e5 100644 --- a/av-dev/agents/review-triage.md +++ b/av-dev/agents/review-triage.md @@ -29,7 +29,7 @@ color: yellow **Откуда план приходит, зависит от режима, и режимов два.** -- **С меткой** — план собрал `review-scope` (один запуск после `propose`), и к +- **С меткой** — план собрал `review-scope` (один запуск после `apply`), и к таблице прилагаются размер, сложность и метка с обоснованием. - **Без метки** — так идёт прогон сценария обслуживания: изменение не меняет поведения, размечать нечего, и разметчик не запускается вовсе. План diff --git a/av-dev/shared/axes.md b/av-dev/shared/axes.md index fa1ab97..2bf89a5 100644 --- a/av-dev/shared/axes.md +++ b/av-dev/shared/axes.md @@ -48,7 +48,7 @@ | тип записи | сценарий — **предлагает**, подтверждает предмет работы | `task-track/SKILL.md`, «Тип записи» | | тип записи | метку и глубину — **не влияет, и это записано явно** | там же | | сценарий | режим прогона: обслуживание идёт без метки | `code-resolve/references/maintain.md` | -| метка | состав проходов обеих стадий | `code-review/SKILL.md`, «Метки» | +| метка | состав проходов прогона | `code-review/SKILL.md`, «Метки» | | метка | глубину темы: против чего смотрят и как | там же | | режим прогона | состав проходов и саму возможность запуска прохода | `code-review/SKILL.md`, «Прогон без change» | | категория документа | заводит ли документ направление проверки | `canon.md`, «Три категории» | @@ -91,7 +91,7 @@ **Прогон ревью идёт в одном из двух режимов, и режим — не глубина.** - **С меткой** — обычный прогон по change: разметку сделал `review-scope`, состав - обеих стадий выведен из метки. + прогона выведен из метки. - **Без метки** — прогон сценария обслуживания: change нет, размечать нечего, план фиксирован и назван сценарием. Разметчик не запускается вовсе. diff --git a/av-dev/skills/canon/references/canon.md b/av-dev/skills/canon/references/canon.md index 9c3846f..938225f 100644 --- a/av-dev/skills/canon/references/canon.md +++ b/av-dev/skills/canon/references/canon.md @@ -427,7 +427,7 @@ kebab-case.** Причина не эстетическая: имя файла с **Файл канону не принадлежит, и проверяет его тоже не канон.** Каталог `openspec/` — предпосылка конвейера: без него не работают ни `opsx:propose`, ни -ревью дизайна, ни сверка требований. Заводит его, настраивает и **проверяет +сверка требований. Заводит его, настраивает и **проверяет форму** скилл `av-dev:code-openspec`: там образец файла, там же скрипт `openspec.py check`. `docs.py` о файле не говорит ничего. diff --git a/av-dev/skills/canon/references/changelog-before-merge.md b/av-dev/skills/canon/references/changelog-before-merge.md index a9cc12c..1291114 100644 --- a/av-dev/skills/canon/references/changelog-before-merge.md +++ b/av-dev/skills/canon/references/changelog-before-merge.md @@ -217,7 +217,7 @@ OpenSpec уехал в конвейер. Каталог `openspec/` версие канона: `init` его заводил, `adopt` тоже, образец `config.yaml` лежал в скелетах, а отсутствие каталога `docs.py` считал отказом. Разрез был проведён не там. По OpenSpec работает конвейер — без каталога не запускаются ни `opsx:propose`, ни -ревью дизайна, ни сверка требований, — а канон документов о нём только +сверка требований, — а канон документов о нём только высказывался. Проект, которому конвейер не нужен, получал отказ за отсутствие того, чем не пользуется. @@ -290,7 +290,7 @@ OpenSpec работает конвейер — без каталога не за `config.yaml` описан абзацем — а заводил всё это человек руками, и проверялось из перечисленного ничего. Заведение нового проекта проходило мимо: `init` собирал документы канона и оставлял проект без каталога, без которого не работают -ни `opsx:propose`, ни ревью дизайна, ни сверка требований. +ни `opsx:propose`, ни сверка требований. Хуже отсутствия оказался файл из коробки. `openspec init` кладёт `config.yaml`, где `context` и `rules` — закомментированный пример на английском. Такой файл diff --git a/av-dev/skills/code-openspec/SKILL.md b/av-dev/skills/code-openspec/SKILL.md index a3f17e2..c3facb5 100644 --- a/av-dev/skills/code-openspec/SKILL.md +++ b/av-dev/skills/code-openspec/SKILL.md @@ -1,12 +1,12 @@ --- name: code-openspec -description: "Завести и настроить OpenSpec в проекте — openspec init --tools claude, замена закомментированного примера в openspec/config.yaml на настройку канонической формы (язык, правила именования capability, придирки валидатора, адреса паспорта и CLAUDE.md), проверка формы своим скриптом openspec.py (имя файла, схема, незаменённый пример, адреса документов, ключи rules против артефактов схемы) и сверка слепка с живой версией инструмента. Использовать, когда в проекте нет каталога openspec/, когда config.yaml остался примером из коробки, когда заводят новый проект или переводят чужой и дошли до шага OpenSpec, а также когда конвейер отказался работать без источника требований. Каталог openspec нужен именно конвейеру: без него не работают ни opsx:propose, ни ревью дизайна, ни сверка требований." +description: "Завести и настроить OpenSpec в проекте — openspec init --tools claude, замена закомментированного примера в openspec/config.yaml на настройку канонической формы (язык, правила именования capability, придирки валидатора, адреса паспорта и CLAUDE.md), проверка формы своим скриптом openspec.py (имя файла, схема, незаменённый пример, адреса документов, ключи rules против артефактов схемы) и сверка слепка с живой версией инструмента. Использовать, когда в проекте нет каталога openspec/, когда config.yaml остался примером из коробки, когда заводят новый проект или переводят чужой и дошли до шага OpenSpec, а также когда конвейер отказался работать без источника требований. Каталог openspec нужен именно конвейеру: без него не работают ни opsx:propose, ни сверка требований." --- # OpenSpec в проекте Каталог `openspec/` — **предпосылка конвейера**, а не канона документов. Без него -не работают ни `opsx:propose`, ни ревью дизайна, ни `review-specs`: у требований +не работают ни `opsx:propose`, ни `review-specs`: у требований не остаётся дома. Поэтому заводит и настраивает его этот скилл — тот, кто по OpenSpec и работает. diff --git a/av-dev/skills/code-openspec/references/config-skeleton.md b/av-dev/skills/code-openspec/references/config-skeleton.md index 4ec7a21..a628fea 100644 --- a/av-dev/skills/code-openspec/references/config-skeleton.md +++ b/av-dev/skills/code-openspec/references/config-skeleton.md @@ -69,7 +69,6 @@ rules: - "Заголовки и WHEN/THEN/GIVEN — на английском, остальной текст на русском" tasks: - "Критерии приёмки задачи — отдельным блоком и дословно: файл задачи закрытие удалит, критерии обязаны его пережить" - - "Рубрика ревью дизайна, если оно её дало, идёт в тот же блок: приёмка судится по одному списку, а не по двум" - "Шаг плана формулируется проверяемо — по нему видно «сделано / не сделано» без суждения" ``` @@ -88,9 +87,8 @@ ADR** — отвергнутый вариант с названной причи **Правила для `tasks` держит тот же скилл, и по той же причине — момент порождения.** `tasks.md` — единственное, что переживает задачу: файл задачи закрытие удаляет, а приёмка потом судится по критериям, которые в него -скопированы. Туда же ложится рубрика ревью дизайна, если оно её дало. Записанное -в момент порождения не приходится вспоминать шагом позже, когда артефакт уже -написан. Блок `context` проект +скопированы. Записанное в момент порождения не приходится вспоминать шагом позже, +когда артефакт уже написан. Блок `context` проект дополняет своим (стек, разведка, особенности домена), но **адреса паспорта и `CLAUDE.md` обязательны** — отсутствие адреса к существующему документу `openspec.py check` называет отказом. diff --git a/av-dev/skills/code-openspec/scripts/openspec.py b/av-dev/skills/code-openspec/scripts/openspec.py index 69e1039..3d4394a 100644 --- a/av-dev/skills/code-openspec/scripts/openspec.py +++ b/av-dev/skills/code-openspec/scripts/openspec.py @@ -2,7 +2,7 @@ """Форма `openspec/config.yaml`: проверка проекта и сверка слепка с инструментом. Каталог `openspec/` — предпосылка **конвейера**, а не канона документов: без него -не работают ни `opsx:propose`, ни ревью дизайна, ни сверка требований. Поэтому и +не работают ни `opsx:propose`, ни сверка требований конвейером. Поэтому и проверка формы живёт здесь, рядом со скиллом, который каталог заводит. Раньше она жила в `docs.py`, у скилла канона, и у файла было два владельца: один заводит, другой проверяет. diff --git a/av-dev/skills/code-resolve/SKILL.md b/av-dev/skills/code-resolve/SKILL.md index ab59683..10b7c6d 100644 --- a/av-dev/skills/code-resolve/SKILL.md +++ b/av-dev/skills/code-resolve/SKILL.md @@ -1,6 +1,6 @@ --- name: code-resolve -description: "Взять одну задачу и довести её до закрытия. Одна точка входа, три сценария, и выбирает сценарий сам скилл, прочитав постановку. Способ известен и меняется поведение — сценарий решения: цикл Spec Driven Development (opsx propose → разметка → ревью дизайна → чекпоинт с объяснением человеческим языком → opsx apply → ревью кода → archive → синк документации → коммит → закрытие). Способ известен, а спека не меняется (тип chore: тулчейн, зависимости, сборка, гит-хуки, перенос, чистка) — сценарий обслуживания: правка → гейт со сверкой состава проверок → ревью фиксированным планом без change (autotests, operations, плюс conventions, если тронут код) → синк документации → коммит → закрытие; планового стопа нет, change не заводится. Нашлась дельта-спека — задача оказалась шире своего типа: стоп с объяснением простым языком и двумя решениями человека, переформулировать запись в fix или feature и решать её процессом того типа следующим прогоном либо прекратить работу. Способа нет, постановка мутная, тип research — сценарий разведки: вопрос и рамки → чтение документов, кода и внешних источников (можно opsx:explore) → чекпоинт вариантов: 2–4 способа решить, цена каждого, что становится невозможным, рекомендация → ответ уезжает в документы канона, исход — в задачи → вычитка написанного → коммит → закрытие. Разведка кода не пишет и change не заводит, а выбранный способ реализуется следующим прогоном. На входе путь к файлу задачи, её слаг или просто текст постановки: размеченная запись не обязательна — текст берётся так же, как его берёт opsx:propose, и текстом идут все три сценария. Использовать, когда просят взять, сделать или решить задачу — хоть записью из каталога, хоть описанием прямо в разговоре, — обновить зависимости или сборку, разобраться, изучить, сравнить подходы, проработать сырую идею, ответить на вопрос из беклога." +description: "Взять одну задачу и довести её до закрытия. Одна точка входа, три сценария, и выбирает сценарий сам скилл, прочитав постановку. Способ известен и меняется поведение — сценарий решения: цикл Spec Driven Development (opsx propose → чекпоинт с объяснением человеческим языком → opsx apply → разметка по диффу → ревью кода → archive → синк документации → коммит → закрытие). Способ известен, а спека не меняется (тип chore: тулчейн, зависимости, сборка, гит-хуки, перенос, чистка) — сценарий обслуживания: правка → гейт со сверкой состава проверок → ревью фиксированным планом без change (autotests, operations, плюс conventions, если тронут код) → синк документации → коммит → закрытие; планового стопа нет, change не заводится. Нашлась дельта-спека — задача оказалась шире своего типа: стоп с объяснением простым языком и двумя решениями человека, переформулировать запись в fix или feature и решать её процессом того типа следующим прогоном либо прекратить работу. Способа нет, постановка мутная, тип research — сценарий разведки: вопрос и рамки → чтение документов, кода и внешних источников (можно opsx:explore) → чекпоинт вариантов: 2–4 способа решить, цена каждого, что становится невозможным, рекомендация → ответ уезжает в документы канона, исход — в задачи → вычитка написанного → коммит → закрытие. Разведка кода не пишет и change не заводит, а выбранный способ реализуется следующим прогоном. На входе путь к файлу задачи, её слаг или просто текст постановки: размеченная запись не обязательна — текст берётся так же, как его берёт opsx:propose, и текстом идут все три сценария. Использовать, когда просят взять, сделать или решить задачу — хоть записью из каталога, хоть описанием прямо в разговоре, — обновить зависимости или сборку, разобраться, изучить, сравнить подходы, проработать сырую идею, ответить на вопрос из беклога." --- # Работа над одной задачей @@ -31,7 +31,7 @@ description: "Взять одну задачу и довести её до за ## Предпосылки - **OpenSpec и скиллы `opsx:*` — жёсткая предпосылка сценария решения**, а не - опция. На них стоят его шаги 2, 6 и 8, проход `review-specs` и ревью дизайна + опция. На них стоят его шаги 2, 4 и 7 и проход `review-specs` (они завязаны на `openspec/changes//specs/*/spec.md` и на `openspec validate --strict`). **Проект без OpenSpec этим скиллом не ведётся** — подключай OpenSpec, а не вырождай цикл сценария; почему ветка деградации здесь @@ -239,8 +239,8 @@ description: "Взять одну задачу и довести её до за человек. Обратной смены «решение → обслуживание» нет: задача, заведшая change, доводится -циклом решения. Дельта-спеки, оказавшиеся пустыми, — находка ревью дизайна о -самой постановке, а не повод свернуть на короткий путь из середины длинного. +циклом решения. Дельта-спеки, оказавшиеся пустыми, — повод назвать это на +чекпоинте, а не свернуть на короткий путь из середины длинного. **Соблазн «разведаю по ходу» живёт именно здесь**, и он дорог тем, что выглядит экономией одного прогона. Разведка внутри решения не имеет своего чекпоинта: @@ -298,9 +298,9 @@ flowchart TD | Работа | Где шаг | | --- | --- | | предложение и дельта-спеки — `opsx:propose` | [solve](references/solve.md), шаг 2 | -| правки спек и дизайна по находкам ревью дизайна | [solve](references/solve.md), шаг 4 | -| код — `opsx:apply`, вместе с гейтом до зелёного и поведенческой верификацией | [solve](references/solve.md), шаг 6 | -| правки по находкам триажа, помеченным `инлайн` | [solve](references/solve.md), шаг 7; [maintain](references/maintain.md), шаг 4 | +| правки спек и дизайна по сказанному на чекпоинте | [solve](references/solve.md), шаг 3 | +| код — `opsx:apply`, вместе с гейтом до зелёного и поведенческой верификацией | [solve](references/solve.md), шаг 4 | +| правки по находкам триажа, помеченным `инлайн` | [solve](references/solve.md), шаг 6; [maintain](references/maintain.md), шаг 4 | | правка оснастки в сценарии обслуживания | [maintain](references/maintain.md), шаг 2 | **Остальное остаётся оркестратору, и перечень закрыт:** выбор сценария и стопы, @@ -334,7 +334,7 @@ flowchart TD - **что делать**: файл задачи либо её текст дословно, критерии приёмки, идентификатор change; - **что читать**: `CLAUDE.md`, конвенции проекта, дельта-спеки change; -- **находки — дословно**, как их вернул триаж или ревью дизайна, вместе с +- **находки — дословно**, как их вернул триаж, вместе с оракулом; - **границы**: правится названное, соседнее не улучшается заодно; развилок агент не решает, задач не заводит, ничего не коммитит и наружу не ходит — правило @@ -380,8 +380,8 @@ flowchart TD ## Автономность и плановый стоп **У двух сценариев ровно один плановый стоп**, и стоят они в разных местах: -у решения — объяснение после ревью дизайна, у разведки — варианты до первого -написанного требования. Правило вокруг них общее. +у решения — объяснение сразу после предложения и до кода, у разведки — варианты +до первого написанного требования. Правило вокруг них общее. **У обслуживания планового стопа нет вовсе, и это следствие, а не поблажка.** Один стоп с ожиданием ответа у него всё же есть — по найденной дельта-спеке, — но diff --git a/av-dev/skills/code-resolve/references/maintain.md b/av-dev/skills/code-resolve/references/maintain.md index 260b8cf..38f8c82 100644 --- a/av-dev/skills/code-resolve/references/maintain.md +++ b/av-dev/skills/code-resolve/references/maintain.md @@ -125,8 +125,8 @@ **Третьего решения — «доделать как обслуживание» — нет.** Оно и есть то самое молчаливое изменение поведения, против которого стоит весь разрез: под коммитом, -заявляющим «поменяли оснастку», уехала бы правка, не прошедшая ни ревью дизайна, -ни чекпоинта, и не оставившая следа в спеках. +заявляющим «поменяли оснастку», уехала бы правка, не прошедшая ни чекпоинта, ни +ревью по метке, и не оставившая следа в спеках. **Сделанное не выбрасывается ни при каком из двух решений.** Оно остаётся в рабочем дереве незакоммиченным: при переформулировке уезжает в change следующим diff --git a/av-dev/skills/code-resolve/references/solve.md b/av-dev/skills/code-resolve/references/solve.md index 769066f..9933f3b 100644 --- a/av-dev/skills/code-resolve/references/solve.md +++ b/av-dev/skills/code-resolve/references/solve.md @@ -2,7 +2,7 @@ Способ решения известен, спорно только как. Проводит задачу от постановки до закрытия и **пишет код**: цикл Spec Driven Development с одним плановым стопом — -объяснением после ревью дизайна. +объяснением сразу после предложения. Сценарий выбирается развилкой на входе скилла ([SKILL.md](../SKILL.md), раздел «Развилка: какой сценарий») и называется вслух первой репликой. Здесь только его @@ -11,14 +11,13 @@ пересказывается. **OpenSpec — жёсткая предпосылка именно этого сценария** (SKILL.md, -«Предпосылки»): на нём стоят шаги 2, 6 и 8, проход `review-specs` и ревью -дизайна. +«Предпосылки»): на нём стоят шаги 2, 4 и 7 и проход `review-specs`. Тонкая обёртка над каноническими скиллами `opsx:propose` / `opsx:apply` / `opsx:archive` — их шаги не переизобретаются, а **зовёт их агент**, не ты (SKILL.md, «Кто пишет: письмо уходит агентам»). Ревью — скилл `av-dev:code-review`; он же держит правило выбора метки, а называет её агент -`review-scope` — один раз на задачу, для обеих стадий ревью. +`review-scope` — один раз на задачу, **после того как код написан**. ## Ход работы @@ -27,21 +26,20 @@ 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,
вторым коммитом учёта"] + 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 --> s11 - s3 -.->|"план задачи: та же метка"| s7 - s5 -.->|"скорректировать:
меняются дельта-спеки"| s3 - s7 -.->|"находка отменяет дизайн:
меняются дельта-спеки"| s3 + s1 --> s2 --> s3 --> s4 --> s5 --> s6 --> s7 --> s8 --> s9 --> s10 + s5 -.->|"план задачи: темы и глубины"| s6 + s3 -.->|"скорректировать:
правка спек и дизайна"| s3 + s6 -.->|"находка отменяет дизайн:
меняются дельта-спеки"| s3 ``` Схема — **сводка**: содержание каждого шага в его разделе ниже, и при @@ -93,7 +91,7 @@ flowchart TD **Постановка пришла текстом** (SKILL.md, «Постановка текстом») — записи нет, читаешь сам текст. Критерии в нём бывают редко: выпиши то, что там есть, а -недостающие **предложи на чекпоинте шага 5** и считай их данными только после +недостающие **предложи на чекпоинте шага 3** и считай их данными только после ответа человека. Сам себе критерии не проставляешь — правило то же, что и с записью: они приходят снаружи, и подсунуть их себе значит назначить себе приёмку. Человек критериев не назвал — скажи строкой, что задача идёт без них и приёмка @@ -116,7 +114,7 @@ flowchart TD сценарии — `GIVEN/WHEN/THEN`. **`proposal.md` и `design.md` после возврата читаешь сам** — из них собирается -чекпоинт шага 5, и держать их в контексте это твоя работа, а не переполнение. +чекпоинт шага 3, и держать их в контексте это твоя работа, а не переполнение. Кода нет, читать нечего сверх них. Ещё две вещи задание называет прямо, иначе их не сделает никто. **Критерии @@ -128,84 +126,21 @@ flowchart TD `design.md`, с причиной отказа по каждому отвергнутому. **`proposal.md` пишется так, чтобы его понял человек, не читавший спек.** Это не -стилистическое пожелание: из него собирается чекпоинт шага 5, и переписывать его +стилистическое пожелание: из него собирается чекпоинт шага 3, и переписывать его там заново значит завести второй дом для одного объяснения. Требование стоит в `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` как приёмочные критерии; там же уже -лежат критерии от постановки, если они были. - -**Отработка замечаний, и она идёт до чекпоинта, а не после:** - -- мелочь и явные улучшения — правкой спек и дизайна, и её делает **агент** - (SKILL.md, «Кто пишет»): находки уходят ему дословно, вместе с - идентификатором change и требованием перепрогнать - `openspec validate --strict `; -- развилки (компромисс, scope, инвариант) — **не в запись, а в чекпоинт**: он - следующим шагом, и это ровно то, ради чего он поставлен здесь. Агенту развилка - не отдаётся вовсе: решает её человек, а не тот, кто правит спеку; -- возврат агента — адреса тронутых дельт и исход валидации; правленые спеки - перечитываешь по адресам, если чекпоинт опирается на изменившееся. - -### 5. Чекпоинт: объяснение +### 3. Чекпоинт: объяснение **Остановись и объясни человеку, что происходит.** Единственный плановый стоп этого сценария, и он обязателен для всякой задачи. -Он стоит **после** ревью дизайна намеренно. Человек читает объяснение, уже -просеянное машиной: то, что поймал бы `review-specs`, до него не доходит, а -внимание — самый дорогой ресурс процесса, и тратить его на выловимое машиной -нельзя. +Он стоит **сразу после предложения и до кода** — намеренно. Раньше между +`propose` и чекпоинтом стояла стадия ревью дизайна, и человек читал объяснение, +уже просеянное машиной. Стадию сняли ради времени прогона, и просеивать теперь +нечем: человек читает предложение как оно есть. Взамен стоп пришёл **раньше** — +коррекция здесь стоит правки спеки, а не переписывания готового кода. **Объяснение не сочиняется заново — оно собирается из артефактов**, `proposal.md` и `design.md`. Третий пересказ был бы третьим домом одного и того же и разошёлся @@ -217,7 +152,7 @@ flowchart TD - **что человек увидит иначе**, когда это будет сделано; - **чего мы намеренно не делаем** и почему — граница scope ловится хуже всего; - **чем рискуем и что осталось нерешённым** — сюда съезжаются развилки, - накопленные до этого места, и находки ревью с пометкой `развилка`; + накопленные до этого места; - **что дальше**, если возражений нет; - **критерии приёмки, если постановка пришла текстом и не назвала их** — предложенными, а не принятыми: человек их подтверждает или правит здесь же. @@ -241,22 +176,24 @@ flowchart TD Три исхода: -- **согласен** — идёшь на шаг 6; -- **скорректировать** — правишь спеки и дизайн по сказанному. Изменились - **дельта-спеки** — повтори шаг 3 (разметка выведена из них) и ту часть ревью - дизайна, которой касается правка; затем чекпоинт **заново**. Правка внутри - дизайна без спек — повтори только чекпоинт; +- **согласен** — идёшь на шаг 4; +- **скорректировать** — правку спек и дизайна по сказанному делает **агент** + (SKILL.md, «Кто пишет»): сказанное человеком уходит ему дословно, вместе с + идентификатором change и требованием перепрогнать + `openspec validate --strict `. Затем чекпоинт **заново** — правленое + объяснение читает тот же человек. Разметки на этот момент ещё нет, и повторять + здесь нечего: она идёт после кода; - **не одобрено** — исход «не доведена» с причиной. Change остаётся незаархивированным, задача не закрывается, ничего не коммитится наполовину. -### 6. Написать код — `opsx:apply` +### 4. Написать код — `opsx:apply` **Код пишет агент, и в его же задании лежит весь этот раздел** (SKILL.md, «Кто пишет»): вызов `opsx:apply` для реализации `tasks.md`, гейт до зелёного, поведенческая верификация. Возврат — адреса тронутого, исход гейта и строка верификации; диффа в нём нет. **Исход гейта возвращается сводкой, путём к логам шагов и отпечатком дерева** (SKILL.md, «Возврат — не длиннее экрана»): его -передача на шаг 7 избавляет ревью от второго прогона того же гейта. +передача на шаг 6 избавляет ревью от второго прогона того же гейта. Код — по конвенциям проекта (каталог `docs/conventions/`). Меняешь схему — обнови её описание в документации @@ -272,23 +209,52 @@ flowchart TD **Сервис не оставляем лежать.** Если запуск упал — агент чинит или откатывает до конца шага; возврат с лежащим сервисом — незакрытый шаг, а не исход. -### 7. Ревью кода — та же метка +### 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 ``, -базу диффа, **план разметки с шага 3**, режим запуска и **исход гейта с шага 6** — +базу диффа, **план разметки с шага 5**, режим запуска и **исход гейта с шага 4** — сводку, путь к логам шагов и отпечаток дерева. **Метку ты не выбираешь, и это правило, а не упрощение.** Её назвал -`review-scope` ещё на шаге 3 — по размеру и сложности, с обоснованием по каждой -оси. Причина в разведённости: ты только что написал этот код, и решать, насколько -глубоко его проверять, тебе нельзя — под давлением «я почти закончил» решение -известно заранее. Правило выбора живёт в скилле конвейера — -`av-dev:code-review`, `references/review-levels.md`; проектные +`review-scope` шагом раньше — по размеру и сложности, с обоснованием по каждой +оси; причина в разведённости, и она разобрана там же. Правило выбора живёт в +скилле конвейера — `av-dev:code-review`, `references/review-levels.md`; проектные триггеры — в `docs/review.*`, подраздел «Триггеры метки». -**Метка не пересматривается по факту диффа.** Дифф может выйти крупнее, чем -ожидалось при разметке, — это не повод её поднимать: пересмотр означал бы второй -запуск разметчика, ровно то, ради устранения чего он и переехал на шаг 3. +**Метка, названная по диффу, внутри прогона больше не пересматривается.** +Разметчик видел дифф целиком и посчитал по нему обе оси; второй запуск на том же +дереве вернул бы то же самое. **Считаешь метку заниженной — скажи это в докладе строкой, а не переспорь.** Разметчик вправе и поднять, и понизить; твоё несогласие это факт для человека, а @@ -298,7 +264,7 @@ flowchart TD **Плана нет — ревью кода не запускается.** Триаж требует план обязательным входом: без него он не может сверить, все ли размеченные темы вернули отчёт, а эта сверка — единственная защита от молчащего пропуска. Потерял план (прервалась -сессия, ушёл контекст) — повтори шаг 3, а не гони прогон без него. +сессия, ушёл контекст) — повтори шаг 5, а не гони прогон без него. **Режим по умолчанию — `по графу`, и обосновывать его не надо.** Конвейер сам знает свои рёбра: гейт открывает проходы с мнением, проходы с пометкой «держит @@ -329,9 +295,9 @@ flowchart TD проверяемый: **меняются ли дельта-спеки**. - не меняются — находка внутри дизайна, дожимай сам, это обычная отработка; -- меняются — решение стало другим, а одобрено было прежнее. Повтори шаг 3 - (разметка выведена из дельта-спек) и **вернись на чекпоинт шага 5** с тем, что - изменилось и почему. Такая находка агенту не отдаётся ни при каких условиях: +- меняются — решение стало другим, а одобрено было прежнее. **Вернись на чекпоинт + шага 3** с тем, что изменилось и почему; дальше задача идёт своим ходом заново — + код, разметка, ревью. Такая находка агенту не отдаётся ни при каких условиях: она отменяет одобрение, а это разговор с человеком. **Это правило старше правила о развилке.** Находка класса `развилка`, чьё @@ -354,18 +320,18 @@ flowchart TD сжатой строкой. Отчёт, из которого исчезло «что проверить было невозможно», превращается в ложное ощущение проверенности. -**Отчёт триажа сохрани вместе с change (`openspec/changes//review/`; шаг 8 +**Отчёт триажа сохрани вместе с change (`openspec/changes//review/`; шаг 7 унесёт его в архив вместе с change) — это обязательно, а не «если удобно».** По нему потом видно, что было найдено и что из этого осталось в урожае. И это единственный **независимый** артефакт о составе прогона: своей прозе здесь верить нельзя — она написана тем же, кто мог проход и пропустить. -### 8. Архивировать — `opsx:archive` +### 7. Архивировать — `opsx:archive` Вызови Skill `opsx:archive`: change уезжает в архив, дельты вливаются в актуальные спеки. Не пропускай `openspec validate --strict` перед этим. -### 9. Синк документации +### 8. Синк документации **Вызови Skill `av-dev:doc-sync`**: он владеет содержимым документов канона и ведёт чек-лист синка. @@ -385,7 +351,7 @@ flowchart TD задачу нельзя: документ, заведённый мимо канона, окажется вторым домом ровно тому, что канон потом заведёт своим. -### 10. Коммит +### 9. Коммит Коммить **в текущую ветку** (`git rev-parse --abbrev-ref HEAD`), сам ветку не создавай и не переключай, ничего не пушь. @@ -395,14 +361,14 @@ flowchart TD напиши сообщение сам и скажи строкой доклада, что форму коммита не сверял никто. Одна задача — один осмысленный коммит. -### 11. Закрыть задачу — **после коммита, не раньше** +### 10. Закрыть задачу — **после коммита, не раньше** **Вызови Skill `av-dev:task-track`** и попроси закрыть задачу как реализованную — он владеет форматом и двигает строку индекса сам. Путь к его скрипту не выясняй и индексы руками не правь: мост между плагинами — вызов скилла, а не путь. **Порядок обязателен.** Закрытие удаляет файл задачи; сделанное до коммита оно -оставило бы задачу закрытой без единого следа работы, если шаг 10 упадёт. +оставило бы задачу закрытой без единого следа работы, если шаг 9 упадёт. **Закрытие тоже коммитится — вторым коммитом, тут же.** Удаление файла задачи и правка индексов (их имена знает `av-dev:task-track`, не ты) — это правки в рабочем @@ -443,8 +409,8 @@ change. Заводить запись задним числом, чтобы её улучшений заодно. - **Занизить метку ревью, пропустить тему или проскочить чекпоинт — самый дешёвый способ «ускориться», и он же самый дорогой по последствиям.** Защита устроена - так, что регулятора у тебя нет: метку выбирает разметчик **до того**, как ты - написал код, план сверяется по темам, непокрытое называется строкой, а + так, что регулятора у тебя нет: метку выбирает **не ты, а разметчик, и выводит + её из диффа**, план сверяется по темам, непокрытое называется строкой, а расхождение с одобренным — отдельным пунктом доклада. - **Заведение задач из урожая ревью — не твоя работа.** Отложенные находки отдаются **списком**; превращает их в задачи `av-dev:task-track`, у него на diff --git a/av-dev/skills/code-review/SKILL.md b/av-dev/skills/code-review/SKILL.md index 1613758..76c25c7 100644 --- a/av-dev/skills/code-review/SKILL.md +++ b/av-dev/skills/code-review/SKILL.md @@ -1,6 +1,6 @@ --- name: code-review -description: "Конвейер ревью изменения, устроенный по темам: документ проекта либо заводит тему ревью, либо питает чужую тему источником, либо процессный и в ревью не читается вовсе. Ядро тем — requirements, autotests, conventions, architecture, security, operations; список тем открытый, свои темы проект заводит документом. Разметка задачи идёт один раз, после propose: агент review-scope выводит размер и сложность, из их максимума — метка, и раздаёт темы проходам обеих стадий. Метка правит и ревью дизайна (small — только specs; medium — плюс rubric; large — плюс architecture), и ревью кода (small — гейт, спеки, код, триаж; medium — плюс приёмник тем; large — плюс доказательство: враждебные постановки, эксплуатационный постмортем, архитектурный проход на широком входе). Триаж обязателен всегда. Порядок прогона — граф зависимостей: гейт открывает проходы с мнением, проходы с пометкой «держит машину» идут цепочкой, триаж — единственный сток. Проектная специфика приходит из документов канона проекта. Вызывается из скилла av-dev:code-resolve — двумя стадиями: ревью дизайна до кода и ревью кода после apply. Третий вызов идёт от сценария обслуживания: без change и без метки, фиксированным планом (autotests, operations, плюс conventions, если тронут код), разметчик при этом не запускается." +description: "Конвейер ревью изменения, устроенный по темам: документ проекта либо заводит тему ревью, либо питает чужую тему источником, либо процессный и в ревью не читается вовсе. Ядро тем — requirements, autotests, conventions, architecture, security, operations; список тем открытый, свои темы проект заводит документом. Разметка задачи идёт один раз, после apply: агент review-scope выводит размер по диффу и сложность по форме решения, из их максимума — метка, и раздаёт темы проходам. Метка правит состав ревью кода: small — гейт, спеки, код, триаж; medium — плюс приёмник тем; large — плюс доказательство: враждебные постановки, эксплуатационный постмортем, архитектурный проход на широком входе. Триаж обязателен всегда. Порядок прогона — граф зависимостей: гейт открывает проходы с мнением, проходы с пометкой «держит машину» идут цепочкой, триаж — единственный сток. Проектная специфика приходит из документов канона проекта. Вызывается из скилла av-dev:code-resolve после apply. Второй вызов идёт от сценария обслуживания: без change и без метки, фиксированным планом (autotests, operations, плюс conventions, если тронут код), разметчик при этом не запускается." --- # Конвейер ревью @@ -245,6 +245,11 @@ description: "Конвейер ревью изменения, устроенны | `sonnet` | green | scope, autotests, ops | вывод перечислим и сверяется механически | | `opus` | yellow | specs, code, basics, adversary, rubric, architecture, triage | дорога ошибка — ложная либо пропущенная | +**`rubric` в составе прогона не стоит и в таблице держится за компанию.** Стадия, +где он жил, снята: рубрику на задуманный узел он порождает, не видя кода, а +конвейер работает по готовому диффу. Устав остаётся для прямого вызова человеком, +и модель у него та же — потому строка и не убрана. + **Цвет charter'а кодирует модель, а не роль прохода.** Это единственное назначение цвета: список агентов читается взглядом, и по нему сразу видно, чем платит прогон. Роль прохода из имени и так понятна, а цвет, розданный по ролям, @@ -272,20 +277,20 @@ charter'а, а модель потом двигает калибровка, и проде, и он тоже не оставляет следа ни в отчёте, ни в границах покрытия. По той же причине, что `specs`, и это дороже всего в конвейере: проход идёт на каждой задаче. -- `architecture` — запускается только со старшей меткой, на 5–10% задач, потолок - в 3 находки делает его дешёвым по выходу, а находка на предложении стоит абзаца - против переписывания на готовом коде. Дёшево × высокое плечо. +- `architecture` — запускается только со старшей меткой, на 5–10% задач, и + потолок в 3 находки делает его дешёвым по выходу. Его находка дороже прочих по + последствиям: второй способ делать то, что уже делается, переписыванием не + чинится, а живёт в кодовой базе годами. Дёшево × высокое плечо. -**`scope` внизу, и это не противоречие, хотя его ошибка расходится дальше всех — -теперь ещё дальше, чем прежде.** С переездом разметки к `propose` он правит -состав **обеих** стадий и не пересматривается после кода: ошибка метки стоит -всей задачи, а не одного прогона. Модель он всё же держит нижнюю, и вот почему. -Его работа распадается надвое: разнесение документов по категориям и раздача тем -**перечислимы** — план сверяется с `ls docs/` за секунду, пропущенный документ -виден без рассуждения. Выбор метки — суждение, но с переходом на две оси оно -стало **дважды перечислимым**: размер считается по перечню границ задачи и -дельта-спекам, сложность отвечается одним проверяемым признаком («можно ли до -работы назвать тронутые узлы»). Плюс три независимых корректора: отрицательный +**`scope` внизу, и это не противоречие, хотя его ошибка расходится дальше +всех.** Он правит состав всего прогона и внутри прогона не пересматривается: +ошибка метки стоит всей проверки задачи, а не одного прохода. Модель он всё же +держит нижнюю, и вот почему. Его работа распадается надвое: разнесение документов +по категориям и раздача тем **перечислимы** — план сверяется с `ls docs/` за +секунду, пропущенный документ виден без рассуждения. Выбор метки — суждение, но с +переходом на две оси оно стало **дважды перечислимым**: размер считается по +диффу, сложность отвечается одним проверяемым признаком («можно ли было до работы +назвать тронутые узлы»). Плюс три независимых корректора: отрицательный тест `small`, правило «спорный случай вниз» и **сигнал о заниженной метке от `code`** — тот идёт при любой метке и видит дифф целиком. Дешёвая модель безопасна ровно потому, что её вывод устроен как список, @@ -325,21 +330,20 @@ charter'а, а модель потом двигает калибровка, и ## Метки -**«Стадия» и «ступень» — разные членения, и путать их нельзя.** Стадий ревью -две — дизайна и кода, — и они видны снаружи: их зовёт `av-dev:code-resolve` в -разных точках цикла. Ступеней внутри прогона кода пять, они нумерованы и наружу -не выходят. Перечень осей процесса целиком — [shared/axes.md](../../shared/axes.md). +**Ступени нумерованы и наружу не выходят.** Прогон ревью один, и зовёт его +`av-dev:code-resolve` после того, как код написан; членение внутри прогона — +ступени, и знать их снаружи не нужно. Перечень осей процесса целиком — +[shared/axes.md](../../shared/axes.md). **Классификация задачи выдаёт ровно одно значение — метку**: `small`, `medium` или `large`. Это **единственный вход, по которому конвейер выбирает -исполнителей**: и на дизайне, и на коде состав читается из неё, а не из класса -задачи, не из её типа и не из ощущения важности. Метку ставит `review-scope` при -разметке задачи; все проходы получают её в задании и обязаны напечатать в своих -границах покрытия. +исполнителей**: состав читается из неё, а не из класса задачи, не из её типа и не +из ощущения важности. Метку ставит `review-scope` при разметке задачи; все +проходы получают её в задании и обязаны напечатать в своих границах покрытия. -**Метка одна на всю задачу и правит обе стадии ревью** — и дизайна, и кода. У -изменения нет двух разных «глубин проверки»: величина, из которой выводится -состав, — одна и та же пара «размер × сложность», посчитанная один раз. +**Метка одна на всю задачу.** У изменения нет двух разных «глубин проверки»: +величина, из которой выводится состав, — пара «размер × сложность», посчитанная +один раз по готовому диффу. **Метка не меняет список тем — она меняет их дом и глубину.** Все темы ядра названы при любой метке; разница в том, против чего их смотрят (дом темы @@ -367,18 +371,12 @@ charter'а, а модель потом двигает калибровка, и ```mermaid flowchart TD propose["opsx:propose — change, дельта-спеки, tasks.md"] - scope["review-scope — разметка задачи
размер × сложность → МЕТКА"] + checkpoint(["чекпоинт: объяснение человеку"]) + apply["opsx:apply — код, гейт зелёный"] + scope["review-scope — разметка по диффу
размер × сложность → МЕТКА"] label{{"метка"}} - subgraph design["Ревью дизайна — до кода"] - dS["specs — всегда"] - dR["+ rubric"] - dA["+ architecture
+ вопрос автору о трёх формах"] - end - - apply["opsx:apply — код, гейт зелёный"] - - subgraph code["Ревью кода — после apply"] + subgraph code["Ревью кода"] cGate["autotests — гейт, источник графа"] cS["specs — requirements"] cC["code — conventions + техника"] @@ -389,19 +387,9 @@ flowchart TD cT["triage — единственный сток"] end - propose --> scope --> label + propose --> checkpoint --> apply --> scope --> label - label -->|small| dS - label -->|medium| dR - label -->|large| dA - dR -.-> dS - dA -.-> dR - - dS --> apply - dR --> apply - dA --> apply - - apply --> cGate + label -->|любая метка| cGate cGate -->|зелёный| cS cGate -->|зелёный| cC label -->|small| cInv @@ -418,27 +406,18 @@ flowchart TD cHeavy --> cT ``` -Пунктир между проходами дизайна значит «включает предыдущее»: `medium` это -`specs` **плюс** `rubric`, `large` — они же плюс `architecture`. +Отсюда состав прогона: -Отсюда состав обеих стадий: - -| Метка | Когда | Ревью дизайна | Ревью кода: ступени | Проходов всего | Доля задач | -|---|---|---|---|---|---| -| `small` | малое **и** знакомое: багфикс, локальная правка, доки | `specs` | 1, 2, 5 (+3 при своих темах) | **5–6** | **до трети, и меньше, чем `medium`** | -| `medium` | **рабочее умолчание**: среднее и знакомое | `specs`, `rubric` | 1, 2, 3, 5 | **7** | **большинство** | -| `large` | крупное **или** незнакомое: большой рефакторинг, функциональность, форму которой ещё предстоит нащупать | `specs`, `rubric`, `architecture` | 1, 2, 4, 5 (+3 при своих темах) | **10–11** | **5–10%** | - -Ревью дизайна разбирается отдельно ниже — оно идёт до кода, у него свой плоский -граф и свой сток. Здесь оно стоит в таблице потому, что **метка у обеих стадий -общая**, и увидеть цену задачи можно только сложив их. +| Метка | Когда | Ступени | Проходов | Доля задач | +|---|---|---|---|---| +| `small` | малое **и** знакомое: багфикс, локальная правка, доки | 1, 2, 5 (+3 при своих темах) | **4–5** | **до трети, и меньше, чем `medium`** | +| `medium` | **рабочее умолчание**: среднее и знакомое | 1, 2, 3, 5 | **5** | **большинство** | +| `large` | крупное **или** незнакомое: большой рефакторинг, функциональность, форму которой ещё предстоит нащупать | 1, 2, 4, 5 (+3 при своих темах) | **7–8** | **5–10%** | **Разметка в этих числах не считается — её платят один раз на задачу, а не один -раз на прогон.** Она ушла из состава ревью кода целиком: `review-scope` идёт -после `propose`, до ревью дизайна, и его план обслуживает **обе** стадии. Раньше -разметка стояла первой в каждом ревью кода, а перед ревью дизайна вызывающий -отвечал на тот же вопрос сам — то есть о размере изменения судили дважды и в -одном из двух мест без разведённости с автором. +раз на прогон.** Она ушла из состава прогона целиком: `review-scope` идёт после +`apply`, до первой ступени. Раньше разметка стояла первой в каждом ревью кода и +повторялась при каждом перезапуске прогона. **Три глубины, и они не про старательность, а про способ доказательства.** **Сверка** — открыть дом темы, открыть дифф, сравнить. **Разбор** — построить @@ -463,8 +442,8 @@ flowchart TD ## Порядок прогона — граф, а не очередь Метка отвечает «какие темы и на какой глубине», порядок — «что кого ждёт». -Стадии остаются единицей **состава**, но порядок задают **не их номера**: между -стадиями 2–4 настоящих зависимостей нет — ни один проход не читает вывод другого, +Ступени остаются единицей **состава**, но порядок задают **не их номера**: между +ступенями 2–4 настоящих зависимостей нет — ни один проход не читает вывод другого, — и очередь между ними была бы платой ни за что. Рёбер два вида, и они разной природы. Путать их нельзя: первое про @@ -476,10 +455,10 @@ flowchart TD | **зависимость** | B не стартует, пока A не закончил, потому что без A задание B не определено | гейт → все проходы с мнением; все проходы → триаж | | **конфликт за ресурс** | A и B не держат машину одновременно; кто из них первый — неважно, направления у ребра нет | проходы, помеченные «держит машину» | -**План разметки — вход графа, а не его узел.** Он готов до того, как ревью кода -началось: разметка идёт один раз на задачу, после `propose`. Раньше она была +**План разметки — вход графа, а не его узел.** Он готов до того, как прогон +начался: разметка идёт один раз на задачу, сразу после `apply`. Раньше она была первым узлом каждого прогона, и ребро «разметка → все» стояло здесь; теперь этого -ребра нет, потому что нет и узла. +ребра нет, потому что нет и узла — перезапуск прогона разметку не повторяет. ```mermaid flowchart TD @@ -604,46 +583,48 @@ flowchart TD Режим объявляется в отчёте наравне с меткой: **`по графу`** — одним словом, **`линейно`** — с причиной (какой именно из трёх). -## Разметка задачи — один раз, до обеих стадий ревью +## Разметка задачи — один раз, после кода -Агент `review-scope`. Идёт **после `propose`, до ревью дизайна**, и один: до его -плана неизвестно ни что проверять, ни на какой метке, ни сколько ревьюверов -звать на предложение. +Агент `review-scope`. Идёт **после `apply`, до первой ступени**, и один: до его +плана неизвестно ни что проверять, ни на какой метке, ни сколько проходов звать. -**Это не стадия прогона, и в счёт проходов метки она не входит.** Раньше -разметка была стадией 0 ревью кода и платилась на каждом прогоне, а перед ревью -дизайна тот же вопрос — «крупное или незнакомое?» — задавал сам вызывающий, то -есть оркестратор, который только что написал предложение. Одна и та же величина -считалась дважды, и один из двух раз — без разведённости с автором. Теперь она -считается один раз и обслуживает обе стадии. +**Это не ступень прогона, и в счёт проходов метки она не входит.** Она платится +один раз на задачу: перезапуск прогона по находке «переделать форму» её не +повторяет, потому что план описывает задачу, а не дифф. **Что он читает.** `docs/` на уровне имён и заголовков, `CLAUDE.md` и `AGENTS.md`, `openspec/specs/`, `docs/review.*` — раздел настройки. Плюс **корпус -оценки**: пять письменных источников о задаче, из которых выводятся обе оси. +оценки**, и у двух осей он разный. | Источник | Размер | Сложность | |---|---|---| +| **дифф** | **сколько мест тронуто на самом деле** | — | | запись задачи, «Затрагивает» | перечень границ, названный до работы | узлы названы поимённо — знакомое | | `proposal.md` | что делаем и зачем | вводит ли новое понятие | | `design.md` | какие узлы в решении | **разбирались ли альтернативы** | | `tasks.md` | число шагов и их разнородность | шаг «разобраться», «выяснить» | | дельта-спеки | сколько capability и требований | `ADDED` целой capability против `MODIFIED` | -**Диффа он не читает: кода ещё нет** — и это причина, по которой корпус должен -быть широким. Одни дельта-спеки описывают заказанное поведение, но молчат об -объёме работы: шесть шагов в двух узлах видны в `tasks.md`, а факт, что форму -решения выбирали из нескольких, — только в `design.md`. Оценка по одному -источнику это оценка по остатку. +**Размер он меряет по диффу, и это главный источник.** Написанное о задаче до +работы описывает заказанное, а не сделанное: перечень границ мог оказаться +неполным, а `tasks.md` — обещать шесть шагов там, где хватило двух. Дифф этого не +обещает, он это показывает. Прочие источники размер **уточняют**: они называют +то, чего в диффе не видно, — например, что тронутые места лежат в разных слоях. + +**Сложность дифф не отвечает вовсе.** Признак незнакомого — нельзя было назвать +тронутые узлы до работы, — проверяется сверкой перечня границ задачи с тем, что +реально тронуто: разошлись поимённо, значит формы решения не знали. Оттого запись +задачи и `design.md` остаются в корпусе и после кода. **Расхождение источников по объёму разрешается в пользу большего** — не «спорное вниз»: там ничья при равных данных, здесь один источник просто видел больше. Само расхождение при этом идёт доводом за `незнакомое`: если о задаче написано -так, что источники не сходятся в объёме, формы решения не знают. +так, что источники не сходятся в объёме, формы решения не знали. Возвращает **план задачи**: размер и сложность с обоснованием, метка как -максимум по ним, состав ревью дизайна, список тем с домами и глубинами для ревью -кода, разнесение документов по трём категориям и строку про найденные директивы. -План уезжает в отчёты обеих стадий целиком и служит границами покрытия. +максимум по ним, список тем с домами и глубинами, разнесение документов по трём +категориям и строку про найденные директивы. План уезжает в отчёт прогона целиком +и служит границами покрытия. **Он не судит по существу** — ни одной находки об изменении. Его ошибка это пропущенная тема или не та метка, и обе видны: разнесение документов сверяется @@ -660,13 +641,11 @@ flowchart TD повторяется; это самый дешёвый проход конвейера, и платить за его вечность дороже, чем перезапустить. -**Метка, названная до кода, после кода не пересматривается.** Дифф может выйти -крупнее ожидания — метка от этого не двинется. Решение сознательное: пересмотр -означал бы либо второй запуск разметчика (ровно то, что здесь убрано), либо -машинный порог, который на всякой нетипичной задаче срабатывает не туда. -Расхождение факта с разметкой ловится **журналом дефектов** в `docs/review.md`, -постфактум, и это единственный сигнал — ровно как и для всякой другой ошибки -выбора метки. +**Внутри прогона метка не пересматривается.** Разметчик видел дифф целиком, и +второй запуск на том же дереве вернул бы то же самое; правки по находкам инлайна +дифф растят, а задачу — нет. Ошибка выбора ловится **журналом дефектов** в +`docs/review.md`, постфактум, и это единственный сигнал — ровно как и для всякой +другой ошибки метки. ## Прогон без change — сценарий обслуживания @@ -683,7 +662,7 @@ change**: у работы, не меняющей поведения, дельт **Прогон ревью идёт в одном из двух режимов, и режим — не глубина.** - **С меткой** — обычный прогон по change: разметку сделал `review-scope`, состав - обеих стадий выведен из метки. + прогона выведен из метки. - **Без метки** — прогон сценария обслуживания: change нет, размечать нечего, план фиксирован и назван сценарием. Разметчик не запускается вовсе. @@ -804,7 +783,7 @@ change**: у работы, не меняющей поведения, дельт Два прохода, оба против **записанного** критерия. Машину не держат ни один, ребра между ними нет — уходят одним сообщением сразу после зелёного гейта, вместе со -стадией 3 или 4 — той, которую назначила метка. +ступенью 3 или 4 — той, которую назначила метка. - `review-specs` закрывает тему `requirements`. Критерий взят из **дельта-спек предлагаемого изменения**, а не из proposal, сообщения коммита или описания @@ -854,7 +833,7 @@ Recall темы `conventions` равен длине конвенций прое ## Ступень 3 — Темы (`medium` целиком; `small` и `large` — только свои темы проекта) Агент `review-basics`. Один проход, машину не держит, ничего не запускает и не -меряет — уходит одним сообщением вместе со стадией 2, сразу после зелёного гейта. +меряет — уходит одним сообщением вместе со ступенью 2, сразу после зелёного гейта. **Он не самостоятельная оптика, а держатель тем, у которых с этой меткой нет своего проходчика.** На `medium` это `security`, `operations` и `architecture`: @@ -891,7 +870,7 @@ Recall темы `conventions` равен длине конвенций прое ## Ступень 4 — Доказательство (только `large`) Три прохода, и все три уходят сразу после зелёного гейта, в одном ряду со -стадией 2. Каждый берёт свою тему и доводит её до **доказательства**: +ступенью 2. Каждый берёт свою тему и доводит её до **доказательства**: - `review-adversary`, тема `security` — находка есть **построенный путь**, а не свойство: он пишет падающий тест и гоняет его; @@ -909,7 +888,7 @@ Recall темы `conventions` равен длине конвенций прое её только прямое слово оператора про эту пару, и тогда в границы покрытия идёт строка, что числа прогона сняты под соседней нагрузкой. -**Эта стадия зарабатывает больше всех остальных вместе — и она же дороже всех +**Эта ступень зарабатывает больше всех остальных вместе — и она же дороже всех остальных вместе.** Измерено на пяти задачах подряд: враждебный проход дал пять из семи выживших находок дозапуска (включая обе верхние); эксплуатационный — единственный, кто нашёл, что откат бинаря поверх новой схемы стартует молча. Оба @@ -927,9 +906,9 @@ Recall темы `conventions` равен длине конвенций прое (эксплуатация и хранилище) — эксплуатационному, `architecture` (устройство, граница домена) — архитектурному. Что с чем сшивать и почему — [project-facts.md](references/project-facts.md), раздел «Сшивать обязаны -проходы». Без домов стадия вырождается в общие места. +проходы». Без домов ступень вырождается в общие места. -**Числа и решения проекта эта стадия больше не читает.** `research.*` и `adr.*` — +**Числа и решения проекта эта ступень больше не читает.** `research.*` и `adr.*` — процессные документы, и прогон их не открывает. Для эксплуатационного прохода это значит, что **число он обязан снять сам** — замером, а не цитатой из чужой записки; для архитектурного — что граница домена берётся из `passport.*`, а не из @@ -987,85 +966,6 @@ change»: сверять исход с планом триаж обязан и понижение неподтверждённого до гипотезы → отсев вкусовщины → ранжирование по ущербу × вероятности → потолок 7 пунктов в основном списке. -## Ревью дизайна — до кода - -Запускается на первой стадии ревью (шаг 4 скилла -`av-dev:code-resolve`), когда change уже имеет `proposal.md` и -дельта-спеки, но кода ещё нет. Разметка задачи к этому моменту уже прошла — она -шагом раньше, и метка известна. - -**Состав растёт метками — теми же, что у ревью кода, и по той же паре осей.** -Их называет разметка задачи, а не вызывающий: величина считается один раз и -служит обеим стадиям. - -| Метка | Проходы на предложении | Проходов | -|---|---|---| -| `small` — малое и знакомое | `specs` | **1** | -| `medium` — среднее и знакомое | `specs`, `rubric` | **2** | -| `large` — крупное или незнакомое | `specs`, `rubric`, `architecture` + вопрос автору | **3** | - -- **всегда** — `review-specs` в режиме «дизайн ДО кода». Дельта-спеки сверяются - на каждой задаче: это самый дешёвый проход конвейера, и он ловит то, что на - готовом коде уже не чинят; -- **со `medium`** — `review-rubric`: рубрика на задуманный узел, по ней же - разбирается дельта-спека, а сами пункты уезжают приёмочными критериями в - `tasks.md`; -- **только в `large`** — `review-architecture` на предложении: можно ли выразить - существующими понятиями — **включая конструкции стандартной библиотеки**, — не - появляется ли второй способ. Вопрос «не изобретаем ли то, что уже есть в - библиотеке» живёт здесь; тогда же задаётся вопрос автору дизайна: **«предложи - три формы решения и назови компромисс каждой»** — если ответ показывает, что - рассматривалась одна, это находка. - -**Рубрика съехала на метку вниз, а архитектура осталась наверху — и это не -симметричная правка.** Раньше оба прохода включались одним условием, и `medium` -получал на предложении ровно один проход, то есть не отличался от `small` вовсе. -Разводятся они потому, что зарабатывают на разном: рубрика порождает **свойства -узла** и окупается уже на среднем изменении — её выход уезжает приёмочными -критериями в `tasks.md` и работает потом на всей задаче; архитектура отвечает на -вопрос «не появился ли второй способ», а он на среднем знакомом изменении -отвечается «нет» ещё до запуска. Держать её ниже `large` значит платить за -предсказуемый ответ на каждой задаче. - -Причина меток — арифметика, а не экономия на осторожности. Стадия стоит -**на каждой задаче**, поэтому каждый проход здесь умножается на число задач, и при -мелкой нарезке это самая большая статья конвейера. - -**Граф этой стадии свой, и он плоский.** Гейта нет — кода ещё нет, запускать -нечего; метка уже названа разметкой задачи; машину не держит ни один проход; -сток — не триаж, а шаг скилла `av-dev:code-resolve`, где замечания -отрабатываются правкой спек. Триаж здесь не нужен: находок единицы, и каждая -либо правит спеку, либо -становится развилкой. - -```mermaid -flowchart TD - plan[/"план разметки задачи:
размер, сложность, метка"/] - proposal["предложение: proposal.md + дельта-спеки"] - specs["specs (режим «дизайн ДО кода») — всегда"] - rubric["rubric → приёмочные критерии в tasks.md"] - arch["architecture на предложении"] - author["вопрос автору: три формы решения и компромисс каждой"] - fix["шаг resolve: правка спек, развилки — вопросом в запись"] - - plan --> proposal - proposal --> specs - proposal -->|"метка ≥ medium"| rubric - proposal -->|"метка = large"| arch - proposal -->|"метка = large"| author - specs --> fix - rubric --> fix - arch --> fix - author --> fix -``` - -Смысл стадии: архитектурная находка на готовом коде стоит переписывания и -поэтому игнорируется; та же находка на предложении стоит абзаца обсуждения. - -`rubric` живёт **только** на этой стадии. Судить код по критерию, под который он -писался, — корреляция по построению; те же 8–12 свойств уже лежат приёмочными -критериями в `tasks.md`. - ## Контракт находок Единый для всех проходов — [references/finding-contract.md](references/finding-contract.md). @@ -1185,10 +1085,11 @@ flowchart TD он тратил больше всех остальных проходов вместе, — а не по замеру, который [calibration.md](references/calibration.md) требует перед удалением. Значит и записывается это как сознательное сужение, а не как «класс оказался пустым»: -остаток независимого взгляда даёт ревью дизайна (код пишется под его находки) и -`architecture` (второй способ, лишние слои), но **альтернативной реализации, с -которой можно сдиффить решения, у конвейера теперь нет**. Класс идёт строкой в -границы покрытия каждого прогона — там же, где проект перечисляет своё в +остаток независимого взгляда даёт `architecture` (второй способ, лишние слои), но +**альтернативной реализации, с которой можно сдиффить решения, у конвейера теперь +нет**. Сузилось это дважды: вместе с проходом независимой реализации ушла и +стадия ревью дизайна, ловившая форму решения до того, как код написан. Класс +идёт строкой в границы покрытия каждого прогона — там же, где проект перечисляет своё в подразделе «перестали проверять сознательно». Это и есть причина, по которой конвейер готовит ревью, а не заменяет его. diff --git a/av-dev/skills/code-review/references/review-levels.md b/av-dev/skills/code-review/references/review-levels.md index 27139cf..c00a462 100644 --- a/av-dev/skills/code-review/references/review-levels.md +++ b/av-dev/skills/code-review/references/review-levels.md @@ -42,10 +42,12 @@ а именно эта пара и есть рабочее умолчание. Теперь обе оси называются в плане поимённо, и обе — с обоснованием. -**Оси называются и на стадии дизайна, и на стадии кода — но считаются один -раз.** Это и есть причина, по которой разметка переехала к `propose`: состав -ревью дизайна выводится из той же пары, что и состав ревью кода, а считать её -дважды значит один раз посчитать без разведённости с автором. +**Обе оси считаются один раз — по готовому диффу.** Раньше разметка шла до кода, +и размер приходилось выводить из написанного о задаче: перечня границ, `tasks.md`, +дельта-спек. Теперь размер меряется по тому, что тронуто на самом деле, а +написанное о задаче остаётся источником **сложности**: признак незнакомого — +нельзя было назвать тронутые узлы заранее — проверяется сверкой обещанного с +сделанным. **Обратимость — не третья ось, а отрицательный тест.** Она не уточняет размер и не уточняет сложность: она запрещает нижнюю метку независимо от обеих. @@ -105,9 +107,8 @@ пределы своего скилла он ходит вызовом, а не файлом. Разметка в костяк не входит — она платится один раз на задачу, а не один раз на -прогон, и потому **разрез задачи её не удваивает**. Это единственное, что стало -дешевле от переезда разметки к `propose`, и это же снимает прежний довод против -нарезки. +прогон, и потому **перезапуск прогона её не удваивает**. Разрез задачи, впрочем, +удваивает: у каждой половины свой дифф, и мерить его приходится порознь. **Размер, сложность, метка и глубина объявляются в отчёте, и все четыре с обоснованием.** Метка выбирает `review-scope`; он вправе и поднять, и понизить diff --git a/av-dev/skills/doc-init/SKILL.md b/av-dev/skills/doc-init/SKILL.md index 9029fc2..1a4f2f3 100644 --- a/av-dev/skills/doc-init/SKILL.md +++ b/av-dev/skills/doc-init/SKILL.md @@ -123,7 +123,7 @@ description: "Завести новый проект — сессия вопро 2. Проведи интервью итерациями по ≤3 вопроса. 3. **OpenSpec — вызови Skill `av-dev:code-openspec`.** Он заводит каталог и заменяет пример в `config.yaml` настройкой. Делается это **до первого - документа**: без `openspec/` не работают ни `opsx:propose`, ни ревью дизайна, + документа**: без `openspec/` не работают ни `opsx:propose`, ни сверка требований. Каталог принадлежит конвейеру, а не канону, поэтому здесь только вызов — ни команды, ни формы файла `init` не знает. diff --git a/decisions/74-design-review-dropped-scope-after-code.md b/decisions/74-design-review-dropped-scope-after-code.md new file mode 100644 index 0000000..744bf65 --- /dev/null +++ b/decisions/74-design-review-dropped-scope-after-code.md @@ -0,0 +1,74 @@ +# 74. Ревью дизайна снято, разметка переехала за код (2026-08-23) + +## Что было + +Сценарий решения шёл так: `propose` → разметка → ревью дизайна → чекпоинт → +`apply` → ревью кода. Разметка считала метку по написанному о задаче, а стадия +ревью дизайна смотрела предложение до кода: `specs` на каждой задаче, `rubric` с +`medium`, `architecture` с `large`. + +Замер по прогонам в проекте transcriber 22–23 августа: полный прогон сценария +занимал 3 часа 20 минут машинного времени, из них разметка и ревью дизайна с +отработкой находок — 30 минут, а повторная разметка с повторным архитектурным +проходом после чекпоинта — ещё 15. Владелец назвал целью час на прогон. + +## Решено + +**Р280. Стадия ревью дизайна снята целиком.** Ни `specs`, ни `rubric`, ни +`architecture` на предложении не запускаются. Требования сверяет `specs` на +готовом коде — тот же проход, тот же дом темы, другой момент. + +**Р281. Разметка переехала за `apply`.** `review-scope` идёт после того, как код +написан и гейт зелёный, и до первой ступени прогона. Величина по-прежнему +считается один раз на задачу: перезапуск прогона по находке «переделать форму» +разметку не повторяет. + +**Р282. Размер меряется по диффу, сложность — по написанному о задаче.** Дифф +отвечает «сколько мест тронуто на самом деле» и ничего не обещает; на вопрос +«знали ли форму решения заранее» он не отвечает вовсе — по готовому коду не +видно, нащупывали его или писали по образцу. Признак незнакомого стал +проверяемым: **обещанные границы задачи сверяются с тронутыми**, разошлись +поимённо — формы не знали. + +**Р283. Правило «метка не пересматривается по факту диффа» снято.** Оно +существовало ровно потому, что разметка шла до кода: пересмотр означал бы второй +запуск разметчика. Теперь дифф — вход разметки, а не повод её оспорить, и +пересматривать внутри прогона нечего: второй запуск на том же дереве вернёт то +же самое. + +**Р284. Чекпоинт остался и переехал к предложению.** Он стоит сразу после +`propose` и до кода. Прежде он стоял после ревью дизайна намеренно — человек +читал объяснение, уже просеянное машиной; теперь просеивать нечем, и это прямая +цена решения. Взамен стоп пришёл раньше: коррекция здесь стоит правки спеки, а не +переписывания готового кода. + +**Р285. `review-rubric` осиротел, и это сказано в его уставе.** Проход жил только +на снятой стадии: рубрика, составленная при видимом коде, подстраивается под +увиденное, а судить код по критерию, под который он писался, — корреляция по +построению. Устав остаётся рабочим для прямого вызова человеком; конвейер его не +зовёт. + +**Р286. Приёмочные критерии приходят только от постановки и с чекпоинта.** +Раньше третьим источником была рубрика, уезжавшая в `tasks.md`. Слот в скелете +`openspec/config.yaml` снят вместе с ней. + +## Следствия + +**С257. Архитектурная находка теперь стоит переписывания.** Довод «та же находка +на предложении стоит абзаца» был основанием стадии, и он остаётся верным — просто +конвейер за него больше не платит. `architecture` работает по коду и только с +меткой `large`; что этот класс сузился, идёт строкой в границы покрытия каждого +прогона. + +**С258. Разведённость выбора метки сохранена, а её основание сменилось.** Прежде +метка выбиралась **до** кода, и давление «я почти закончил» на неё не действовало +по построению. Теперь защита держится только на том, что метку называет не автор: +разметчик работу не писал и обе оси выводит из фактов. + +**С259. Разрез задачи снова удваивает разметку.** У каждой половины свой дифф, и +мерить его приходится порознь; прежний довод «разметка платится один раз на +задачу, и разрез её не удваивает» верен теперь только для перезапуска прогона. + +**С260. Стадий у ревью больше нет — есть ступени.** Слово «стадия» в конвейере +означало членение, видное снаружи; оно исчезло вместе со второй стадией, и проза +приведена к «ступени». diff --git a/decisions/README.md b/decisions/README.md index c093702..1526641 100644 --- a/decisions/README.md +++ b/decisions/README.md @@ -125,3 +125,4 @@ | 71 | [Образец языка назван прямо; «интейк» снят вслед за «провенансом»](71-language-model-popular-science.md) | 2026-08-13 | | 72 | [Письмо уходит агентам: оркестратор ставит задание и читает возврат](72-writing-delegated-to-agents.md) | 2026-08-22 | | 73 | [Гейт, прогнанный до ревью, не гоняется второй раз](73-gate-run-reused-by-fingerprint.md) | 2026-08-23 | +| 74 | [Ревью дизайна снято, разметка переехала за код](74-design-review-dropped-scope-after-code.md) | 2026-08-23 |