В цикле задачи темы security и operations закрывает один лёгкий проход review-proof: чтением и рассуждением, без запуска, потолки раздельные. Машину он не держит, поэтому идёт в общем залпе — цепочки за ресурс в обычном прогоне не осталось. Тяжёлая пара adversary и ops переехала в новый скилл code-deep-review: вход — названная область кода, глубина постоянная, исход — разбор с человеком и задачи через task-track. Вход глубокому прогону копит сам цикл строками «отложено». Журнал — тема 76.
1123 lines
104 KiB
Markdown
1123 lines
104 KiB
Markdown
---
|
||
name: code-review
|
||
description: "Конвейер ревью изменения, устроенный по темам: документ проекта либо заводит тему ревью, либо питает чужую тему источником, либо процессный и в ревью не читается вовсе. Ядро тем — requirements, autotests, conventions, architecture, security, operations; список тем открытый, свои темы проект заводит документом. Разметка задачи идёт один раз, после apply: агент review-scope выводит размер по диффу и сложность по форме решения, из их максимума — метка, и раздаёт темы проходам. Метка правит состав ревью кода: small — гейт, спеки, код, триаж; medium — плюс приёмник тем; large — плюс review-proof (security и operations разом, чтением и рассуждением) и архитектурный проход на широком входе. Триаж обязателен всегда. Порядок прогона — граф зависимостей: гейт открывает проходы с мнением, триаж — единственный сток; проходы с пометкой «держит машину» идут цепочкой, но в обычном прогоне таких нет. Тяжёлые проходы — adversary и ops — переехали в скилл av-dev:code-deep-review, который идёт по области кода и время от времени. Проектная специфика приходит из документов канона проекта. Вызывается из скилла av-dev:code-resolve после apply. Второй вызов идёт от сценария обслуживания: без change и без метки, фиксированным планом (autotests, operations, плюс conventions, если тронут код), разметчик при этом не запускается."
|
||
---
|
||
|
||
# Конвейер ревью
|
||
|
||
Готовит ревью — **не заменяет его**. Потребитель отчёта — оркестратор, который
|
||
чинит код; человек читает только сводку, развилки и границы покрытия.
|
||
|
||
## Четыре правила, из которых всё следует
|
||
|
||
Если ситуация не покрыта инструкцией — решай по ним.
|
||
|
||
0. **Тема первична, проход вторичен.** Ревью проверяет **темы** — набор
|
||
направлений, который проект объявляет своими документами. Проход это только
|
||
способ закрыть тему на заданной глубине, и проходы меняются: уезжают в старшую метку, сливаются, упраздняются. Если состав прогона считать списком проходов,
|
||
то уехавший проход уносит тему с собой **беззвучно** — отчёт честно скажет
|
||
«`ops` не запускался» и не скажет «эксплуатацию не смотрел никто», а нужно
|
||
второе. Проверено на живом переезде: `ops` ушёл в `av-dev:code-deep-review`, а
|
||
тема `operations` осталась в конвейере и досталась `proof`. Поэтому прогон описывается таблицей «тема → глубина → кто закрывает», и
|
||
таблица эта есть в каждом отчёте.
|
||
|
||
1. **Recall чек-листа равен длине чек-листа.** Проход, устроенный как «проверь
|
||
пункты 1..N», найдёт ровно перечисленное. Всё неявное — идиомы, форма
|
||
решения, «так не делают» — неперечислимо по определению: перечислимое уже
|
||
стало бы конвенцией. Отсюда деление проходов на **applicative** (применяют
|
||
заданный критерий) и **generative** (сперва порождают критерий или
|
||
альтернативу, потом сравнивают). Расширять чек-листы бесполезно; неявный слой
|
||
достают только generative-проходы.
|
||
2. **Ценность верификатора = наличие внешнего оракула × разведённость с
|
||
автором**, а не число ролей. Под всеми ролями одна модель с одними
|
||
априорными, вход у всех общий: седьмая роль почти не добавляет recall, но
|
||
линейно удорожает триаж. Иерархия надёжности: детерминированный инструмент >
|
||
агент, который его **запускает** и интерпретирует вывод > агент с чистым
|
||
мнением. Максимум работы переносим вниз.
|
||
3. **Отчёт без границ покрытия хуже отсутствия отчёта.** «Критичных проблем не
|
||
обнаружено» потребляет ощущение проверенности, ничего не гарантируя. Секция
|
||
границ покрытия обязательна и не сокращается — в том числе в докладе человеку.
|
||
|
||
## Предпосылки
|
||
|
||
Конвейер опирается на внешнюю обвязку и без неё работает не целиком. Проверь это
|
||
один раз, при установке плагина в проект:
|
||
|
||
- **OpenSpec — жёсткая предпосылка, а не опция.** Ревью дизайна, проход
|
||
`review-specs` и
|
||
вызывающий скилл `av-dev:code-resolve` завязаны на дельта-спеки
|
||
(`openspec/changes/<id>/specs/*/spec.md`), на актуальные спеки
|
||
(`openspec/specs/`) и на `openspec validate --strict`. В проекте без OpenSpec
|
||
шаги, зовущие `opsx:explore` / `opsx:propose` / `opsx:apply` / `opsx:archive`,
|
||
упадут на «нет такого скилла», а `review-specs` останется без источника
|
||
требований. **Проект без OpenSpec этим конвейером не проверяется** — подключай
|
||
OpenSpec, а не понижай прогон: ветка деградации здесь не пишется, потому что
|
||
непроверенная ветка деградации хуже честного отказа. Заводить руками не надо:
|
||
этим владеет скилл `av-dev:code-openspec` — он заводит каталог и заменяет
|
||
пример в `config.yaml` настройкой. Его же зовут `av-dev:doc-init` на новом
|
||
проекте и `av-dev:canon` в режиме `adopt` — на переводимом.
|
||
**Предпосылка эта — про изменение поведения, а не про всякий прогон:**
|
||
сценарий обслуживания зовёт конвейер без change и без дельта-спек, и ни один
|
||
проход его плана на них не завязан. См. «Прогон без change».
|
||
- **Документы канона** — см. следующий раздел.
|
||
- **Проектные копии этих скиллов и агентов удаляются при установке.**
|
||
|
||
<!-- копия: проектные-копии из README.md -->
|
||
|
||
Голые имена в `.claude/skills/`: `resolve`, `review`, а у проектов прошлого
|
||
поколения ещё `task-pipeline`, `review-pipeline`, `task-batch`. С префиксом
|
||
проекта: `<проект>-task-pipeline`, `<проект>-review-pipeline`. Агенты:
|
||
`.claude/agents/<проект>-review-*.md`.
|
||
|
||
Две копии одного скилла расходятся, и побеждает та, что **короче названа**:
|
||
короткое имя разрешится в устаревшую проектную копию молча и без признаков
|
||
подмены.
|
||
|
||
<!-- /копия: проектные-копии -->
|
||
|
||
### Чего может не быть
|
||
|
||
**Копия.** Дом правила — `shared/absence.md` в репозитории плагина.
|
||
Правится дом, а не этот файл.
|
||
|
||
<!-- копия: отсутствие из av-dev/shared/absence.md -->
|
||
|
||
**Скилл не вправе считать раскладку проекта полной.** Части заводятся порознь и
|
||
живут порознь; каждая узнаётся своим следом:
|
||
|
||
| Чего нет | Как видно | Чего теперь не делает никто |
|
||
| --- | --- | --- |
|
||
| настройки av-dev | нет `.av-dev.toml` в корне | проект под процесс не заводился; версии нет, настроек нет |
|
||
| документы канона | нет `docs/` | проектную конкретику брать неоткуда — темы, инварианты, прецеденты |
|
||
| учёт работ | нет каталога задач | запись остаётся владельцу: назови её текстом в докладе |
|
||
| источник требований | нет `openspec/config.yaml` | цикл SDD не запускается: спеки не с чем сверять |
|
||
|
||
**Свой скилл зовётся полным именем** — `av-dev:canon`, `av-dev:task-track`,
|
||
`av-dev:code-review`. Короткое имя может разрешиться в устаревшую проектную
|
||
копию из `.claude/skills/`, и подмены не будет видно ни в докладе, ни в
|
||
поведении.
|
||
|
||
**Внешний плагин может не стоять.** Их два: `opsx:*` — цикл SDD, и
|
||
`av-dev-git:commit` — сообщения коммитов. Путь в дерево чужого плагина не
|
||
пишется никогда: `$CLAUDE_PLUGIN_ROOT` ведёт только в своё дерево, а
|
||
вычисленный от него путь к соседу либо не откроется, либо откроет чужую
|
||
установку. Нужен чужой справочник — зови владеющий им скилл, он прочитает его
|
||
сам.
|
||
|
||
**Отсутствие — исход, а не поломка.** Назови строкой доклада, чего теперь не
|
||
делает никто, и продолжай работу. Молчать нельзя: пропуск неотличим от
|
||
сделанного. Выдумывать обходной путь нельзя тоже.
|
||
|
||
**Присутствие узнаётся следом в проекте, а не объявлением.** Перечня того, что
|
||
здесь заведено, проект не ведёт — он разошёлся бы с действительностью молча.
|
||
|
||
<!-- /копия: отсутствие -->
|
||
|
||
Своих скиллов это касается ровно так же: `av-dev:code-review`,
|
||
`av-dev:code-resolve`, `av-dev:code-openspec` — подменяется короткое имя,
|
||
а не чужое.
|
||
|
||
## Темы, источники и процессные документы
|
||
|
||
Раньше здесь стояло плоское правило «каждый документ проекта — тема ревью». Оно
|
||
верно ровно наполовину, и потому вредно целиком: паспорт и схему хранилища
|
||
ревью читает, но темами они не являются, а журнал решений и журнал наблюдений
|
||
ревью изменения не нужны вовсе. Разметчик, применявший правило буквально, обязан
|
||
был либо завести фантомные темы и продублировать ими работу настоящих, либо
|
||
потерять документ молча.
|
||
|
||
**Разрез один и проверяемый — тот же, что в каноне: можно ли по документу
|
||
сказать «в этом изменении сделано не так»?**
|
||
|
||
| Категория | Что конвейер с ней делает | Кто в ней |
|
||
|---|---|---|
|
||
| **тема** | заводит направление проверки и требует исполнителя | `conventions.*`, `security.*`, `architecture.*`, свои документы проекта |
|
||
| **источник темы** | читает как материал чужой темы, своей не порождает | `passport.*`, `database.*`, `CLAUDE.md`/`AGENTS.md`, `openspec/specs/` |
|
||
| **процессный документ** | не судит по нему изменение | `tasks/`, `docs/review.*`, `docs/adr.*`, `docs/research.*`, `.av-dev.toml` |
|
||
|
||
**Одна процессная запись всё же читается — `docs/review.*`.** В ней лежит
|
||
настройка самого конвейера: вопросы по темам, журнал дефектов, типовые узлы,
|
||
типовые ложноположительные. Проход, читающий её, читает **свою обвязку**, а не
|
||
критерий, по которому судит изменение. `adr.*`, `research.*` и `tasks/` не
|
||
открывает никто.
|
||
|
||
Дом канона этой раскладки — скилл `av-dev:canon`, раздел «Три категории
|
||
документов». Конвейер её **читатель**: категории и имена тем он берёт
|
||
оттуда и своих не заводит.
|
||
|
||
Отсюда то, ради чего правило и заведено: **`docs/` перестаёт быть просто
|
||
документацией и становится конфигурацией конвейера**. Проект настраивает ревью
|
||
тем, что пишет о себе, а не отдельным файлом настроек, который разошёлся бы с
|
||
документами. **Открыта при этом только категория `тема`** — две другие закрыты
|
||
и перечислены поимённо, поэтому документ, которого нет в раскладке канона,
|
||
однозначно своя тема проекта, а не «что-то непонятное».
|
||
|
||
Ядро — шесть тем, они есть у любого проекта, приведённого к канону. Форма дома
|
||
значения не имеет: `docs/security.md` и `docs/security/` — одна тема `security`.
|
||
|
||
| Тема | Дом | Вопрос темы |
|
||
|---|---|---|
|
||
| `requirements` | `openspec/specs/`, дельты change | делает ли код заказанное, и только его |
|
||
| `autotests` | `CLAUDE.md`: семантика гейта, команды | проверено ли машиной и хватает ли проверок |
|
||
| `conventions` | `docs/conventions.*` | написано ли так, как здесь пишут |
|
||
| `architecture` | `docs/architecture.*` + источник `passport.*` | цело ли устройство: понятия и границы |
|
||
| `security` | `docs/security.*` | что сделает недоверенный вход |
|
||
| `operations` | `docs/architecture.*`, раздел эксплуатации + источник `database.*` | что будет через неделю на проде |
|
||
|
||
**Три темы ядра дома в `docs/` не имеют, и это не пробел.** `requirements` живёт
|
||
в `openspec/`, `autotests` — в `CLAUDE.md`, `operations` — разделом внутри
|
||
`architecture.*`. Имя темы поэтому не выводится из имени файла, и обратно тоже:
|
||
`docs/passport.md` не заводит темы `passport`.
|
||
|
||
**`adr/` и `research/` прогон больше не открывает.** Раньше архитектурный проход
|
||
читал решения, а эксплуатационный и `specs` — числа. Цена решения записана в
|
||
каноне и повторяется здесь, потому что платит её конвейер: **расхождение
|
||
изменения с записанным решением прогоном не ловится**, это работа сверки
|
||
документации — скилл `av-dev:doc-healthcheck`.
|
||
Строка об этом обязательна в границах покрытия каждого прогона.
|
||
|
||
**Своя тема проекта бывает двух происхождений, и обе законны:** документ, который
|
||
проект положил в `docs/` и которого нет в раскладке канона, — и **тема, названная
|
||
директивой** `CLAUDE.md`/`AGENTS.md`, у которой документа нет вовсе. У второй дом
|
||
— сама директива; в остальном она ничем не отличается, и в раздаче идёт туда же.
|
||
Различать их приходится потому, что условие запуска приёмника тем звучит «есть ли
|
||
свои темы проекта», и тема без файла в `docs/` иначе не попала бы под это условие
|
||
никогда.
|
||
|
||
**Проектная тема закрывается `basics`**, при любой метке. Именных проходов
|
||
конечное число, а тем — сколько заведёт проект; приёмник обязателен, иначе
|
||
открытость списка была бы обещанием без механизма. Темы **ядра** он держит только
|
||
на `medium`: на `small` их закрывает `code` сверкой по инвариантам, в `large` —
|
||
именные проходы. Отсюда правило состава: **`basics` запускается тогда и только
|
||
тогда, когда ему есть что принимать** — см. «Метки».
|
||
|
||
**Тема без дома — законное состояние и отдельная строка.** «Тема `operations`
|
||
заявлена, `docs/database.md` нет» читается иначе, чем «не смотрели». Деградация
|
||
поразрядная: нет дома — падает глубина этой темы, и только её.
|
||
|
||
Что именно проход читает по каждой теме — [references/project-facts.md](references/project-facts.md).
|
||
Отдельного файла-брифа при этом нет: пути известны, посредник не нужен, а второй
|
||
дом для тех же фактов разошёлся бы и выглядел актуальным.
|
||
|
||
**Документов канона нет вовсе** — проект не приведён к канону. Скажи это строкой
|
||
и предложи скилл `av-dev:canon`: одна операция на проект против деградации на
|
||
каждой задаче. Прогон при этом не останавливается.
|
||
|
||
## Что получает каждый проход
|
||
|
||
Задание собирается **по плану разметки задачи** и состоит из шести вещей:
|
||
|
||
- **его темы** — какие темы он закрывает на этом прогоне, у каждой **дом**
|
||
(путь и раздел) и **глубина**. Дом передаётся адресом, а не пересказом: проход,
|
||
получивший проинтерпретированный периметр, не заметит, что интерпретация
|
||
неверна;
|
||
- **вопросы по его темам** из `docs/review.*`, если они там есть, — **дословно**.
|
||
Вопрос привязан к теме, а не к имени прохода, и потому переживает переезд
|
||
прохода между метками;
|
||
- **контракт находок** — путь к
|
||
[references/finding-contract.md](references/finding-contract.md) (в
|
||
установленном плагине — `${CLAUDE_PLUGIN_ROOT}/skills/code-review/references/`);
|
||
- **изменение** — идентификатор change и путь к его дельта-спекам;
|
||
- **база диффа**;
|
||
- **метка, его глубина и режим** прогона — чтобы проход знал, что писать в
|
||
границы покрытия.
|
||
|
||
**Ступень 1 получает сверх этого исход гейта, прогнанного до ревью** — сводку,
|
||
путь к логам шагов и отпечаток дерева, — если вызывающий скилл его дал. Зачем и
|
||
что происходит при расхождении — «Ступень 1 — Автотесты».
|
||
|
||
Чего проход **не** получает ни в каком режиме — выводов других проходов. См.
|
||
«Порядок прогона».
|
||
|
||
## Модель по проходу
|
||
|
||
Модель выбирается **по цене ошибки прохода, а не по его роду**. Признак рабочий и
|
||
проверяемый: находка со ссылкой на записанный источник — строку спеки, цель в
|
||
манифесте, значение в конфиге — опровергается открытием файла, и дешёвая модель
|
||
ошибается здесь проверяемо; находка-суждение опровергается рассуждением, а
|
||
рассуждение стоит триажа или человека. Второй род ошибки — **пропуск**: он не
|
||
стоит ничего сегодня и не виден вовсе, и проход, у которого дороже пропустить,
|
||
держится наверху, даже будучи applicative.
|
||
|
||
Модель задана во frontmatter каждого агента, менять её здесь не нужно.
|
||
|
||
| Модель | Цвет | Проходы | Почему |
|
||
|---|---|---|---|
|
||
| `sonnet` | green | scope, autotests, ops | вывод перечислим и сверяется механически |
|
||
| `opus` | yellow | specs, code, basics, proof, rubric, architecture, triage | дорога ошибка — ложная либо пропущенная |
|
||
|
||
**`rubric` в составе прогона не стоит и в таблице держится за компанию.** Стадия,
|
||
где он жил, снята: рубрику на задуманный узел он порождает, не видя кода, а
|
||
конвейер работает по готовому диффу. Устав остаётся для прямого вызова человеком,
|
||
и модель у него та же — потому строка и не убрана.
|
||
|
||
**Цвет charter'а кодирует модель, а не роль прохода.** Это единственное
|
||
назначение цвета: список агентов читается взглядом, и по нему сразу видно, чем
|
||
платит прогон. Роль прохода из имени и так понятна, а цвет, розданный по ролям,
|
||
не отвечает ни на один вопрос, который задают во время прогона. Раскладка живёт
|
||
здесь и **проверяется механически** — цвет ставится один раз при заведении
|
||
charter'а, а модель потом двигает калибровка, и разъезжаются они молча.
|
||
|
||
**Моделей две, и верхняя из них — `opus`; выше неё конвейер не платит.** Замер:
|
||
на первом же прогоне самые ценные находки дали `opus`-проходы — сверка спек дала
|
||
13 находок с оракулами, а проход про идиоматичность (впоследствии упразднённый) —
|
||
три эксперимента против драйвера БД с воспроизведёнными числами. Разницы в пользу
|
||
модели **дороже** `opus` не обнаружилось ни на одном проходе, а прогон на ней
|
||
стоил заметно дольше и дороже — значит платить за неё не за что.
|
||
|
||
Четверо держатся наверху не за суждение, а по отдельным причинам, и их стоит
|
||
знать поимённо:
|
||
|
||
- `triage` — через него проходит всё, что оркестратор реализует **молча**:
|
||
ложноположительная находка становится кодом, потерянный `critical` — дефектом.
|
||
Ошибка триажа дороже ошибки любого отдельного прохода.
|
||
- `specs` — по устройству applicative, но направление `code → spec` требует
|
||
заметить **отсутствие**: тихий фолбэк, самодеятельный дефолт, проглоченную
|
||
ошибку. Здесь дорог пропуск, а не ложная находка.
|
||
- `code` — единственный, кто читает код **как код**. Его пропуск это дефект в
|
||
проде, и он тоже не оставляет следа ни в отчёте, ни в границах покрытия. По той
|
||
же причине, что `specs`, и это дороже всего в конвейере: проход идёт на каждой
|
||
задаче.
|
||
- `architecture` — запускается только со старшей меткой, на 5–10% задач, и
|
||
потолок в 3 находки делает его дешёвым по выходу. Его находка дороже прочих по
|
||
последствиям: второй способ делать то, что уже делается, переписыванием не
|
||
чинится, а живёт в кодовой базе годами. Дёшево × высокое плечо.
|
||
|
||
**`scope` внизу, и это не противоречие, хотя его ошибка расходится дальше
|
||
всех.** Он правит состав всего прогона и внутри прогона не пересматривается:
|
||
ошибка метки стоит всей проверки задачи, а не одного прохода. Модель он всё же
|
||
держит нижнюю, и вот почему. Его работа распадается надвое: разнесение документов
|
||
по категориям и раздача тем **перечислимы** — план сверяется с `ls docs/` за
|
||
секунду, пропущенный документ виден без рассуждения. Выбор метки — суждение, но с
|
||
переходом на две оси оно стало **дважды перечислимым**: размер считается по
|
||
диффу, сложность отвечается одним проверяемым признаком («можно ли было до работы
|
||
назвать тронутые узлы»). Плюс три независимых корректора: отрицательный
|
||
тест `small`, правило «спорный случай вниз» и **сигнал о заниженной метке от
|
||
`code`** — тот идёт при любой метке и видит дифф целиком. Дешёвая модель
|
||
безопасна ровно потому, что её вывод устроен как список,
|
||
а не как мнение.
|
||
|
||
**Самая дешёвая модель не используется ни на одном проходе, и это не экономия
|
||
наоборот.** Дешёвая модель на проходе с мнением даёт правдоподобные находки,
|
||
которые триаж обязан опровергать оракулом, — а это самая дорогая операция
|
||
конвейера. Механизируемая же работа здесь вынесена **ниже** модели: гейт,
|
||
покрытие диффа, карта проекта — это скрипты проекта, они стоят ноль токенов.
|
||
Дешёвому проходу просто не осталось работы.
|
||
|
||
Экономия достигается **не понижением модели, а тремя другими рычагами**, и все
|
||
три применяются к каждому проходу с мнением, а не к одному избранному.
|
||
|
||
1. **Непуск.** `large` добавляет две темы риска и взгляд на устройство; `small`
|
||
снимает приёмник тем. Что при этом перестаёт
|
||
проверяться, названо поимённо и идёт в границы покрытия.
|
||
2. **Вход.** `basics` идёт на верхней модели, но с узким входом: дифф и его
|
||
окрестности, без карты проекта. На `small` сужаются и остальные: `specs`
|
||
читает только дельта-спеку, `code` — только индекс конвенций.
|
||
3. **Потолок.** Он есть у каждого прохода с мнением и напечатан: `basics` — 2
|
||
находки на сверке и 4 на разборе; `code` — 3 технических и 2 конвенционных на
|
||
`small`, 4 конвенционных выше; `specs` — 3 на `small`; `architecture` — 3;
|
||
триаж — 7 в основном списке.
|
||
|
||
Раньше рычагов было заявлено два, и оба применялись к одному `basics`. Проход без
|
||
потолка выдаёт столько находок, сколько нашёл поверхностей, — а это ровно тот
|
||
механизм, из-за которого был снят проход независимой реализации: **счёт
|
||
определялся объёмом вывода**. Потолок ставится не ради краткости отчёта, а против
|
||
этого.
|
||
|
||
**Потолок обязан быть объявлен, когда он сработал.** Проход, срезавший находки
|
||
до потолка, говорит об этом строкой в своих границах покрытия: сколько осталось
|
||
за срезом и какого рода. Молчащий срез неотличим от «больше не нашлось» — это тот
|
||
же класс молчащего пропуска, что и непущенный проход.
|
||
|
||
## Метки
|
||
|
||
**Ступени нумерованы и наружу не выходят.** Прогон ревью один, и зовёт его
|
||
`av-dev:code-resolve` после того, как код написан; членение внутри прогона —
|
||
ступени, и знать их снаружи не нужно. Перечень осей процесса целиком —
|
||
[shared/axes.md](../../shared/axes.md).
|
||
|
||
**Классификация задачи выдаёт ровно одно значение — метку**: `small`, `medium`
|
||
или `large`. Это **единственный вход, по которому конвейер выбирает
|
||
исполнителей**: состав читается из неё, а не из класса задачи, не из её типа и не
|
||
из ощущения важности. Метку ставит `review-scope` при разметке задачи; все
|
||
проходы получают её в задании и обязаны напечатать в своих границах покрытия.
|
||
|
||
**Метка одна на всю задачу.** У изменения нет двух разных «глубин проверки»:
|
||
величина, из которой выводится состав, — пара «размер × сложность», посчитанная
|
||
один раз по готовому диффу.
|
||
|
||
**Метка не меняет список тем — она меняет их дом и глубину.** Все темы ядра
|
||
названы при любой метке; разница в том, против чего их смотрят (дом темы
|
||
или только инварианты) и как (чтением, рассуждением или запуском).
|
||
|
||
Ревью кода:
|
||
|
||
<!-- дом: тема-метка-глубина -->
|
||
|
||
| Тема | `small` | `medium` | `large` |
|
||
|---|---|---|---|
|
||
| `requirements` | `specs`, сверка | `specs`, разбор | `specs`, разбор |
|
||
| `autotests` | `autotests` | `autotests` | `autotests` |
|
||
| `conventions` | `code`, сверка | `code`, разбор | `code`, разбор |
|
||
| `architecture` | `code`, сверка по инвариантам | `basics`, разбор | `architecture`, разбор на широком входе |
|
||
| `security` | `code`, сверка по инвариантам | `basics`, разбор | `proof`, разбор |
|
||
| `operations` | `code`, сверка по инвариантам | `basics`, разбор | `proof`, разбор |
|
||
| тема проекта | `basics`, сверка | `basics`, разбор | `basics`, разбор |
|
||
|
||
<!-- /дом: тема-метка-глубина -->
|
||
|
||
Весь процесс с выбором исполнителей на каждом этапе — одной схемой. **Метка
|
||
считается один раз, в узле разметки, и дальше только читается:**
|
||
|
||
```mermaid
|
||
flowchart TD
|
||
propose["opsx:propose — change, дельта-спеки, tasks.md"]
|
||
checkpoint(["чекпоинт: объяснение человеку"])
|
||
apply["opsx:apply — код, гейт зелёный"]
|
||
scope["review-scope — разметка по диффу<br/>размер × сложность → МЕТКА"]
|
||
label{{"метка"}}
|
||
|
||
subgraph code["Ревью кода"]
|
||
cGate["autotests — гейт, источник графа"]
|
||
cS["specs — requirements"]
|
||
cC["code — conventions + техника"]
|
||
cInv["code, третья половина:<br/>security, operations, architecture<br/>против инвариантов CLAUDE.md"]
|
||
cB["basics — темы ядра + свои темы"]
|
||
cBown["basics — только свои темы проекта"]
|
||
cHeavy["proof (security + operations)<br/>· architecture"]
|
||
cT["triage — единственный сток"]
|
||
end
|
||
|
||
propose --> checkpoint --> apply --> scope --> label
|
||
|
||
label -->|любая метка| cGate
|
||
cGate -->|зелёный| cS
|
||
cGate -->|зелёный| cC
|
||
label -->|small| cInv
|
||
label -->|small, есть свои темы| cBown
|
||
label -->|medium| cB
|
||
label -->|large| cHeavy
|
||
label -->|large, есть свои темы| cBown
|
||
|
||
cS --> cT
|
||
cC --> cT
|
||
cInv --> cT
|
||
cB --> cT
|
||
cBown --> cT
|
||
cHeavy --> cT
|
||
```
|
||
|
||
Отсюда состав прогона:
|
||
|
||
| Метка | Когда | Ступени | Проходов | Доля задач |
|
||
|---|---|---|---|---|
|
||
| `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` идёт после
|
||
`apply`, до первой ступени. Раньше разметка стояла первой в каждом ревью кода и
|
||
повторялась при каждом перезапуске прогона.
|
||
|
||
**Глубины две, и они не про старательность, а про способ доказательства.**
|
||
**Сверка** — открыть дом темы, открыть дифф, сравнить. **Разбор** — построить
|
||
сценарий рассуждением, ничего не запуская.
|
||
|
||
**Третья глубина — доказательство** (прогнать, померить, построить путь) — в
|
||
цикле задачи не производится вовсе. Она требует машины и стоит часов, и потому
|
||
живёт в скилле `av-dev:code-deep-review`, который идёт по названной области и
|
||
время от времени. Проход, которому в плане назначили доказательство, получил план
|
||
не от конвейера задачи.
|
||
|
||
**Здесь диспетчер и кончается: метка названа — состав читается.** Само правило
|
||
выбора — две оси, «спорное решается вниз», максимум по поверхности, — а с ним
|
||
разбор того, чем именно `small` дешевле `medium` и почему доли служат проверкой
|
||
правила, живут в [references/review-levels.md](references/review-levels.md). Тот
|
||
файл открывают, когда метку **выбирают, оспаривают или калибруют**; его
|
||
единственный постоянный читатель — `review-scope`.
|
||
|
||
**Состав сверяется до коммита — по плану разметки задачи, а не по этой таблице.** План
|
||
и есть реестр: тема, дом, глубина, кто закрывает. Это единственная защита от
|
||
промаха, который уже случился: пропуск **не отличим от прохода без находок** (гейт
|
||
зелёный, спеки сошлись, отчёт выглядит полным), а заметить его мог бы только
|
||
триаж, который сам заполняется тем, что ему подали. Непущенное идёт строкой «не
|
||
запускался» с причиной, а не отсутствует. Цена молчащего пропуска измерена: семь
|
||
находок и отдельная задача на их дозакрытие.
|
||
|
||
## Порядок прогона — граф, а не очередь
|
||
|
||
Метка отвечает «какие темы и на какой глубине», порядок — «что кого ждёт».
|
||
Ступени остаются единицей **состава**, но порядок задают **не их номера**: между
|
||
ступенями 2–4 настоящих зависимостей нет — ни один проход не читает вывод другого,
|
||
— и очередь между ними была бы платой ни за что.
|
||
|
||
Рёбер два вида, и они разной природы. Путать их нельзя: первое про
|
||
**осмысленность** (без плана задание не определено, а на красном гейте проходу с
|
||
мнением не о чем судить), второе про **железо**.
|
||
|
||
| Ребро | Смысл | Между кем |
|
||
|---|---|---|
|
||
| **зависимость** | B не стартует, пока A не закончил, потому что без A задание B не определено | гейт → все проходы с мнением; все проходы → триаж |
|
||
| **конфликт за ресурс** | A и B не держат машину одновременно; кто из них первый — неважно, направления у ребра нет | проходы, помеченные «держит машину» |
|
||
|
||
**План разметки — вход графа, а не его узел.** Он готов до того, как прогон
|
||
начался: разметка идёт один раз на задачу, сразу после `apply`. Раньше она была
|
||
первым узлом каждого прогона, и ребро «разметка → все» стояло здесь; теперь этого
|
||
ребра нет, потому что нет и узла — перезапуск прогона разметку не повторяет.
|
||
|
||
```mermaid
|
||
flowchart TD
|
||
plan[/"план разметки задачи<br/>(готов до ревью кода)"/]
|
||
autotests["autotests<br/>(ступень 1, держит машину)"]
|
||
specs["specs"]
|
||
code["code"]
|
||
basics["basics<br/>(medium: темы ядра и свои;<br/>small, large: только свои темы проекта)"]
|
||
proof["proof<br/>(large: security + operations)"]
|
||
architecture["architecture<br/>(large)"]
|
||
triage["triage — единственный сток"]
|
||
|
||
plan -.->|задания по темам| autotests
|
||
autotests -->|зелёный| specs
|
||
autotests -->|зелёный| code
|
||
autotests -->|"зелёный, темы по плану"| basics
|
||
autotests -->|"зелёный, large"| proof
|
||
autotests -->|"зелёный, large"| architecture
|
||
specs --> triage
|
||
code --> triage
|
||
basics --> triage
|
||
proof --> triage
|
||
architecture --> triage
|
||
```
|
||
|
||
Читается граф так: **всё, у чего входящие рёбра закрыты, уходит одним
|
||
сообщением**. Источник графа — гейт: он один по построению и идёт первым. На
|
||
`medium` после зелёного гейта уходят разом `specs`, `code` и `basics`, и сразу
|
||
триаж. На `small` — `specs` и `code`, а `basics` только при своих темах проекта.
|
||
В `large` вместо тем `basics` уходят разом `proof` и `architecture` — ждать им
|
||
нечего, машину не держит ни один, — и триаж стартует, когда вернулся последний.
|
||
|
||
**Схема здесь старше прозы.** Она не иллюстрация к тексту, а сам алгоритм
|
||
планировщика; проза ниже объясняет рёбра и называет их цену. Разошлись — прав
|
||
граф, а расхождение чинится правкой текста.
|
||
|
||
**Ребро значит «A закончил раньше, чем B стартовал», и ничего больше.** В обычном
|
||
графе задач ребро тянет за собой данные — здесь нет, и это не деталь реализации.
|
||
Проход **не видит** находок других проходов, в каком бы порядке их ни запустили.
|
||
Вся ценность конвейера держится на разведённости: под всеми ролями одна модель с
|
||
одними априорными, и стоит показать ей чужой вывод — она согласится. Согласие
|
||
нескольких проходов и так не повышает `confidence` (см. «Честный предел»);
|
||
согласие **наведённое** ещё и маскируется под независимое подтверждение.
|
||
Единственный, кто получает чужие выводы, — триаж, и это его работа.
|
||
|
||
### Кто держит машину
|
||
|
||
Ресурс один и неделимый: **машина** — тесты, поднятый сервис, СУБД, порты, диск.
|
||
Проходы, заявившие его, сериализуются между собой при любой метке и на любой
|
||
ступени; порядок внутри цепочки произволен.
|
||
|
||
| Проход | Держит машину | Почему |
|
||
|---|---|---|
|
||
| `autotests` | да | запускает инструменты проекта — но он источник графа и один по построению |
|
||
| `triage` | да | проверяет оракул `major` запуском — но он сток и тоже один |
|
||
| `specs`, `code`, `basics`, `proof`, `architecture`, `rubric`, `scope` | нет | читают и рассуждают, ничего не исполняют |
|
||
|
||
**В обычном прогоне цепочки за машину нет.** Оба прохода, что её держали —
|
||
`adversary` и `ops`, — переехали в скилл `av-dev:code-deep-review`; там правило
|
||
действует целиком, и дом его остаётся здесь. Оставшиеся двое машину держат, но
|
||
каждый один по построению: один источник графа, другой сток.
|
||
|
||
**Правило про ресурс, а не про имена.** Раньше здесь стояло именованное
|
||
исключение «`adversary` и `ops`»; оно рассыпается, как только проход начнёт
|
||
мерить или в проекте появится свой. Два прохода на одной машине соревнуются за
|
||
диск, CPU и за саму СУБД и выдают числа, которые не воспроизведутся, — а число,
|
||
снятое под конкурентную нагрузку, это находка с испорченным оракулом. Её
|
||
опровержение стоит дороже всего выигрыша от параллельности, и она хуже
|
||
отсутствующей: выглядит доказанной. Правило выведено из находок, целиком
|
||
державшихся на таких замерах; у каждого проекта они свои и лежат в журнале
|
||
`docs/review.md`.
|
||
|
||
Проект вправе пометить «держит машину» и другой проход — в `docs/review.md`,
|
||
разделе настройки конвейера. Снимать пометку с перечисленных нельзя.
|
||
|
||
### Находка «переделать форму» — прогон повторяется целиком
|
||
|
||
**Барьера стоимости в конвейере нет, и раннего выхода тоже.** Барьер существовал
|
||
ради независимой реализации — единственного прохода, чей счёт определялся объёмом
|
||
вывода, — и ушёл вместе с ней. Граф при любой метке плоский, от гейта до триажа:
|
||
защищать за барьером нечего, `architecture` дёшев по выходу (потолок 3 находки), а
|
||
сериализация не бесплатна — она разводит по очереди то, что могло идти разом.
|
||
|
||
Находка «**форму изменения** надо переделывать» ловится триажем, как и любая
|
||
другая; дальше правило одно. Находка чинится, и ревью кода запускается **заново с
|
||
гейта**, а не «доезжает» остатком по коду, которого через час не станет.
|
||
|
||
**Разметка при этом не повторяется — кроме одного случая.** План описывает
|
||
задачу, а не дифф, и переделка формы внутри той же задачи его не отменяет.
|
||
Повторить разметку надо тогда, когда правка изменила **дельта-спеки**: план
|
||
выведен из них, и план, выведенный из отменённых требований, будет уверенно
|
||
называть не те темы.
|
||
Если прогон всё же остановлен на полпути, незапущенные проходы идут в границы
|
||
покрытия строкой «не запускался: прогон остановлен на <проход> из-за <находка>»,
|
||
поимённо, а **триаж на половине прогона не запускается**: его отчёт выглядит
|
||
полным, потому что агрегирует всё, что ему подали, — это тот же молчащий пропуск,
|
||
что и в разделе «Метки».
|
||
|
||
Находка, которая чинится в пределах существующей формы (`Действие: инлайн`),
|
||
прогон не останавливает: дешевле дособрать все находки и починить пачкой, чем
|
||
гонять конвейер дважды.
|
||
|
||
### Линеаризация — когда графа мало
|
||
|
||
Граф можно вытянуть в одну цепочку. Это отступление, и оно называется в отчёте:
|
||
|
||
1. **сказал оператор** — «гони линейно». Набора называть не надо: линейный прогон
|
||
ничего не портит, он только дольше, и домысливать тут нечего;
|
||
2. **машина занята, и знает об этом вызывающий.** Рядом идёт другая задача,
|
||
поднят сервис, гоняется дорогая проверка проекта. Сам конвейер занятости
|
||
машины не видит — её обязан назвать тот, кто запускает;
|
||
3. **разбор самого конвейера** — когда выясняется, почему проход чего-то не
|
||
нашёл, порядок и изоляция важнее скорости.
|
||
|
||
Обратное отступление — **слить цепочку ресурса** (пустить меряющие проходы
|
||
разом) — бывает только по прямому слову оператора, и тогда в границы покрытия
|
||
идёт строка: какие проходы шли одновременно и что замеры этого прогона как
|
||
оракул слабее.
|
||
|
||
Режим объявляется в отчёте наравне с меткой: **`по графу`** — одним словом,
|
||
**`линейно`** — с причиной (какой именно из трёх).
|
||
|
||
## Разметка задачи — один раз, после кода
|
||
|
||
Агент `review-scope`. Идёт **после `apply`, до первой ступени**, и один: до его
|
||
плана неизвестно ни что проверять, ни на какой метке, ни сколько проходов звать.
|
||
|
||
**Это не ступень прогона, и в счёт проходов метки она не входит.** Она платится
|
||
один раз на задачу: перезапуск прогона по находке «переделать форму» её не
|
||
повторяет, потому что план описывает задачу, а не дифф.
|
||
|
||
**Что он читает.** `docs/` на уровне имён и заголовков, `CLAUDE.md` и
|
||
`AGENTS.md`, `openspec/specs/`, `docs/review.*` — раздел настройки. Плюс **корпус
|
||
оценки**, и у двух осей он разный.
|
||
|
||
| Источник | Размер | Сложность |
|
||
|---|---|---|
|
||
| **дифф** | **сколько мест тронуто на самом деле** | — |
|
||
| запись задачи, «Затрагивает» | перечень границ, названный до работы | узлы названы поимённо — знакомое |
|
||
| `proposal.md` | что делаем и зачем | вводит ли новое понятие |
|
||
| `design.md` | какие узлы в решении | **разбирались ли альтернативы** |
|
||
| `tasks.md` | число шагов и их разнородность | шаг «разобраться», «выяснить» |
|
||
| дельта-спеки | сколько capability и требований | `ADDED` целой capability против `MODIFIED` |
|
||
|
||
**Размер он меряет по диффу, и это главный источник.** Написанное о задаче до
|
||
работы описывает заказанное, а не сделанное: перечень границ мог оказаться
|
||
неполным, а `tasks.md` — обещать шесть шагов там, где хватило двух. Дифф этого не
|
||
обещает, он это показывает. Прочие источники размер **уточняют**: они называют
|
||
то, чего в диффе не видно, — например, что тронутые места лежат в разных слоях.
|
||
|
||
**Сложность дифф не отвечает вовсе.** Признак незнакомого — нельзя было назвать
|
||
тронутые узлы до работы, — проверяется сверкой перечня границ задачи с тем, что
|
||
реально тронуто: разошлись поимённо, значит формы решения не знали. Оттого запись
|
||
задачи и `design.md` остаются в корпусе и после кода.
|
||
|
||
**Расхождение источников по объёму разрешается в пользу большего** — не «спорное
|
||
вниз»: там ничья при равных данных, здесь один источник просто видел больше.
|
||
Само расхождение при этом идёт доводом за `незнакомое`: если о задаче написано
|
||
так, что источники не сходятся в объёме, формы решения не знали.
|
||
|
||
Возвращает **план задачи**: размер и сложность с обоснованием, метка как
|
||
максимум по ним, список тем с домами и глубинами, разнесение документов по трём
|
||
категориям и строку про найденные директивы. План уезжает в отчёт прогона целиком
|
||
и служит границами покрытия.
|
||
|
||
**Он не судит по существу** — ни одной находки об изменении. Его ошибка это
|
||
пропущенная тема или не та метка, и обе видны: разнесение документов сверяется
|
||
с `ls docs/` за секунду, а заниженную метку ловит `code` своим сигналом — на
|
||
любой метке, потому что он идёт всегда.
|
||
|
||
Право у разметчика симметричное: **поднять и понизить метку он может
|
||
одинаково**, но обоснование обязательно в обоих случаях и всегда — строкой, какой
|
||
признак по какой оси сработал и по какому факту.
|
||
|
||
**План живёт в контексте прогона задачи и на диск не пишется.** Файл-план был бы
|
||
четвёртым артефактом рядом с `proposal.md`, `tasks.md` и `design.md`, жил бы
|
||
дольше задачи и расходился бы с ней молча. Прервали прогон задачи — разметка
|
||
повторяется; это самый дешёвый проход конвейера, и платить за его вечность
|
||
дороже, чем перезапустить.
|
||
|
||
**Внутри прогона метка не пересматривается.** Разметчик видел дифф целиком, и
|
||
второй запуск на том же дереве вернул бы то же самое; правки по находкам инлайна
|
||
дифф растят, а задачу — нет. Ошибка выбора ловится **журналом дефектов** в
|
||
`docs/review.md`, постфактум, и это единственный сигнал — ровно как и для всякой
|
||
другой ошибки метки.
|
||
|
||
## Прогон без change — сценарий обслуживания
|
||
|
||
Третий вызывающий конвейера — сценарий обслуживания скилла `av-dev:code-resolve`
|
||
(тулчейн и сборка, зависимости, гит-хуки, перенос, чистка). Он приходит **без
|
||
change**: у работы, не меняющей поведения, дельта-спек нет по построению.
|
||
|
||
**Копия.** Дом оси — `shared/axes.md` в репозитории плагина: режим делят конвейер,
|
||
сценарий обслуживания и два устава, и ни один из них им не владеет. Правится дом,
|
||
а не этот файл.
|
||
|
||
<!-- копия: режим-прогона из av-dev/shared/axes.md -->
|
||
|
||
**Прогон ревью идёт в одном из двух режимов, и режим — не глубина.**
|
||
|
||
- **С меткой** — обычный прогон по change: разметку сделал `review-scope`, состав
|
||
прогона выведен из метки.
|
||
- **Без метки** — размечать нечего, план фиксирован и назван вызывающим,
|
||
разметчик не запускается вовсе. Так идут двое: сценарий обслуживания, у
|
||
которого нет change, и скилл `av-dev:code-deep-review`, у которого нет задачи —
|
||
он смотрит названную область кода.
|
||
|
||
**Без метки — не то же самое, что `small`.** `small` — это суждение о размере и
|
||
сложности, снятое с изменения; отсутствие метки — утверждение, что снимать её
|
||
не с чего. Проход, подставивший себе `small` там, где метки нет, вывел бы
|
||
глубину из ничего.
|
||
|
||
**Режим правит не только состав, но и саму возможность запуска.** Проход, у
|
||
которого запуск задан меткой, без метки не имеет ответа на вопрос «запускаться
|
||
ли» — и ответ ему даёт план сценария, а не умолчание.
|
||
|
||
<!-- /копия: режим-прогона -->
|
||
|
||
**Метка на таком прогоне не назначается, и разметчик не зовётся.** Обе его оси
|
||
здесь не определены: размер он выводит из `proposal.md`, `design.md`, `tasks.md`
|
||
и дельта-спек, а сложность — из формы решения, которая у обслуживания либо
|
||
известна заранее, либо задача туда не попала (незнакомое уходит в разведку).
|
||
Разметчик без своего корпуса вернул бы величину, выведенную из ничего, — и это
|
||
хуже отсутствующей метки, потому что выглядит измеренным.
|
||
|
||
**План приходит вызовом и фиксирован сценарием**, а не выводится здесь. **Он же
|
||
называет глубину и вход каждого прохода** — их обычный источник метка, и без неё
|
||
проходы взяли бы их наугад:
|
||
|
||
<!-- копия: план-без-метки из av-dev/skills/code-resolve/references/maintain.md -->
|
||
|
||
| Тема | Дом | Кто закрывает | Глубина и вход | Когда |
|
||
| --- | --- | --- | --- | --- |
|
||
| `autotests` | `CLAUDE.md`, семантика гейта | `review-autotests` | как обычно: гейт запускается целиком | всегда |
|
||
| `operations` | `architecture.*`, раздел эксплуатации | `review-basics` | **сверка**: дом темы против диффа, потолок 2 | всегда |
|
||
| `conventions` + технический разбор | `conventions.*` | `review-code` | вход `small`: только индекс конвенций; потолки 3 технических и 2 конвенционных; **третья половина включена** — сверка с инвариантами `CLAUDE.md`, потолок 1 | дифф трогает код, а не только оснастку |
|
||
|
||
<!-- /копия: план-без-метки -->
|
||
|
||
Триаж обязателен и здесь — он единственный сток и единственный, кто сверяет план
|
||
с исходом; на его вход подаётся этот план вместо плана разметки. Тема
|
||
`requirements` в плане отсутствует за отсутствием предмета; `security` и
|
||
`architecture` закрыты только сверкой с записанными инвариантами внутри `code` —
|
||
третья половина этого прохода включается здесь по той же причине, что и при
|
||
метке `small`. Все три обязаны быть названы в границах покрытия, а **сигнал о
|
||
заниженной метке на таком прогоне не работает**: поднимать нечего.
|
||
|
||
Дом плана — сценарий, а не этот скилл: `av-dev:code-resolve`,
|
||
`references/maintain.md`, раздел «Ревью — план фиксирован сценарием».
|
||
|
||
**Правило гейта на таком прогоне работает жёстче обычного.** Правка, которая
|
||
трогает сам гейт, проверяется гейтом же — инструмент проверяет себя, — поэтому
|
||
сверяется не только цвет, но и состав шагов. Что считается составом, объявляет
|
||
проект семантикой гейта в `CLAUDE.md`; не объявил — это строка границ покрытия, а
|
||
не догадка прохода.
|
||
|
||
## Ступень 1 — Автотесты (обязательна при любой метке)
|
||
|
||
Агент `review-autotests`, тема `autotests`. Гонит команду гейта из семантики
|
||
гейта в `CLAUDE.md` — либо засчитывает прогон, сделанный до ревью, — и
|
||
интерпретирует вывод.
|
||
|
||
**Тема и проход названы одинаково намеренно, а «гейт» осталось именем команды.**
|
||
Раньше тема звалась `autotests`, а проход — `gate`: одна сущность под двумя
|
||
именами, и вопрос проекта, адресованный одному имени, к другому не приезжал.
|
||
Слово «гейт» теперь значит ровно одно — барьер, который проект запускает; тема
|
||
шире него ровно на «чего в гейте намеренно нет».
|
||
|
||
**Гейт, прогнанный до ревью, второй раз не гоняется.** Задача приходит на ревью
|
||
с зелёным гейтом: сценарий решения доводит его до зелёного шагом `opsx:apply`,
|
||
сценарий обслуживания — своим шагом гейта. Повтор на неизменившемся дереве
|
||
вернёт тот же вывод, а стоит он минут — то есть платит ими ни за что.
|
||
|
||
**Признак один и проверяемый — отпечаток рабочего дерева.** Его снимают дважды:
|
||
тот, кто прогнал гейт, сразу после прогона, и проход перед началом работы.
|
||
|
||
<!-- дом: отпечаток-дерева -->
|
||
|
||
```sh
|
||
{ git rev-parse HEAD; git status --porcelain -uall; git diff HEAD;
|
||
git ls-files -o --exclude-standard -z | xargs -0 -r git hash-object; } | sha1sum
|
||
```
|
||
|
||
<!-- /дом: отпечаток-дерева -->
|
||
|
||
Сводку прошлого прогона, путь к логам шагов и отпечаток проход получает
|
||
**заданием** — их передаёт вызывающий скилл. Отпечатки совпали — проход читает
|
||
готовую сводку и логи, команду не запускает. Разошлись, отпечатка в задании нет,
|
||
логи недоступны — проход гонит гейт сам и ни у кого не спрашивает.
|
||
|
||
**Отказ здесь безопасен по построению.** Лишний прогон стоит минут, а
|
||
засчитанный чужой — красноты, которой никто не увидел. Временный каталог проекта
|
||
из отпечатка выпадает сам: `--exclude-standard` отбрасывает игнорируемое, а логи
|
||
шагов гейт пишет именно туда. У проекта, держащего временный каталог под git,
|
||
отпечатки не совпадут никогда — и он получит честный прогон вместо тихого
|
||
засчитывания.
|
||
|
||
**Переиспользуется команда, а не проход.** Тема `autotests` закрывается целиком:
|
||
логи проход читает сам, находки об отсутствующей верификации выдаёт как обычно.
|
||
Переиспользование он объявляет строкой сводки и строкой границ покрытия — чем
|
||
гейт прогнан, когда и на каком отпечатке. Молчащее переиспользование неотличимо
|
||
от собственного прогона, а разница между ними в том, кто видел вывод своими
|
||
глазами.
|
||
|
||
**Пока гейт красный — проходы с мнением не запускаются.** Оркестратор чинит и
|
||
перезапускает гейт. Исключение одно: отказ, унаследованный от базовой ветки
|
||
(гейт проверяет это прогоном на базе) — тогда он фиксируется находкой и не
|
||
блокирует.
|
||
|
||
Гейт возвращает не только «зелено/красно», но и находки класса **отсутствующая
|
||
верификация**: изменённые строки без покрытия, конкурентность без теста с
|
||
параллельным доступом, флаки-тест (не ниже `major`), недоступный инструмент.
|
||
|
||
Шаги выбираются по изменённым файлам: правка документации не гоняет тесты,
|
||
линтеры и детектор гонок. Пропуск при этом не молчит — он виден в сводке с
|
||
причиной и уезжает в границы покрытия, как и любой другой `SKIP`.
|
||
|
||
Шаги, которые красят гейт безусловно, перечислены в `CLAUDE.md` с причиной. Проходу
|
||
запрещено списывать такой отказ в мелочь.
|
||
|
||
## Ступень 2 — Сверка (обязательна при любой метке)
|
||
|
||
Два прохода, оба против **записанного** критерия. Машину не держат ни один, ребра
|
||
между ними нет — уходят одним сообщением сразу после зелёного гейта, вместе со
|
||
ступенью 3 или 4 — той, которую назначила метка.
|
||
|
||
- `review-specs` закрывает тему `requirements`. Критерий взят из **дельта-спек
|
||
предлагаемого изменения**, а не из proposal, сообщения коммита или описания
|
||
задачи. Сверка двунаправленная; направление `code → spec` важнее.
|
||
- `review-code` закрывает тему `conventions` **и делает технический разбор
|
||
кода** — это две его половины. Первая ищет дефект, который сработает сам, на
|
||
обычном входе: необработанная ветка отказа, пустое значение, граница диапазона,
|
||
перепутанный операнд, неосвобождённый ресурс, неверно применённый интерфейс
|
||
библиотеки. Вторая сверяет с конвенциями проекта, беря только ту их часть,
|
||
которая **не выражается правилом**: механизируемое уже проверила ступень 1.
|
||
**На `small` у него есть третья, узкая обязанность** — сверить дифф с
|
||
записанными инвариантами `CLAUDE.md` по темам `security`, `operations` и
|
||
`architecture`, потому что с этой меткой `basics` не идёт. Потолок 1 находка
|
||
на все три темы разом: это не замена приёмнику тем, а объявленный минимум.
|
||
|
||
**Вход обеих половин зависит от метки, и это второй рычаг дешевизны `small`.**
|
||
На `small` `specs` читает только дельта-спеку, `code` — только **индекс**
|
||
конвенций: перечень родов и пометки, что уже механизировано. На `medium` и
|
||
выше оба читают дома целиком. Разница честная: узкий вход ловит нарушение
|
||
записанного рода и пропускает то, ради чего конвенцию писали абзацем.
|
||
|
||
**Потолки у обоих половин раздельные, и это не бюрократия.** Конвенционных
|
||
находок больше по построению — родов навигации в разы больше, чем классов
|
||
технического дефекта, — и в общем списке они вытесняют техническую половину, чей
|
||
пропуск дороже. Раздельный потолок делает вытеснение невозможным: на `small` это
|
||
3 технических и 2 конвенционных, на `medium` и выше потолка нет у первой
|
||
половины и 4 у второй.
|
||
|
||
**Технический разбор — не тема, а обязанность прохода, и он единственный.**
|
||
Остальные читают код как материал для своей оптики: `specs` — против требований,
|
||
`basics` — против отказов окружения, `architecture` — против устройства. «Здесь
|
||
ошибка в логике» не говорит больше никто, и до недавнего времени не говорил
|
||
никто вовсе: `code` был проходом только по конвенциям, а дефект ловился разве что
|
||
случайно. Это была самая крупная дыра конвейера, и стоила она дороже любой
|
||
недосмотренной темы.
|
||
|
||
Recall темы `conventions` равен длине конвенций проекта — это предел любой
|
||
сверки, и ровно ради него существуют ступени 3 и 4.
|
||
|
||
**Оба прохода на верхней модели, и по одной причине — цене пропуска.** У `specs`
|
||
это направление `code → spec`: надо заметить **отсутствие** — тихий фолбэк,
|
||
самодеятельный дефолт, проглоченную ошибку. У `code` это пропущенный дефект,
|
||
который поедет в прод. Ни то ни другое не оставляет следа ни в отчёте, ни в
|
||
границах покрытия; прочие проходы с мнением держат `opus` из-за цены **ложных**
|
||
находок, эти двое — из-за цены пропущенных.
|
||
|
||
## Ступень 3 — Темы (`medium` целиком; `small` и `large` — только свои темы проекта)
|
||
|
||
Агент `review-basics`. Один проход, машину не держит, ничего не запускает и не
|
||
меряет — уходит одним сообщением вместе со ступенью 2, сразу после зелёного гейта.
|
||
|
||
**Он не самостоятельная оптика, а держатель тем, у которых с этой меткой нет
|
||
своего проходчика.** На `medium` это `security`, `operations` и `architecture`:
|
||
их именные проходы живут в `large`, а на `small` эти темы смотрятся только против
|
||
инвариантов внутри `code`. При любой метке, включая `small` и `large`, он же —
|
||
**приёмник проектных тем**: именных проходов конечное число, а тем столько,
|
||
сколько заведёт проект.
|
||
|
||
**Он запускается только тогда, когда ему есть что принимать, и это правило одно
|
||
на все три метки.** На `medium` темы у него есть всегда — три ядра плюс свои.
|
||
На `small` и `large` — только свои темы проекта; нет таких, и план говорит строкой:
|
||
на `large` «все темы разобраны именными проходами», на `small` «темы ядра
|
||
`security`, `operations`, `architecture` закрыты сверкой по инвариантам внутри
|
||
`code`». Это единственное место, где состав не выводится из одной лишь метки, и
|
||
потому оно называется в плане явно.
|
||
|
||
Глубина приходит из плана: **сверка** (открыть дом темы, открыть дифф, сравнить;
|
||
потолок 2 находки) или **разбор** (построить сценарий рассуждением; потолок 4).
|
||
Обе глубины действуют и на темах ядра, и на проектных: раньше проектная тема
|
||
разбиралась «так же» независимо от метки, и различие меток на ней не
|
||
работало вовсе. Чего он не делает ни на какой глубине — замеров, эксперимента
|
||
против драйвера, построенного пути, карты проекта, границы домена. Всё это стоит
|
||
машины или входа шире диффа, то есть ровно того, ради чего существует `large`.
|
||
|
||
**Он покрывает миграцию и публичный контракт на `medium`.** Это не побочный
|
||
эффект, а условие, при котором миграция схемы вообще может не поднимать метка:
|
||
её шаг гоняет `autotests`, спеку сверяет `specs`, а вопросы «обратима ли» и «что с
|
||
записями новой версии после отката» задаёт здесь `basics`, темой `operations`.
|
||
**И ровно поэтому отрицательный тест `small` стал жёстче, а не мягче:** на `small`
|
||
этого прохода нет, миграция и публичный контракт остаются без единственного
|
||
взгляда на ось времени — значит изменение, которое не откатывается обратной
|
||
правкой, на `small` не идёт вовсе, каким бы малым оно ни было.
|
||
|
||
## Ступень 4 — Риск и устройство (только `large`)
|
||
|
||
Два прохода, оба уходят сразу после зелёного гейта, в одном ряду со ступенью 2.
|
||
Машину не держит ни один, ждать им нечего:
|
||
|
||
- `review-proof` — **две темы разом**, `security` и `operations`. Набросок пути
|
||
(вход, преобразование, куда легло) и ось времени (миграция и откат, рост,
|
||
удержание, чужая деградация). Строит сценарий рассуждением и ничего не
|
||
запускает; потолки раздельные — 2 находки на тему;
|
||
- `review-architecture`, тема `architecture` — концептуальная целостность на
|
||
входе шире диффа.
|
||
|
||
**Доказательства на этой ступени больше нет, и это решение по цене.** Прежде обе
|
||
темы закрывала пара тяжёлых проходов: `review-adversary` строил путь и **прогонял**
|
||
падающий тест, `review-ops` снимал числа замером. Оба держали машину, шли
|
||
цепочкой и стоили часов на каждой задаче, где запускались.
|
||
|
||
Пара никуда не делась — её зовёт скилл **`av-dev:code-deep-review`**, который
|
||
идёт не на задаче, а по названной области и время от времени. Замер, ради
|
||
которого её и держали, остался: враждебный проход дал пять из семи выживших
|
||
находок дозапуска на пяти задачах подряд, эксплуатационный — единственный, кто
|
||
нашёл, что откат бинаря поверх новой схемы стартует молча. Ценность этой пары
|
||
оплачивалась **на каждой** задаче, а получалась на немногих; теперь она
|
||
оплачивается тогда, когда её решают получить.
|
||
|
||
**`review-proof` копит вход глубокому прогону.** Всё, что доказывается только
|
||
запуском, он не выдаёт находкой и не выбрасывает: строка в границах покрытия
|
||
называет тему, место и запуск, которым это проверяется. Строка — единственный
|
||
вход `av-dev:code-deep-review`, заводящийся по ходу обычной работы.
|
||
|
||
**Чем платит цикл, названо прямо.** `critical` эта ступень больше не присваивает:
|
||
его оракул добывается запуском. Дефект, который виден только под нагрузкой —
|
||
гонка, деградация, исчерпание ресурса, — в цикле задачи не ловится ничем; это
|
||
идёт строкой в границы покрытия каждого прогона и разобрано в «Честном пределе».
|
||
|
||
Дома тем приходят из плана разметки задачи: `security` и `operations` —
|
||
`review-proof`, `architecture` (устройство, граница домена) — архитектурному. Что
|
||
с чем сшивать и почему — [project-facts.md](references/project-facts.md), раздел
|
||
«Сшивать обязаны проходы». Без домов ступень вырождается в общие места.
|
||
|
||
**Числа и решения проекта эта ступень не читает.** `research.*` и `adr.*` —
|
||
процессные документы, и прогон их не открывает. Для `review-proof` это значит,
|
||
что чужое число ему не оракул: он его не снимал, а свои он не снимает вовсе. Для
|
||
архитектурного — что граница домена берётся из `passport.*`, а не из истории
|
||
решений. Обе потери названы в «Честном пределе».
|
||
|
||
**Условие ступени и есть условие метки `large`:** изменение крупное **или**
|
||
незнакомое — любая из двух осей. Разведены они не для красоты: у архитектурного
|
||
прохода работа появляется от **размера** (трогается несколько слоёв разом или в
|
||
проекте становится больше сущностей, чем было), у меряющей пары — от
|
||
**сложности** (форму решения нащупывали по ходу, и потому неизвестно, где она
|
||
протекает). На малом и знакомом вопрос «не появился ли второй способ» отвечается
|
||
«нет» до запуска, а построенный путь строить негде.
|
||
|
||
`review-architecture` получает **вход шире диффа**: дерево пакетов с
|
||
назначением, граф внутренних зависимостей, инвентарь существующих концепций.
|
||
Команду, которая это готовит, даёт раздел команд `CLAUDE.md`; нет команды —
|
||
проход собирает карту сам и говорит об этом в границах покрытия.
|
||
|
||
Главный вопрос — концептуальная целостность и **второй способ** делать то, что
|
||
уже делается. Он же и оправдывает проход: на задаче про пересборку архитектурный
|
||
проход нашёл, что новый код был **вторым проигрывателем журнала** со своим
|
||
порядком. Второй обязательный вопрос — **что опытный человек отсюда удалил бы**:
|
||
слой с единственной реализацией, интерфейс ради мока, незапрошенная
|
||
конфигурируемость, подстраховка поверх подстраховки. Потолок — 3 находки плюс
|
||
секция «дешевле переделать до мерджа».
|
||
|
||
## Ступень 5 — Triage (обязательна)
|
||
|
||
Агент `review-triage`. **Единственный сток графа и единственный, кто агрегирует.**
|
||
Входящие рёбра — все запущенные проходы: пока хоть один не вернул отчёт, триаж не
|
||
стартует. Получает сырые выводы всех проходов, `git diff`, режим и **план
|
||
разметки задачи**; возвращает финальный отчёт.
|
||
|
||
**На прогоне без change его место занимает план сценария** — см. «Прогон без
|
||
change»: сверять исход с планом триаж обязан и там, а другого плана в том прогоне
|
||
не существует.
|
||
|
||
**План на входе у триажа — не формальность, а сверка.** Он единственный, кто
|
||
видит и то, что размечено, и то, что пришло: «тем размечено шесть, отчёты
|
||
покрывают пять» — находка о самом прогоне, и заметить её больше некому. Раньше он
|
||
получал список запущенных проходов и потому мог сверить только состав; теперь
|
||
сверяет **темы**, а тема, оставшаяся без отчёта, — это то, чего список проходов
|
||
никогда не показывал.
|
||
|
||
Отсюда же правило, которое иначе выглядит придиркой: **триаж на неполном графе не
|
||
запускается**. Прогон, остановленный на полпути находкой «переделать форму», до
|
||
стока не доезжает — его отчёт агрегировал бы половину и выглядел бы полным.
|
||
|
||
Без триажа проходы дают порядка сорока замечаний при единицах существенных.
|
||
Потребитель здесь — оркестратор, который **молча реализует** всё, что прочитал:
|
||
цена нетриажированного отчёта — не потерянное время человека, а разросшийся от
|
||
вкусовщины код.
|
||
|
||
Порядок: дедупликация по причине → оракул для всего `critical`/`major` →
|
||
понижение неподтверждённого до гипотезы → отсев вкусовщины → ранжирование по
|
||
ущербу × вероятности → потолок 7 пунктов в основном списке.
|
||
|
||
## Контракт находок
|
||
|
||
Единый для всех проходов — [references/finding-contract.md](references/finding-contract.md).
|
||
Коротко: заголовок через **последствие**, обязательные поля `Файл`, `Severity`,
|
||
`Confidence`, `Оракул`, `Последствие`, `Предложение`, `Найдено проходом`.
|
||
`critical` без оракула или построенного пути не существует. Находка без поля
|
||
«Последствие» не выводится вовсе.
|
||
|
||
Каждый проход завершает вывод блоком `## Coverage of this pass`.
|
||
|
||
## Что происходит с находками дальше
|
||
|
||
- Оркестратор чинит помеченное `Действие: инлайн` и **не логирует мелочь**.
|
||
- `Действие: развилка` — вопросом с вариантами и ценой каждого туда, где проект
|
||
держит вопросы (это знает вызвавший скилл, а не конвейер ревью). Оркестратор не
|
||
останавливается: он урезает изменение до остатка и доводит его.
|
||
- Находка не для этого мерджа, но реальная (отложенный `major`, развилка,
|
||
решённая «потом»), — не теряется, но **и не заводится здесь**. Конвейер отдаёт
|
||
её **списком урожая** в отчёте: формулировка, оракул, откуда взялась (какой проход,
|
||
какой change). Заведение задач принадлежит `av-dev:task-track` — зови его со
|
||
списком урожая, у него на этот вход отдельный сценарий «задачи из ревью и
|
||
аудита»: свой формат, кластеризация по причине, дедуп против беклога и
|
||
кладбища. Каталога задач в проекте нет — урожай остаётся списком в отчёте, и
|
||
это говорится строкой доклада: задачи из него не заведёт никто. Мелочь класса `nit`
|
||
идёт в урожай одной пачкой, а не записью на находку.
|
||
- `Promote candidates` — по процедуре [references/promote.md](references/promote.md):
|
||
находка → конвенция → правило линтера → **удаление формулировки из конвенций**.
|
||
Третий шаг обязателен.
|
||
- Дефект, проскочивший ревью и всплывший позже, идёт в журнал проекта
|
||
([references/review-journal.md](references/review-journal.md)) — сразу, не
|
||
ретроспективно: теряется именно то, почему дефект не поймали.
|
||
- **Отчёт триажа сохраняется вместе с изменением** — `openspec/changes/<id>/review/`.
|
||
Он единственное, по чему потом видно, что было найдено и что из этого не
|
||
заведено: нулевой урожай при непустом отчёте виден сразу.
|
||
**Вместе с изменением он и переезжает:** после `opsx:archive` его адрес —
|
||
`openspec/changes/archive/<id>/review/`. Кто ищет отчёт после архивации
|
||
(приёмщик на груминге `av-dev:task-groom`, разбор дефекта), смотрит **оба**
|
||
пути; «отчёта нет» объявляется, только когда пуст и архивный, иначе самый
|
||
дорогой сценарий «состав ревью неизвестен, гоняем заново» срабатывает на
|
||
каждой доведённой задаче.
|
||
|
||
## Честный предел
|
||
|
||
Модель воспроизводит медиану публичного кода, смещённую к популярному и
|
||
туториальному: отсюда тяга к интерфейсам ради интерфейсов, лишним мокам и
|
||
конфигурируемости, которую никто не просил. **«Идиоматично» и «распространено» —
|
||
разные вещи**; проходы обязаны различать их и опираться на поимённое положение
|
||
руководства, а не на ощущение частотности.
|
||
|
||
Согласие нескольких проходов — **не подтверждение**: это один источник,
|
||
высказавшийся несколько раз. Совпадение повышает приоритет, но не `confidence`.
|
||
|
||
Что недоступно **этому** проекту принципиально — перечисляет «Недоступно
|
||
проверке» в `docs/review.*`, по темам, и оба его подраздела целиком уезжают в
|
||
границы покрытия. **Тема, у которой нет дома, — тоже граница покрытия**, и она
|
||
объявляется планом на каждом прогоне, а не разово.
|
||
Независимо от проекта недоступно:
|
||
|
||
- поведение внешних систем в их будущих версиях;
|
||
- реальный профиль нагрузки и то, что на самом деле лежит в данных, — **сверх
|
||
того, что проход снял замером сам, на этом прогоне**;
|
||
- завязка внешних потребителей на текущую форму ответа;
|
||
- суждение «этой функциональности не должно существовать».
|
||
|
||
Отдельно и честно: **поимённая сверка с положениями руководств по стилю языка не
|
||
задаётся ни одним проходом.** Проход про идиоматичность упразднён, его способные
|
||
части переселены (эксперимент против поведения библиотеки и драйвера — в `ops`,
|
||
вопрос 8, а он теперь в `av-dev:code-deep-review`; «не изобретаем ли то, что уже
|
||
есть в библиотеке» — в `architecture`, вопрос 1), но различение «идиоматично против распространено» теперь не спрашивает
|
||
никто. Класс обратимый — портит форму кода, не данные, — и его надо признавать в
|
||
границах покрытия, а не считать проверенным.
|
||
|
||
**На `small` и `medium` ничего не проверяется запуском сверх гейта.** Это самая
|
||
крупная граница покрытия конвейера, и она обязана идти строкой в каждом таком
|
||
прогоне — поимённо, а не общим «метка ниже». Формулировка «не запускается
|
||
ничего» была бы короче и была бы ложью: гейт запускает инструменты проекта, а
|
||
триаж проверяет оракул `critical`/`major` запуском — оба идут при любой метке.
|
||
Не проверяется **проходом с мнением**: построенный путь атаки (его надо
|
||
прогнать), поведение библиотеки и драйвера в вырожденном случае (достаётся только
|
||
экспериментом), любое число — время удержания блокировки, пик кучи, темп роста
|
||
журнала, стоимость на годовой истории. `basics` задаёт часть тех же вопросов
|
||
**чтением**, и его ответы поэтому слабее: он формулирует условиями, оракула не
|
||
приносит и выше гипотезы находку не поднимает — кроме той, что опирается на
|
||
инвариант `CLAUDE.md`.
|
||
|
||
**На `small` три темы ядра смотрятся только против записанных инвариантов.**
|
||
Отдельная строка, и она обязательна на каждом прогоне `small`: `security`,
|
||
`operations` и `architecture` закрывает не приёмник тем, а `code` сверкой с
|
||
`CLAUDE.md`, потолком 1 находка на все три. Свойства, которого нет в инвариантах,
|
||
с этой меткой не спросит никто. Это не «глубина ниже» — это **другой дом
|
||
темы**, куда более узкий, и путать одно с другим нельзя.
|
||
|
||
**Решения и измеренные числа проекта прогон не читает вовсе.** `adr.*` и
|
||
`research.*` — процессные документы. Отсюда две строки в границы покрытия каждого
|
||
прогона: расхождение изменения с записанным решением ловится не здесь, а сверкой
|
||
документации; число, на которое опирается находка, обязано быть снято **на этом
|
||
прогоне**, иначе находка не поднимается выше гипотезы. Раньше числа брались из
|
||
`docs/research/`, и находка выглядела доказанной чужим замером неизвестной
|
||
свежести.
|
||
|
||
**Темы при этом названы все — но закрыты они по-разному, и это надо читать
|
||
буквально.** «Тема `security`, глубина сверка» не значит «безопасность
|
||
проверена»: значит, что дом темы открыли, дифф посмотрели и сравнили.
|
||
|
||
**Доказательства в цикле задачи нет ни на одной метке, и это самая крупная его
|
||
граница.** Класс дефектов, который виден только построенным путём и снятым
|
||
числом — гонка, деградация под нагрузкой, исчерпание ресурса, откат бинаря поверх
|
||
новой схемы, — не ловится здесь ничем: на `large` его смотрит `proof` чтением и
|
||
называет отложенным, ниже `large` его не смотрит никто.
|
||
|
||
Это сознательная сделка, а не пробел в устройстве: пара меряющих проходов
|
||
оплачивалась на каждой задаче с меткой `large`, а получалась на немногих. Теперь
|
||
она живёт в `av-dev:code-deep-review` и оплачивается тогда, когда её решают
|
||
получить. Проверяется сделка не рассуждением, а двумя следами: **строками
|
||
«отложено»** в отчётах — если по одному месту повторяется один и тот же неснятый
|
||
замер, глубокий прогон просрочен, — и **журналом дефектов**: класс, всплывающий
|
||
после мерджа, значит, что прогон надо звать чаще.
|
||
|
||
Так же честно и про упразднённый проход: **«не знаю, чего не знаю» больше
|
||
не достаёт никто.** Проход независимой реализации писал свою версию узла, не
|
||
открывая существующую, и диффил по решениям — декомпозиция, владение данными,
|
||
модель конкурентности, форма решения там, где спека выбора не сделала. Он снят по
|
||
решению оператора о **стоимости** — счёт определялся объёмом вывода, и на прогон
|
||
он тратил больше всех остальных проходов вместе, — а не по замеру, который
|
||
[calibration.md](references/calibration.md) требует перед удалением. Значит и
|
||
записывается это как сознательное сужение, а не как «класс оказался пустым»:
|
||
остаток независимого взгляда даёт `architecture` (второй способ, лишние слои), но
|
||
**альтернативной реализации, с которой можно сдиффить решения, у конвейера теперь
|
||
нет**. Сузилось это дважды: вместе с проходом независимой реализации ушла и
|
||
стадия ревью дизайна, ловившая форму решения до того, как код написан. Класс
|
||
идёт строкой в границы покрытия каждого прогона — там же, где проект перечисляет своё в
|
||
подразделе «перестали проверять сознательно».
|
||
|
||
Это и есть причина, по которой конвейер готовит ревью, а не заменяет его.
|
||
|
||
## Ссылки
|
||
|
||
- [references/project-facts.md](references/project-facts.md) — что нужно проходу
|
||
и где это лежит в документах проекта; таблица поразрядной деградации.
|
||
- [references/review-levels.md](references/review-levels.md) — дом правила выбора
|
||
метки: две оси, спорное вниз, чем `small` дешевле, доли как проверка правила.
|
||
- Skill `av-dev:code-deep-review` — глубокое ревью области кода: там живут
|
||
`review-adversary` и `review-ops`, там же единственное место процесса, где
|
||
находка доказывается прогоном и замером.
|
||
- Skill `av-dev:canon` — приведение проекта к канону документов.
|
||
- [references/finding-contract.md](references/finding-contract.md) — контракт находок.
|
||
- [references/promote.md](references/promote.md) — промоут находка → конвенция → правило → удаление.
|
||
- [references/calibration.md](references/calibration.md) — калибровка инъекцией, вердикты keep/retune/drop.
|
||
- [references/review-journal.md](references/review-journal.md) — журнал проскочивших дефектов.
|