resolve: ревью дизайна снято, разметка переехала за код

Сценарий решения идёт от предложения сразу к чекпоинту и коду: стадия ревью
дизайна упразднена целиком, review-scope запускается после apply и меряет
размер по диффу, сложность — сверкой обещанных границ с тронутыми. Чекпоинт
остался единственным плановым стопом и стоит теперь до кода. review-rubric
конвейером не зовётся, слот рубрики в скелете config.yaml снят. Журнал —
тема 74.
This commit is contained in:
av
2026-08-23 15:08:17 +03:00
parent 17be316634
commit 72d9aa8034
19 changed files with 356 additions and 417 deletions
+1 -1
View File
@@ -427,7 +427,7 @@ kebab-case.** Причина не эстетическая: имя файла с
**Файл канону не принадлежит, и проверяет его тоже не канон.** Каталог
`openspec/` — предпосылка конвейера: без него не работают ни `opsx:propose`, ни
ревью дизайна, ни сверка требований. Заводит его, настраивает и **проверяет
сверка требований. Заводит его, настраивает и **проверяет
форму** скилл `av-dev:code-openspec`: там образец файла, там же скрипт
`openspec.py check`. `docs.py` о файле не говорит ничего.
@@ -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` — закомментированный пример на английском. Такой файл
+2 -2
View File
@@ -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 и работает.
@@ -69,7 +69,6 @@ rules:
- "Заголовки и WHEN/THEN/GIVEN — на английском, остальной текст на русском"
tasks:
- "Критерии приёмки задачи — отдельным блоком и дословно: файл задачи закрытие удалит, критерии обязаны его пережить"
- "Рубрика ревью дизайна, если оно её дало, идёт в тот же блок: приёмка судится по одному списку, а не по двум"
- "Шаг плана формулируется проверяемо — по нему видно «сделано / не сделано» без суждения"
```
@@ -88,9 +87,8 @@ ADR** — отвергнутый вариант с названной причи
**Правила для `tasks` держит тот же скилл, и по той же причине — момент
порождения.** `tasks.md` — единственное, что переживает задачу: файл задачи
закрытие удаляет, а приёмка потом судится по критериям, которые в него
скопированы. Туда же ложится рубрика ревью дизайна, если оно её дало. Записанное
в момент порождения не приходится вспоминать шагом позже, когда артефакт уже
написан. Блок `context` проект
скопированы. Записанное в момент порождения не приходится вспоминать шагом позже,
когда артефакт уже написан. Блок `context` проект
дополняет своим (стек, разведка, особенности домена), но **адреса паспорта и
`CLAUDE.md` обязательны** — отсутствие адреса к существующему документу
`openspec.py check` называет отказом.
@@ -2,7 +2,7 @@
"""Форма `openspec/config.yaml`: проверка проекта и сверка слепка с инструментом.
Каталог `openspec/` — предпосылка **конвейера**, а не канона документов: без него
не работают ни `opsx:propose`, ни ревью дизайна, ни сверка требований. Поэтому и
не работают ни `opsx:propose`, ни сверка требований конвейером. Поэтому и
проверка формы живёт здесь, рядом со скиллом, который каталог заводит. Раньше она
жила в `docs.py`, у скилла канона, и у файла было два владельца: один заводит,
другой проверяет.
+10 -10
View File
@@ -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/<id>/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
## Автономность и плановый стоп
**У двух сценариев ровно один плановый стоп**, и стоят они в разных местах:
у решения — объяснение после ревью дизайна, у разведки — варианты до первого
написанного требования. Правило вокруг них общее.
у решения — объяснение сразу после предложения и до кода, у разведки — варианты
до первого написанного требования. Правило вокруг них общее.
**У обслуживания планового стопа нет вовсе, и это следствие, а не поблажка.**
Один стоп с ожиданием ответа у него всё же есть — по найденной дельта-спеке, — но
@@ -125,8 +125,8 @@
**Третьего решения — «доделать как обслуживание» — нет.** Оно и есть то самое
молчаливое изменение поведения, против которого стоит весь разрез: под коммитом,
заявляющим «поменяли оснастку», уехала бы правка, не прошедшая ни ревью дизайна,
ни чекпоинта, и не оставившая следа в спеках.
заявляющим «поменяли оснастку», уехала бы правка, не прошедшая ни чекпоинта, ни
ревью по метке, и не оставившая следа в спеках.
**Сделанное не выбрасывается ни при каком из двух решений.** Оно остаётся в
рабочем дереве незакоммиченным: при переформулировке уезжает в change следующим
+85 -119
View File
@@ -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. прочитать задачу<br/>критерии приёмки выписать сразу"]
s2["2. opsx:propose — change, дельта-спеки,<br/>tasks.md — агентом"]
s3["3. разметка — review-scope:<br/>размер, сложность, метка, план тем"]
s4["4. ревью дизайна, состав по метке<br/>+ отработка замечаний агентом"]
s5(["5. ЧЕКПОИНТ: объяснение<br/>в чём проблема, как решаем,<br/>чем рискуем"])
s6["6. opsx:apply — код, гейт,<br/>поведенческая верификация — агентом"]
s7["7. ревью кода, та же метка<br/>+ отработка замечаний агентом"]
s8["8. opsx:archive"]
s9["9. синк документации — av-dev:doc-sync"]
s10["10. коммит работы — av-dev-git:commit"]
s11["11. закрыть задачу — av-dev:task-track,<br/>вторым коммитом учёта"]
s3(["3. ЧЕКПОИНТ: объяснение<br/>в чём проблема, как решаем,<br/>чем рискуем"])
s4["4. opsx:apply — код, гейт,<br/>поведенческая верификация — агентом"]
s5["5. разметка — review-scope по диффу:<br/>размер, сложность, метка, план тем"]
s6["6. ревью кода по метке<br/>+ отработка замечаний агентом"]
s7["7. opsx:archive"]
s8["8. синк документации — av-dev:doc-sync"]
s9["9. коммит работы — av-dev-git:commit"]
s10["10. закрыть задачу — av-dev:task-track,<br/>вторым коммитом учёта"]
in --> s1
s1 --> s2 --> s3 --> s4 --> s5 --> s6 --> s7 --> s8 --> s9 --> s10 --> s11
s3 -.->|"план задачи: та же метка"| s7
s5 -.->|"скорректировать:<br/>меняются дельта-спеки"| s3
s7 -.->|"находка отменяет дизайн:<br/>меняются дельта-спеки"| s3
s1 --> s2 --> s3 --> s4 --> s5 --> s6 --> s7 --> s8 --> s9 --> s10
s5 -.->|"план задачи: темы и глубины"| s6
s3 -.->|"скорректировать:<br/>правка спек и дизайна"| s3
s6 -.->|"находка отменяет дизайн:<br/>меняются дельта-спеки"| 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 `<id>`,
**план разметки с шага 3** и указание, что это ревью дизайна.
Состав приходит планом, а не решается здесь:
| Метка | Проходы на предложении |
|---|---|
| `small` | `specs` |
| `medium` | `specs`, `rubric` |
| `large` | `specs`, `rubric`, `architecture` + вопрос автору о трёх формах решения |
`review-specs` в режиме «дизайн ДО кода» идёт **на каждой задаче**: это самый
дешёвый проход конвейера, и он ловит то, что на готовом коде уже не чинят.
Остальные включаются меткой, потому что стадия стоит на каждой задаче и каждый
лишний проход здесь умножается на число задач.
Смысл стадии: архитектурная находка на готовом коде стоит переписывания и потому
игнорируется — та же находка здесь стоит абзаца обсуждения. Если `review-rubric`
запускался, перенеси его рубрику в `tasks.md` как приёмочные критерии; там же уже
лежат критерии от постановки, если они были.
**Отработка замечаний, и она идёт до чекпоинта, а не после:**
- мелочь и явные улучшения — правкой спек и дизайна, и её делает **агент**
(SKILL.md, «Кто пишет»): находки уходят ему дословно, вместе с
идентификатором change и требованием перепрогнать
`openspec validate --strict <id>`;
- развилки (компромисс, 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 <id>`. Затем чекпоинт **заново** — правленое
объяснение читает тот же человек. Разметки на этот момент ещё нет, и повторять
здесь нечего: она идёт после кода;
- **не одобрено** — исход «не доведена» с причиной. 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 `<id>`,
базу диффа, **план разметки с шага 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/<id>/review/`; шаг 8
**Отчёт триажа сохрани вместе с change (`openspec/changes/<id>/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`, у него на
+88 -187
View File
@@ -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 — разметка задачи<br/>размер × сложность → МЕТКА"]
checkpoint(["чекпоинт: объяснение человеку"])
apply["opsx:apply — код, гейт зелёный"]
scope["review-scope — разметка по диффу<br/>размер × сложность → МЕТКА"]
label{{"метка"}}
subgraph design["Ревью дизайна — до кода"]
dS["specs — всегда"]
dR["+ rubric"]
dA["+ architecture<br/>+ вопрос автору о трёх формах"]
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 при своих темах) | **56** | **до трети, и меньше, чем `medium`** |
| `medium` | **рабочее умолчание**: среднее и знакомое | `specs`, `rubric` | 1, 2, 3, 5 | **7** | **большинство** |
| `large` | крупное **или** незнакомое: большой рефакторинг, функциональность, форму которой ещё предстоит нащупать | `specs`, `rubric`, `architecture` | 1, 2, 4, 5 (+3 при своих темах) | **1011** | **510%** |
Ревью дизайна разбирается отдельно ниже — оно идёт до кода, у него свой плоский
граф и свой сток. Здесь оно стоит в таблице потому, что **метка у обеих стадий
общая**, и увидеть цену задачи можно только сложив их.
| Метка | Когда | Ступени | Проходов | Доля задач |
|---|---|---|---|---|
| `small` | малое **и** знакомое: багфикс, локальная правка, доки | 1, 2, 5 (+3 при своих темах) | **45** | **до трети, и меньше, чем `medium`** |
| `medium` | **рабочее умолчание**: среднее и знакомое | 1, 2, 3, 5 | **5** | **большинство** |
| `large` | крупное **или** незнакомое: большой рефакторинг, функциональность, форму которой ещё предстоит нащупать | 1, 2, 4, 5 (+3 при своих темах) | **78** | **510%** |
**Разметка в этих числах не считается — её платят один раз на задачу, а не один
раз на прогон.** Она ушла из состава ревью кода целиком: `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[/"план разметки задачи:<br/>размер, сложность, метка"/]
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` (второй способ, лишние слои), но
**альтернативной реализации, с которой можно сдиффить решения, у конвейера теперь
нет**. Сузилось это дважды: вместе с проходом независимой реализации ушла и
стадия ревью дизайна, ловившая форму решения до того, как код написан. Класс
идёт строкой в границы покрытия каждого прогона — там же, где проект перечисляет своё в
подразделе «перестали проверять сознательно».
Это и есть причина, по которой конвейер готовит ревью, а не заменяет его.
@@ -42,10 +42,12 @@
а именно эта пара и есть рабочее умолчание. Теперь обе оси называются в плане
поимённо, и обе — с обоснованием.
**Оси называются и на стадии дизайна, и на стадии кода — но считаются один
раз.** Это и есть причина, по которой разметка переехала к `propose`: состав
ревью дизайна выводится из той же пары, что и состав ревью кода, а считать её
дважды значит один раз посчитать без разведённости с автором.
**Обе оси считаются один раз — по готовому диффу.** Раньше разметка шла до кода,
и размер приходилось выводить из написанного о задаче: перечня границ, `tasks.md`,
дельта-спек. Теперь размер меряется по тому, что тронуто на самом деле, а
написанное о задаче остаётся источником **сложности**: признак незнакомого —
нельзя было назвать тронутые узлы заранее — проверяется сверкой обещанного с
сделанным.
**Обратимость — не третья ось, а отрицательный тест.** Она не уточняет размер и
не уточняет сложность: она запрещает нижнюю метку независимо от обеих.
@@ -105,9 +107,8 @@
пределы своего скилла он ходит вызовом, а не файлом.
Разметка в костяк не входит — она платится один раз на задачу, а не один раз на
прогон, и потому **разрез задачи её не удваивает**. Это единственное, что стало
дешевле от переезда разметки к `propose`, и это же снимает прежний довод против
нарезки.
прогон, и потому **перезапуск прогона её не удваивает**. Разрез задачи, впрочем,
удваивает: у каждой половины свой дифф, и мерить его приходится порознь.
**Размер, сложность, метка и глубина объявляются в отчёте, и все четыре с
обоснованием.** Метка выбирает `review-scope`; он вправе и поднять, и понизить
+1 -1
View File
@@ -123,7 +123,7 @@ description: "Завести новый проект — сессия вопро
2. Проведи интервью итерациями по ≤3 вопроса.
3. **OpenSpec — вызови Skill `av-dev:code-openspec`.** Он заводит каталог и
заменяет пример в `config.yaml` настройкой. Делается это **до первого
документа**: без `openspec/` не работают ни `opsx:propose`, ни ревью дизайна,
документа**: без `openspec/` не работают ни `opsx:propose`,
ни сверка требований. Каталог принадлежит конвейеру, а не канону, поэтому
здесь только вызов — ни команды, ни формы файла `init` не знает.