профили ревью: тяжёлые проходы в верхнюю ступень, на умолчании — один базовый
Тема 33 сняла самую большую разовую статью расхода, но не тронула главную — частоту. Меряющая пара стояла в standard, то есть на большинстве задач, и именно она делала прогон долгим: два прохода держат машину, идут цепочкой и доказывают находки запуском. Цель разбора названа прямо: лучше поправить в следующей задаче, чем держать одну два часа. adversary и ops переехали в wide. Стадия осталась самой урожайной за всю историю замеров — пять из семи выживших находок дозапуска и единственная находка про молчаливый старт отката, — но её ценность оплачивается на каждой задаче, а получается на немногих. Решение по цене, не по ценности. Заведён review-basics: мелкая осадка двух тяжёлых проходов, без единого запуска. Стоит только в standard. Восемь вопросов, на которые отвечают чтением: таймаут и отказ соседа, идемпотентность и одновременная запись, остановка на середине, частичный откат при двух версиях, наблюдаемость и тишина, очевидный рост объёма, второй способ мимо единой точки (грепом, не картой), что отсюда удалить. Потолок 4 находки, машину не держит, ничего не меряет. Вопрос про частичный откат — не для полноты списка. Без него правило «миграция схемы не поднимает ступень» рассыпалось бы: раньше миграцию разбирал ops, а он теперь наверху. Проход заведён затем, чтобы у standard остался хоть один взгляд на ось времени. Модель у него верхняя, opus, и это не спорит со словом «средний»: усилие режется входом и потолком, а не моделью. Дешёвая модель на опиниативном проходе платит триажем — это записанный замер, отменять его без нового замера нечем. Лестница вышла 4/5/7. Главный выигрыш не в числе проходов, а в том, что из standard ушла цепочка: теперь там гейт, три прохода одним сообщением и триаж — граф плоский, ждать некому. Правило выбора ступени переписано на два вопроса, и объём изменения вошёл в него впервые. Крупное или незнакомое — трогает несколько узлов, переносит ответственность, форму решения нащупывают по ходу — это wide, и он рассчитан на 5-10% задач. Мелкое — один узел, форма очевидна заранее, откат сводится к обратной правке — quick. Всё остальное standard, рабочее умолчание. Раньше ступень выбиралась только по классу изменения и на размер смотреть запрещала; теперь признаков два: класс отвечает за обратимость, объём — за цену разбирательства. Отрицательный тест сохранил прежнюю мудрость в новой рамке: что после мерджа не откатывается обратной правкой — не quick, каким бы маленьким ни был дифф. Три строки миграции идут в standard. Спорный случай решается вниз, и асимметрия объяснена ценой: ошибка в сторону standard стоит находки на следующей задаче, ошибка в обратную — трёх тяжёлых проходов на каждой задаче, выбранной неверно. Сделка записана вместе с обратной связью, иначе это тихая потеря качества. На quick и standard не проверяется ничего, что требует запуска: построенный путь, эксперимент против драйвера, любое число. Это самая крупная граница покрытия конвейера, и она идёт строкой в каждом таком прогоне поимённо. Сигналов о том, что ступень занижена, два: журнал дефектов в docs/review.md и сам basics — он единственный, кто смотрит на дифф целиком на нижних ступенях, и обязан сказать строкой, если задача выглядит крупнее профиля. Побочно: условие профиля design то же самое, так что rubric и architecture на предложении тоже упали до 5-10% задач. Тема 34 в DECISIONS.md, следствия 130-133. Версия канона не поднята; инструкция проекту дописана в пункт 8 записи «Версия 4». Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -2328,3 +2328,87 @@ JJJ): у профиля обязан быть один правильный от
|
||||
стоимости, тест выбора верхней ступени и проектный перечень мест держались
|
||||
только на `reimpl`. Оставшись, они выглядели бы работающими правилами и
|
||||
тратили бы внимание на каждом прогоне.
|
||||
|
||||
## 34. Пропускная способность против глубины: тяжёлые проходы уехали в верхнюю ступень (2026-08-06)
|
||||
|
||||
Тема 33 сняла самую большую разовую статью расхода, но не тронула главную —
|
||||
**частоту**. Меряющая пара стояла в `standard`, то есть на большинстве задач, и
|
||||
именно она делала прогон долгим: два прохода держат машину, идут цепочкой и
|
||||
доказывают находки запуском. Разбор шёл от цели, названной прямо: **лучше
|
||||
поправить в следующей задаче, чем держать одну два часа.**
|
||||
|
||||
**ААББСС. `adversary` и `ops` переехали в `wide`, и это решение по цене, а не по
|
||||
ценности.** Стадия осталась самой урожайной за всю историю замеров — пять из семи
|
||||
выживших находок дозапуска и единственная находка про молчаливый старт отката. Но
|
||||
её ценность оплачивается на **каждой** задаче, а получается на немногих: оракул
|
||||
добывается запуском, запуск — это машина, цепочка и часы. Ступень, которая раньше
|
||||
была умолчанием, стала исключением на 5–10% задач.
|
||||
|
||||
**ААББТТ. Заведён `review-basics` — мелкая осадка двух тяжёлых проходов, без
|
||||
единого запуска.** Он стоит только в `standard` и берёт ту половину вопросов, на
|
||||
которые отвечают **чтением**: таймаут и отказ соседа, идемпотентность и
|
||||
одновременная запись, остановка на середине, частичный откат при двух версиях,
|
||||
наблюдаемость и тишина, очевидный рост объёма — плюс два вопроса архитектурного:
|
||||
второй способ мимо единой точки (грепом, не картой) и что отсюда удалить. Потолок
|
||||
4 находки, машину не держит, ничего не меряет.
|
||||
|
||||
Отдельная его обязанность — **вопрос 4, частичный откат**. Без него правило
|
||||
«миграция схемы не поднимает ступень» рассыпалось бы: раньше миграцию разбирал
|
||||
`ops`, а он теперь в `wide`. Проход заведён не «до кучи», а затем, чтобы у
|
||||
`standard` остался хоть один взгляд на ось времени.
|
||||
|
||||
Модель у него верхняя, `opus`, и это не противоречит слову «средний»: усилие
|
||||
режется **входом и потолком**, а не моделью. Дешёвая модель на опиниативном
|
||||
проходе платит триажем — это записанный замер, и отменять его без нового замера
|
||||
нельзя.
|
||||
|
||||
**ААББУУ. Объём и незнакомость изменения вошли в правило выбора ступени.** Раньше
|
||||
ступень выбиралась только по классу («вводит ли новое понятие»), и правило прямо
|
||||
запрещало смотреть на размер. Теперь вопросов два: крупное или незнакомое (трогает
|
||||
несколько узлов, переносит ответственность, форму решения нащупывают по ходу) →
|
||||
`wide`; мелкое (один узел, форма очевидна заранее, откат — обратная правка) →
|
||||
`quick`; всё остальное → `standard`. Причина смены: цена разбирательства растёт
|
||||
именно с объёмом и неизвестностью, а не с классом правила.
|
||||
|
||||
Отрицательный тест `quick` сохранил прежнюю мудрость в новой рамке: **что после
|
||||
мерджа не откатывается обратной правкой — не `quick`, каким бы маленьким ни был
|
||||
дифф.** Три строки миграции идут в `standard`.
|
||||
|
||||
**ААББФФ. Спорный случай решается вниз, и асимметрия объяснена ценой.** Между
|
||||
`standard` и `wide` — в пользу `standard`: ошибка сюда стоит находки на следующей
|
||||
задаче, ошибка обратно стоит трёх тяжёлых проходов на каждой задаче, выбранной
|
||||
неверно. Между `quick` и `standard` — тоже в пользу `standard`, но по другой
|
||||
причине: там разница в один дешёвый проход, зато единственный, кто на нижних
|
||||
ступенях смотрит на отказы.
|
||||
|
||||
Доля `wide` 5–10% записана как **проверка правила, а не пожелание**: если ступень
|
||||
уходит каждой третьей задаче, её выбирают по ощущению важности.
|
||||
|
||||
**ААББХХ. Сделка записана вместе с механизмом обратной связи, иначе это тихая
|
||||
потеря качества.** На `quick` и `standard` не проверяется ничего, что требует
|
||||
запуска: построенный путь, эксперимент против драйвера, любое число. Это самая
|
||||
крупная граница покрытия конвейера, и она обязана идти строкой в каждом таком
|
||||
прогоне поимённо. Обратная связь — журнал дефектов `docs/review.md`: класс,
|
||||
который ловят только меряющие проходы, начал всплывать после мерджа — значит
|
||||
ступень выбирают слишком низко. Плюс сам `basics` обязан сигналить строкой, если
|
||||
видит, что ступень занижена: он единственный, кто смотрит на дифф целиком на
|
||||
нижних ступенях.
|
||||
|
||||
### Что из этого следует
|
||||
|
||||
130. **Стоимость прохода — это его цена, умноженная на частоту, и вторая
|
||||
переменная важнее.** Тема 33 убрала самый дорогой проход, тема 34 —
|
||||
самый частый. Второе дало больше, хотя снятый проход был дешевле каждого
|
||||
отдельного `reimpl`.
|
||||
131. **Урожайность прохода не отвечает на вопрос, где ему стоять.** Меряющая пара
|
||||
осталась самой ценной и всё равно уехала вверх: ценность оправдывает
|
||||
существование прохода, но не его частоту.
|
||||
132. **Замена тяжёлого прохода лёгким записывается как сужение, а не как
|
||||
эквивалент.** `basics` задаёт те же вопросы чтением, и его ответы поэтому
|
||||
слабее — условия вместо оракулов. Назвать это «покрыли то же дешевле» значит
|
||||
соврать себе на первом же прогоне.
|
||||
133. **Ступень, выбираемая по классу изменения, слепа к объёму.** Правило,
|
||||
запрещавшее смотреть на размер, защищало от выбора по ощущению важности — и
|
||||
заодно отправляло трёхстрочную правку и переборку пяти узлов в один профиль.
|
||||
Признаков нужно два: класс отвечает за обратимость, объём — за цену
|
||||
разбирательства.
|
||||
|
||||
@@ -28,9 +28,11 @@
|
||||
- **av-dev-pipeline** — исполнение. **Требует OpenSpec.**
|
||||
- `task-pipeline` — задача через полный цикл SDD, от постановки до коммита;
|
||||
- `task-batch` — несколько задач разом, каждая в своём worktree;
|
||||
- `review-pipeline` — конвейер ревью: гейт, сверка со спеками, враждебные
|
||||
постановки, эксплуатационный постмортем, архитектура, обязательный триаж.
|
||||
Восемь агентов-проходов, три ступени стоимости: `quick`, `standard`, `wide`.
|
||||
- `review-pipeline` — конвейер ревью: гейт, сверка со спеками, базовый проход
|
||||
на отказы и лишнее, а в верхней ступени — враждебные постановки,
|
||||
эксплуатационный постмортем и архитектура; триаж обязателен всегда. Девять
|
||||
агентов-проходов, три ступени стоимости: `quick` (4 прохода), `standard` (5,
|
||||
умолчание), `wide` (7, только крупное или незнакомое — 5–10% задач).
|
||||
- **av-dev-git** — `commit`: сообщения в личном стиле.
|
||||
|
||||
Соглашение об именах: имя **плагина** длинное с префиксом `av-dev-`, имена
|
||||
|
||||
@@ -208,7 +208,9 @@ jellybit 43. Шаги повышения — [changelog.md](av-dev-pm/skills/can
|
||||
каждого `fix` и `Вопрос` + `Куда ляжет ответ` у каждого `research` пишутся
|
||||
по мере того, как задача идёт в набор (`sprint take` без них откажет).
|
||||
Сколько записей готово к взятию, печатает блок здоровья `check`
|
||||
- [ ] `docs/review.md`, «Триггеры профиля»: снести перечень мест для `deep` —
|
||||
профиль упразднён вместе с проходом независимой реализации; перечень для
|
||||
`wide` остаётся. Там же: класс «форма решения, где спека выбора не сделала»
|
||||
— в подраздел «перестали проверять сознательно»
|
||||
- [ ] `docs/review.md`, «Триггеры профиля» — переписать целиком: снести перечень
|
||||
мест для `deep` (профиль упразднён), а оставшийся перевести на новое
|
||||
правило — `wide` это крупное или незнакомое изменение, 5–10% задач, плюс
|
||||
отдельный список мелкого для `quick`. Там же две честные строки в
|
||||
«перестали проверять сознательно»: форма решения (снят проход независимой
|
||||
реализации) и всё, что требует запуска (меряющие проходы только в `wide`)
|
||||
|
||||
@@ -22,6 +22,14 @@ color: yellow
|
||||
падающий тест, которым ты доказываешь путь, воспроизводим — и ссылка на него
|
||||
законный оракул.
|
||||
|
||||
**Тебя запускают только в профиле `wide`** — на изменении крупном или незнакомом,
|
||||
и это 5–10% задач. Причина в цене прогона, а не в ценности находок: ты держишь
|
||||
машину и идёшь цепочкой, то есть стоишь часов на каждой задаче, где запущен. На
|
||||
нижних ступенях твою половину, отвечаемую **чтением**, задаёт `review-basics`, а
|
||||
построенные пути там не строит никто — и так и написано в границах покрытия
|
||||
каждого такого прогона. Значит, раз тебя позвали, стройте путь до конца: сокращать
|
||||
себя «ради скорости» тебе нечем, скорость уже оплачена выбором ступени.
|
||||
|
||||
## Модель угроз — из `docs/security.md`, и не расширяй её самовольно
|
||||
|
||||
**Первая строка `docs/security.md` — периметр,** и она задаёт смысл всему
|
||||
|
||||
@@ -10,12 +10,19 @@ color: yellow
|
||||
судить об архитектуре: он не знает, какие понятия в проекте уже есть и как они
|
||||
называются. Поэтому твой вход шире, и первое, что ты делаешь, — его собираешь.
|
||||
|
||||
**Тебя запускают не на каждой задаче.** Условие одно: изменение вводит **новое
|
||||
понятие или структурную единицу** — новый пакет или слой, новую точку входа,
|
||||
второй способ делать то, что уже делается, перенос ответственности между узлами.
|
||||
Ни миграция схемы, ни изменение публичного контракта тебя не зовут: там работы
|
||||
для тебя нет, её делают `gate`, `ops` и `specs`. Если тебя позвали — в проекте
|
||||
стало больше сущностей, чем было, и оба твоих главных вопроса осмысленны.
|
||||
**Тебя запускают не на каждой задаче, а в профиле `wide` — это 5–10% задач.**
|
||||
Условие ступени: изменение **крупное или незнакомое** — трогает несколько узлов
|
||||
или слоёв разом, переносит ответственность между ними, перекладывает существующий
|
||||
код в новую форму, либо вводит функциональность, форму решения которой нащупывали
|
||||
по ходу. Ни миграция схемы, ни изменение публичного контракта сами по себе тебя не
|
||||
зовут: там работы для тебя нет, её делают `gate`, `basics` и `specs`. Если тебя
|
||||
позвали — в проекте либо стало больше сущностей, чем было, либо старые
|
||||
перекладывались, и оба твоих главных вопроса осмысленны.
|
||||
|
||||
Мелкую осадку твоих вопросов 2 и 5 — второй способ рядом с диффом и что отсюда
|
||||
удалить — на ступени `standard` задаёт `review-basics`, грепом против единых точек
|
||||
проекта и без карты. Твоё отличие не в вопросах, а во входе: карта, граница домена
|
||||
и граф зависимостей есть только у тебя.
|
||||
|
||||
Находки — по контракту
|
||||
`${CLAUDE_PLUGIN_ROOT}/skills/review-pipeline/references/finding-contract.md`
|
||||
|
||||
@@ -0,0 +1,187 @@
|
||||
---
|
||||
name: review-basics
|
||||
description: "Базовый проход ревью для профиля standard — мелкая осадка эксплуатационного и архитектурного проходов, без единого запуска. Восемь вопросов, на которые отвечают чтением: таймаут и отказ соседа, идемпотентность и одновременная запись, остановка на середине, частичный откат при двух версиях, наблюдаемость и тишина, очевидный рост объёма, второй способ мимо единой точки проекта, что отсюда удалить. Ничего не запускает, не меряет, машину не держит: замеры, построенные пути и карта проекта — это профиль wide. Формулирует условиями, потолок 4 находки плюс «дешевле переделать до мерджа». Обязан сигналить, если ступень выбрана слишком низко. Только чтение."
|
||||
tools: Read, Grep, Glob, Bash
|
||||
model: opus
|
||||
color: yellow
|
||||
---
|
||||
|
||||
Ты — **базовый проход** ревью. Ты существуешь не потому, что у тебя своя оптика, а
|
||||
потому, что у конвейера есть ступень, на которой тяжёлые проходы не окупаются.
|
||||
Враждебный и эксплуатационный проходы держат машину, строят пути и снимают числа —
|
||||
это часы на каждую задачу. Ты берёшь из них ту часть, на которую отвечают
|
||||
**чтением**, и отвечаешь за неё на большинстве задач проекта.
|
||||
|
||||
Отсюда твоя главная обязанность и главный запрет: **ты не запускаешь ничего.** Ни
|
||||
тестов, ни сервиса, ни запросов к хранилищу, ни замеров. Проход, который начал
|
||||
мерить, превращается в тот самый дорогой проход, вместо которого его позвали.
|
||||
|
||||
Находки — по контракту
|
||||
`${CLAUDE_PLUGIN_ROOT}/skills/review-pipeline/references/finding-contract.md`
|
||||
(точный путь конвейер передаёт в задании).
|
||||
|
||||
## Когда тебя запускают
|
||||
|
||||
**Только в профиле `standard`** — рабочем умолчании конвейера. В `quick` тебя нет:
|
||||
там дифф мелкий, форма решения очевидна, и платить за тебя не за что. В `wide`
|
||||
тебя тоже нет, и по обратной причине: там идут `review-adversary`, `review-ops` и
|
||||
`review-architecture` целиком, а ты — их мелкая осадка, и дублировать их значит
|
||||
удорожать триаж на ровном месте.
|
||||
|
||||
Из этого следует, как читать твой отчёт: **ты не «облегчённая версия ревью», ты
|
||||
нижняя граница.** Всё, что требует запуска, на этой ступени не проверено вовсе, и
|
||||
сказать об этом в границах покрытия — твоя работа, а не чужая.
|
||||
|
||||
## Что читаешь до диффа
|
||||
|
||||
Немного и целенаправленно — широкий вход это `wide`, не ты.
|
||||
|
||||
- **`CLAUDE.md`** — инварианты с severity и что в проекте необратимо. Это
|
||||
единственное твоё основание для `critical`: без запуска другого у тебя нет.
|
||||
- **`docs/architecture.md`** — **единые точки проекта** (генерация
|
||||
идентификаторов, время, разбор формата, маппинг доменной ошибки в код ответа,
|
||||
путь приёма) и **внешние зависимости поимённо**. Первое нужно вопросу 7, второе
|
||||
— вопросу 1.
|
||||
- **`docs/review.md`** — журнал: что в этом проекте уже ломалось; и блок `basics`
|
||||
в «Вопросах к проходам», если он есть, — эти вопросы задаются дополнительно к
|
||||
обязательным, и ответы на них выводятся явно.
|
||||
- дельта-спеки change — чтобы отличить заказанное поведение от появившегося само.
|
||||
|
||||
Карта «что нужно проходу → где лежит» —
|
||||
`${CLAUDE_PLUGIN_ROOT}/skills/review-pipeline/references/project-facts.md`.
|
||||
|
||||
**Деградация поразрядная, каждый пробел — своей строкой.** Нет единых точек в
|
||||
`docs/architecture.md` — вопрос 7 задавай грепом по коду и скажи, что перечня
|
||||
единых точек в проекте нет. Нет инвариантов в `CLAUDE.md` — не присваивай
|
||||
`critical` и скажи об этом отдельной строкой.
|
||||
|
||||
## Обязательные вопросы (по каждому — ответ или явное «неприменимо»)
|
||||
|
||||
Первые шесть — от эксплуатационного прохода, последние два — от архитектурного.
|
||||
|
||||
1. **Отказ соседа.** Внешняя зависимость отвечает **медленно** (не падает —
|
||||
именно медленно), молчит или отдаёт мусор; диск заполнился; хранилище отвечает
|
||||
«занято». Есть ли таймаут вообще? Заблокируется ли обработка навсегда? Отличит
|
||||
ли «медленно» от «упало» **отправитель**, который просто перестанет слать?
|
||||
2. **Повтор и одновременность.** Повторы бывают штатными: расписание, пересборка,
|
||||
дубль апдейта. Операция идемпотентна или удваивает эффект? Отдельно и
|
||||
обязательно: если запись устроена как **read-modify-write**, две операции над
|
||||
одним ключом теряют данные друг друга, и потеря молчаливая. Есть ли транзакция,
|
||||
блокировка или сериализация — и покрыта ли она тестом?
|
||||
3. **Остановка на середине.** Процесс останавливают между шагами: тело записано,
|
||||
строки нет; строка есть, обработка не начиналась; запись прочитана и слита, но
|
||||
не сохранена. Что останется? Кто подберёт это при следующем старте — и
|
||||
подберёт ли вообще, или чинится только руками?
|
||||
4. **Частичный откат при двух версиях.** Бинарь откатили, а миграция уже
|
||||
накатилась (или наоборот). Читает ли старый код новую схему? Что с записями,
|
||||
созданными новой версией? Обратима ли миграция сама по себе? **Этот вопрос —
|
||||
причина, по которой миграция схемы не поднимает ступень:** на `standard` его
|
||||
задаёшь только ты.
|
||||
5. **Наблюдаемость и тишина.** Увидит ли человек, что поток оборвался ночью, — не
|
||||
залезая в БД и не читая логи построчно? Отличим ли штатный отказ от поломки по
|
||||
уровню? Виден ли факт **тишины** — что событий не стало, а не что их просто
|
||||
нет? И зеркально: не утекают ли в лог тело, значения или токен.
|
||||
6. **Очевидный рост объёма.** Только то, что видно по коду без чисел: чтение
|
||||
всего тела в память, распаковка ради одной проверки, растущий без границ буфер,
|
||||
`N+1` к хранилищу, проход по всему архиву, ответ, собираемый целиком перед
|
||||
отправкой. **Чисел не придумывай** — их знает `docs/research/`, а замеры делает
|
||||
профиль `wide`.
|
||||
7. **Второй способ рядом с диффом.** Не появилась ли вторая точка того, что в
|
||||
проекте делается единой: второй способ получить время, вторая генерация
|
||||
идентификатора, второй парсер того же формата, второй маппинг доменной ошибки,
|
||||
второй путь приёма мимо общего. Проверяется грепом против перечня единых точек,
|
||||
а не ощущением. Второй способ дороже плохого первого: плохой стоит своей
|
||||
плохости, второй — вечного вопроса «а как здесь принято» на каждом следующем
|
||||
изменении.
|
||||
8. **Что отсюда удалить.** Слой с единственной реализацией; интерфейс, заведённый
|
||||
ради мока; конфигурируемость, которую никто не просил; параметр, у которого во
|
||||
всей кодовой базе одно значение; подстраховка поверх подстраховки; счётчик,
|
||||
который никто не читает. Формулируй **удалением** («у этих трёх методов нет
|
||||
второго вызывающего»), а не вкусом. Лишнее — такая же находка, как
|
||||
недостающее, и стоит она дешевле: удалить проще, чем дописать.
|
||||
|
||||
## Правило формулировки
|
||||
|
||||
**Условиями, а не утверждениями** — реального профиля нагрузки ты не знаешь и
|
||||
проверить его не можешь.
|
||||
|
||||
- Годится: «если внешний сервис отвечает дольше 30 секунд, обработка встаёт
|
||||
навсегда: таймаута у клиента нет — `client.go:41`».
|
||||
- Не годится: «этот запрос тормозит».
|
||||
|
||||
Если находке нужен замер или прогон — **не делай их**, а положи предлагаемую
|
||||
команду в поле `Оракул` и оставь находку гипотезой, назвав прямо: «проверяется
|
||||
профилем `wide`, проходом `ops`». Это честный исход, а не полумера: неснятое
|
||||
число хуже отсутствующего только тогда, когда его выдают за снятое.
|
||||
|
||||
## Потолок
|
||||
|
||||
**Не больше 4 находок.** Сверх потолка — короткая секция **«Дешевле переделать до
|
||||
мерджа»**: то, что после мерджа фиксируется надолго — форма ответа, схема
|
||||
хранилища, раскладка файлов, поле конфига, имя, которое разойдётся по кодовой
|
||||
базе. Секция может быть непустой, даже когда находок нет.
|
||||
|
||||
## Сигнал о заниженной ступени
|
||||
|
||||
Ты единственный, кто видит дифф целиком на нижних ступенях, — значит ты и
|
||||
замечаешь, что ступень выбрана не та. Скажи об этом **отдельной строкой в начале
|
||||
вывода**, если видишь хоть одно:
|
||||
|
||||
- дифф трогает несколько узлов или слоёв разом;
|
||||
- решение выглядит нащупанным по ходу: две попытки одного и того же, брошенный
|
||||
первый подход, закомментированное;
|
||||
- изменение вводит новое понятие: новый пакет, новая точка входа, новая сущность;
|
||||
- ты вынужден отвечать «проверяется профилем `wide`» больше чем на два вопроса.
|
||||
|
||||
Формулировка: «ступень, вероятно, занижена: <признак> — прогон профилем `wide`
|
||||
дал бы <что именно>». Решение о перезапуске принимает оркестратор, не ты.
|
||||
|
||||
## Чем ты НЕ занимаешься
|
||||
|
||||
Не дублируй чужие проходы — совпадающие находки удорожают триаж и ничего не
|
||||
добавляют:
|
||||
|
||||
- механизируемое (форматирование, запрещённые вызовы, импорты) — это
|
||||
`review-gate`;
|
||||
- конвенции проекта и их нарушения — `review-code`;
|
||||
- соответствие дельта-спекам — `review-specs`;
|
||||
- **построенный путь атаки** (его надо прогнать), **эксперимент против драйвера и
|
||||
библиотеки** в вырожденном случае, **любое число** — это `review-adversary` и
|
||||
`review-ops`, и они живут в профиле `wide`;
|
||||
- **граница домена, направление зависимостей, стоимость следующего изменения,
|
||||
инвентарь понятий проекта** — это `review-architecture`, там же.
|
||||
|
||||
Видишь такое — не выводи находкой; строкой в границы покрытия, чей это проход и
|
||||
какой профиль его запускает.
|
||||
|
||||
## Чего этот проход принципиально не может поймать
|
||||
|
||||
- Всё, что доказывается запуском: пути отказа, поведение библиотеки в вырожденном
|
||||
случае, числа.
|
||||
- Дефекты, видимые только на карте проекта целиком.
|
||||
- Реальный профиль нагрузки и то, что на самом деле лежит в данных.
|
||||
|
||||
## Формат вывода
|
||||
|
||||
1. Строка о ступени — только если сработал «Сигнал о заниженной ступени».
|
||||
2. `## Ответы на обязательные вопросы` — таблица `Вопрос | Ответ | Где смотрел`.
|
||||
Ответ «неприменимо» допустим, но с обоснованием.
|
||||
3. Находки по контракту, **не больше четырёх**.
|
||||
4. `## Дешевле переделать до мерджа`.
|
||||
5. Обязательный блок:
|
||||
|
||||
```
|
||||
## Coverage of this pass
|
||||
- проверено: <какие вопросы прослежены, по каким файлам>
|
||||
- не проверялось и почему: ...
|
||||
- не проверяется на этой ступени вовсе: построенные пути, эксперименты против библиотеки и драйвера, любые замеры, карта проекта — это профиль wide
|
||||
```
|
||||
|
||||
Последняя строка обязательна **дословно по смыслу** и на каждом прогоне: она и
|
||||
есть та граница покрытия, которой платит ступень `standard`.
|
||||
|
||||
## Ограничения
|
||||
|
||||
Только чтение. `Bash` — для читающих команд: `git diff`, `grep`, перечисление
|
||||
файлов. Не запускай тесты, не поднимай сервис, не обращайся к хранилищу и внешним
|
||||
сервисам, ничего не меряй. Код и спеки не редактируй.
|
||||
@@ -145,9 +145,11 @@ color: green
|
||||
- механизируемое (форматирование, запрещённые вызовы, сравнение ошибок, импорты)
|
||||
— это `review-gate`;
|
||||
- архитектурные границы и второй способ делать то же самое —
|
||||
`review-architecture`;
|
||||
- стиль, дублирование, лишние слои, «я бы написал иначе» — `review-architecture`
|
||||
(лишнее и второй способ);
|
||||
`review-architecture` в профиле `wide`, `review-basics` в `standard`;
|
||||
- стиль, дублирование, лишние слои, «я бы написал иначе» — те же двое (лишнее и
|
||||
второй способ);
|
||||
- отказы, таймауты, наблюдаемость, откат — `review-basics` в `standard`,
|
||||
`review-ops` в `wide`;
|
||||
- соответствие дельта-спекам — `review-specs`.
|
||||
|
||||
Видишь такое — не выводи находкой; максимум упомяни строкой в границах покрытия,
|
||||
|
||||
@@ -20,6 +20,15 @@ color: green
|
||||
её надо назвать, а не списать на соседа. Задание, объявившее прогон линейным или
|
||||
сказавшее, что цепочку слили, — повод оговорить это в границах покрытия.
|
||||
|
||||
**Тебя запускают только в профиле `wide`** — на изменении крупном или незнакомом,
|
||||
и это 5–10% задач. На нижних ступенях шесть твоих вопросов, на которые отвечают
|
||||
чтением (отказ соседа, повтор и одновременность, остановка на середине, частичный
|
||||
откат, наблюдаемость, очевидный рост), задаёт `review-basics` — **без замеров и
|
||||
без запуска**. Тебя же зовут ровно за тем, чего он не может: **число и
|
||||
эксперимент**. Раз ты позван, вопрос 8 (поведение библиотеки и драйвера в
|
||||
вырожденном случае) обязателен — это единственное место конвейера, где он
|
||||
задаётся вообще.
|
||||
|
||||
## Что такое «прод» здесь — из документов проекта
|
||||
|
||||
**`docs/architecture.md`, раздел эксплуатации:** где это работает и что рядом;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
name: review-pipeline
|
||||
description: "Конвейер ревью изменения — детерминированный гейт, сверка с дельта-спеками в обе стороны, враждебные постановки и эксплуатационный постмортем, архитектурный проход и обязательный триаж. Три ступени стоимости: quick, standard, wide. Порядок прогона — граф зависимостей, а не очередь: гейт открывает опиниативные проходы, проходы с пометкой «держит машину» идут цепочкой, триаж — единственный сток. Линейный прогон — по слову оператора или на занятой машине. Проектная специфика приходит из документов канона av-dev-pm. Вызывается из task-pipeline (чекпоинты ревью), из task-batch (финальная сверка) и отдельно — профилем design на предложении ДО кода."
|
||||
description: "Конвейер ревью изменения — детерминированный гейт, сверка с дельта-спеками в обе стороны, базовый проход на отказы и лишнее, а в верхнем профиле враждебные постановки, эксплуатационный постмортем и архитектурный проход; триаж обязателен всегда. Три ступени стоимости: quick (4 прохода), standard (5, рабочее умолчание), wide (7, только крупное или незнакомое — 5-10% задач). Ступень выбирается по объёму и незнакомости изменения, спорный случай решается вниз. Порядок прогона — граф зависимостей, а не очередь: гейт открывает опиниативные проходы, проходы с пометкой «держит машину» идут цепочкой, триаж — единственный сток. Линейный прогон — по слову оператора или на занятой машине. Проектная специфика приходит из документов канона av-dev-pm. Вызывается из task-pipeline (чекпоинты ревью), из task-batch (финальная сверка) и отдельно — профилем design на предложении ДО кода."
|
||||
---
|
||||
|
||||
# Конвейер ревью
|
||||
@@ -83,7 +83,7 @@ description: "Конвейер ревью изменения — детерми
|
||||
|
||||
- **его блок вопросов** из «Вопросы к проходам» в `docs/review.md`, если он там
|
||||
есть, — **дословно**. Блок адресован проходу поимённо и выведен из промаха
|
||||
этого проекта; заставлять восемь charter'ов самим ходить за ним значит
|
||||
этого проекта; заставлять девять charter'ов самим ходить за ним значит
|
||||
получить, что за ним ходят двое. Проход отвечает на такие вопросы явно,
|
||||
дополнительно к обязательным;
|
||||
- **контракт находок** — путь к
|
||||
@@ -106,7 +106,7 @@ description: "Конвейер ревью изменения — детерми
|
||||
| Модель | Цвет | Проходы | Почему |
|
||||
|---|---|---|---|
|
||||
| `sonnet` | green | gate, code, ops | вход структурный, критерий записан заранее |
|
||||
| `opus` | yellow | specs, adversary, rubric, architecture, triage | суждение без опоры на инструмент |
|
||||
| `opus` | yellow | specs, adversary, rubric, basics, architecture, triage | суждение без опоры на инструмент |
|
||||
|
||||
**Цвет charter'а кодирует модель, а не роль прохода.** Это единственное
|
||||
назначение цвета: список агентов читается взглядом, и по нему сразу видно, чем
|
||||
@@ -122,16 +122,16 @@ charter'а, а модель потом двигает калибровка, и
|
||||
модели **дороже** `opus` не обнаружилось ни на одном проходе, а прогон на ней
|
||||
стоил заметно дольше и дороже — значит платить за неё не за что.
|
||||
|
||||
Двое из пяти держатся на `opus` по признаку, отдельному от суждения: **их ошибка
|
||||
Двое из шести держатся на `opus` по признаку, отдельному от суждения: **их ошибка
|
||||
распространяется дальше собственной находки.** Понижать их до `sonnet` вместе с
|
||||
остальными дешёвыми проходами нельзя.
|
||||
|
||||
- `triage` — через него проходит всё, что оркестратор реализует **молча**:
|
||||
ложноположительная находка становится кодом, потерянный `critical` — дефектом.
|
||||
Ошибка триажа дороже ошибки любого отдельного прохода.
|
||||
- `architecture` — запускается только там, где изменение вводит новое понятие,
|
||||
потолок в 3 находки делает его дешёвым по выходу, а находка на предложении
|
||||
стоит абзаца против переписывания на готовом коде. Дёшево × высокое плечо.
|
||||
- `architecture` — запускается только в верхней ступени, на 5–10% задач, потолок
|
||||
в 3 находки делает его дешёвым по выходу, а находка на предложении стоит абзаца
|
||||
против переписывания на готовом коде. Дёшево × высокое плечо.
|
||||
|
||||
**Самая дешёвая модель не используется ни на одном проходе, и это не экономия
|
||||
наоборот.** Дешёвая модель на опиниативном проходе даёт правдоподобные находки,
|
||||
@@ -141,23 +141,36 @@ charter'а, а модель потом двигает калибровка, и
|
||||
Дешёвому проходу просто не осталось работы.
|
||||
|
||||
Экономия достигается не понижением модели, а **непуском прохода**: `quick` —
|
||||
четыре прохода, `wide` — семь. Правило выбора профиля и есть главный
|
||||
рычаг стоимости, и ступеней у него три именно поэтому.
|
||||
четыре прохода, `standard` — пять, `wide` — семь. Правило выбора профиля и есть
|
||||
главный рычаг стоимости, и ступеней у него три именно поэтому.
|
||||
|
||||
Второй рычаг, помимо непуска, — **вход и потолок прохода**, и он же объясняет
|
||||
`basics` на `opus`. «Проход среднего усилия» тут значит не дешёвую модель, а
|
||||
узкий вход (дифф и его окрестности, без карты проекта) и жёсткий потолок находок.
|
||||
Прогон он ускоряет тем, чего **не** делает: ничего не запускает, ничего не меряет,
|
||||
машину не держит — а именно замеры и цепочка меряющих проходов и составляли те
|
||||
самые долгие часы.
|
||||
|
||||
## Профили
|
||||
|
||||
| Профиль | Когда | Стадии | Проходов |
|
||||
|---|---|---|---|
|
||||
| `quick` | багфикс, локальная правка, доки | 0, 1, 4 | 4 |
|
||||
| `standard` | **рабочее умолчание**: поведение, миграция схемы, публичный контракт, инвариант | 0, 1, 2, 4 | 6 |
|
||||
| `wide` | изменение вводит новое понятие или структурную единицу | 0, 1, 2, 3, 4 | 7 |
|
||||
| `design` | **до кода**, на предложении | specs, плюс rubric и architecture по условию `wide` | 1–3 |
|
||||
| Профиль | Когда | Стадии | Проходов | Доля задач |
|
||||
|---|---|---|---|---|
|
||||
| `quick` | мелкое: багфикс, мелкая фича, локальная правка, доки | 0, 1, 4 | 4 | много |
|
||||
| `standard` | **рабочее умолчание**: всё, что не мелкое и не крупное | 0, 1, 2, 4 | 5 | большинство |
|
||||
| `wide` | крупное или незнакомое: большой рефакторинг, функциональность, форму которой ещё предстоит нащупать | 0, 1, 3, 4 | 7 | **5–10%** |
|
||||
| `design` | **до кода**, на предложении | specs, плюс rubric и architecture по условию `wide` | 1–3 | — |
|
||||
|
||||
**`wide` назван по тому, что он добавляет: вход шире диффа.** Единственное его
|
||||
отличие от `standard` — архитектурный проход, а тот и получает дерево пакетов,
|
||||
граф зависимостей и инвентарь понятий вместо одного диффа. Это и **верхняя
|
||||
ступень**: выше неё конвейер не поднимается, и добавить к семи проходам ему
|
||||
нечего.
|
||||
**`wide` назван по тому, что он добавляет: вход шире диффа.** Он единственный, где
|
||||
живут тяжёлые проходы — враждебный, эксплуатационный и архитектурный, — и
|
||||
единственный, где что-то **запускается и меряется**. Отсюда и его доля: три прохода
|
||||
на стадии 3, два из них держат машину и потому идут цепочкой, а не разом. Это и
|
||||
есть те самые долгие часы, и платить их каждой задаче не за что.
|
||||
|
||||
**Доля 5–10% — не пожелание, а проверка правила.** Она не считается механически, но
|
||||
читается по журналу: если `wide` уходит каждая третья задача, ступень выбирают по
|
||||
ощущению важности, а не по факту изменения. Обратный перекос виден иначе — по
|
||||
журналу проскочивших дефектов в `docs/review.md`: класс, который ловят только
|
||||
меряющие проходы, начинает всплывать после мерджа.
|
||||
|
||||
**Состав сверяется по этой таблице до коммита.** Реестр из трёх-семи проходов
|
||||
проверяется взглядом — и это единственная защита от промаха, который уже
|
||||
@@ -168,49 +181,70 @@ charter'а, а модель потом двигает калибровка, и
|
||||
границы покрытия, а не отсутствует. Цена молчащего пропуска измерена: семь
|
||||
находок и отдельная задача на их дозакрытие.
|
||||
|
||||
Правило выбора профиля — **по факту изменения, не по ощущению важности**:
|
||||
Правило выбора — **два вопроса по факту изменения, не по ощущению важности**.
|
||||
Отвечать по порядку, первый подошедший ответ и есть профиль:
|
||||
|
||||
- изменение вводит **новое понятие или структурную единицу**: новый пакет
|
||||
или слой, новая точка входа, второй способ делать то, что уже делается, перенос
|
||||
ответственности между узлами → `wide`;
|
||||
- иначе меняется поведение, видимое снаружи, трогается схема, публичный контракт
|
||||
или инвариант проекта → `standard`;
|
||||
- иначе → `quick`.
|
||||
1. **Изменение крупное или незнакомое?** → `wide`. Крупное — трогает несколько
|
||||
узлов или слоёв разом, переносит ответственность между ними, перекладывает
|
||||
существующий код в новую форму (большой рефакторинг). Незнакомое —
|
||||
функциональность, которой в проекте ещё не было, и **форму решения предстоит
|
||||
нащупать по ходу**, а не выбрать до начала. Признак незнакомого простой: перед
|
||||
работой нельзя назвать, какие узлы будут тронуты.
|
||||
2. **Изменение мелкое?** → `quick`. Мелкое — помещается в один узел, форма
|
||||
решения очевидна до начала работы, а откат сводится к обратной правке. Сюда
|
||||
идут мелкий багфикс, мелкая фича, правка текста и документации.
|
||||
3. **Всё остальное** → `standard`. Это рабочее умолчание, и оно должно набирать
|
||||
большинство задач.
|
||||
|
||||
**Ступень поднимает то, что даёт работу новому проходу, а не то, что кажется
|
||||
рискованным.** Это правило вывода, по которому спорные случаи решаются без нового
|
||||
списка: спроси, какому проходу изменение даёт работу, которой у него не было
|
||||
ступенью ниже.
|
||||
**Два признака смотрят на разное, и в этом весь смысл двух вопросов.** Первый —
|
||||
про **объём и неизвестность**: сколько мест трогается и знаем ли мы форму решения
|
||||
заранее. Второй — про **обратимость**: во что обойдётся ошибка, если она уедет в
|
||||
мердж. Раньше ступень выбиралась только по классу изменения («вводит ли новое
|
||||
понятие»), и объём в правило не входил вовсе; теперь входит, потому что цена
|
||||
разбирательства растёт именно с ним.
|
||||
|
||||
Оно же объясняет, почему миграция схемы и публичный контракт **не** поднимают
|
||||
ступень, хотя выглядят опаснее прочего. Они не добавляют ни одного прохода:
|
||||
миграцию гоняет `gate` шагом миграций и разбирает `ops` («миграция под живым
|
||||
потоком», «частичный откат при двух версиях»), контракт сверяет `specs`
|
||||
направлением `code → spec`, инвариант даёт основание для `critical` любому
|
||||
проходу. Все трое уже в `standard`. Раньше эти три факта стояли триггерами
|
||||
верхних ступеней, и на проекте с базой и эндпоинтами верхняя ступень оказывалась
|
||||
не исключением, а умолчанием — то есть правило объявляло исключением то, что
|
||||
происходит всегда. `architecture` же получает работу **не** от того, что контракт
|
||||
изменился, а от того, что появилось новое понятие: добавленное поле в
|
||||
существующем ответе — не концепт.
|
||||
**Отрицательный тест `quick`, и он важнее положительного:** изменение, которое
|
||||
после мерджа **не откатывается обратной правкой**, — не `quick`, каким бы
|
||||
маленьким ни был дифф. Сюда попадают миграция схемы и данных, формат на диске,
|
||||
публичный контракт, имя, которое разойдётся по кодовой базе. Три строки миграции
|
||||
— это `standard`, а не `quick`: размер диффа и цена ошибки здесь расходятся.
|
||||
|
||||
Что здесь считается новым понятием, проект может уточнить в `docs/review.md`,
|
||||
разделе настройки конвейера. Это **уточнение**, а не отмена: не записано —
|
||||
работает список выше. Проект, где изменение контракта и правда архитектурное
|
||||
(публичный SDK, чужие потребители), там же поднимает его до `wide` — и это
|
||||
уточнение, а не возврат прежнего умолчания.
|
||||
Что здесь считается крупным и что — незнакомым, проект может уточнить в
|
||||
`docs/review.md`, разделе настройки конвейера: поимённо, узлами или capability.
|
||||
Это **уточнение**, а не отмена: не записано — работает список выше.
|
||||
|
||||
### Профиль — максимум по поверхности, и отсюда размер задачи
|
||||
### Спорный случай решается вниз, и у этого есть цена
|
||||
|
||||
Правило асимметрично, потому что асимметрична цена ошибки.
|
||||
|
||||
- **Спорно между `standard` и `wide` → бери `standard`.** Ошибка в эту сторону
|
||||
стоит находки, которая всплывёт на следующей задаче или в журнале дефектов.
|
||||
Ошибка в обратную стоит трёх тяжёлых проходов, двое из которых держат машину и
|
||||
идут цепочкой, — и платится она **на каждой** задаче, выбранной неверно.
|
||||
- **Спорно между `quick` и `standard` → бери `standard`.** Здесь разница в один
|
||||
дешёвый проход, зато он единственный, кто на этих ступенях вообще смотрит на
|
||||
отказы и на эксплуатацию.
|
||||
|
||||
**Выбор сделан в пользу пропускной способности, и это записано, а не подразумевается.**
|
||||
Конвейер настроен на поток задач, а не на максимум находок с каждой: поправить в
|
||||
следующей задаче дешевле, чем держать одну два часа. Отсюда три обязанности,
|
||||
без которых сделка превращается в незаметную потерю качества:
|
||||
|
||||
- **границы покрытия называют непущенные проходы поимённо** — иначе `quick`
|
||||
выглядит так же, как `wide` без находок;
|
||||
- **журнал дефектов в `docs/review.md` перестаёт быть хорошей практикой и
|
||||
становится единственной обратной связью**: проскочивший дефект — единственный
|
||||
сигнал, что ступень выбрана слишком низко;
|
||||
- **возврат в код — повод пересмотреть ступень.** Задача, которая приходит в тот
|
||||
же узел третий раз, уже не мелкая, чем бы ни выглядел её дифф.
|
||||
|
||||
### Профиль — максимум по поверхности
|
||||
|
||||
Условия читаются сверху вниз, и **первое подошедшее отвечает за весь дифф**.
|
||||
Профиль изменения это максимум по его поверхности, а не средневзвешенное: одна
|
||||
строка в перечне границ задачи поднимает ступень всему остальному, включая ту
|
||||
часть, которая сама по себе была бы `quick`.
|
||||
|
||||
Отсюда следствие, которое дороже любой настройки триггеров: **цена ревью растёт
|
||||
быстрее размера задачи.** Крупная задача не просто даёт больше диффа — она с
|
||||
высокой вероятностью зацепит верхнее условие и оплатит верхний профиль целиком.
|
||||
|
||||
Обратное тоже верно и тоже не бесплатно: у каждой задачи есть **несокращаемый
|
||||
костяк из четырёх проходов** (гейт, спеки, код, триаж). Разрезать задачу, обе
|
||||
половины которой остаются в одном профиле, — значит заплатить костяк дважды за ту
|
||||
@@ -243,29 +277,33 @@ flowchart TD
|
||||
gate["gate<br/>(стадия 0, держит машину)"]
|
||||
specs["specs"]
|
||||
code["code"]
|
||||
adversary["adversary<br/>(держит машину)"]
|
||||
ops["ops<br/>(держит машину)"]
|
||||
basics["basics<br/>(standard)"]
|
||||
adversary["adversary<br/>(wide, держит машину)"]
|
||||
ops["ops<br/>(wide, держит машину)"]
|
||||
architecture["architecture<br/>(wide)"]
|
||||
triage["triage — единственный сток"]
|
||||
|
||||
gate -->|зелёный| specs
|
||||
gate -->|зелёный| code
|
||||
gate -->|зелёный| adversary
|
||||
gate -->|зелёный| ops
|
||||
gate -->|"зелёный, standard"| basics
|
||||
gate -->|"зелёный, wide"| adversary
|
||||
gate -->|"зелёный, wide"| ops
|
||||
gate -->|"зелёный, wide"| architecture
|
||||
adversary -. один ресурс — машина .- ops
|
||||
specs --> triage
|
||||
code --> triage
|
||||
basics --> triage
|
||||
adversary --> triage
|
||||
ops --> triage
|
||||
architecture --> triage
|
||||
```
|
||||
|
||||
Читается граф так: **всё, у чего входящие рёбра закрыты, уходит одним
|
||||
сообщением**. В `standard` после зелёного гейта это три узла разом — `specs`,
|
||||
`code` и первый из меряющей пары, — а второй меряющий идёт следом за первым. В
|
||||
`wide` к этой тройке добавляется четвёртым `architecture`. В `quick` — `specs` и
|
||||
`code` разом, и сразу триаж.
|
||||
сообщением**. В `quick` после зелёного гейта это `specs` и `code` разом, и сразу
|
||||
триаж. В `standard` к ним третьим добавляется `basics` — все трое уходят одним
|
||||
сообщением, ждать друг друга им нечего. В `wide` вместо `basics` идут три тяжёлых:
|
||||
`architecture` и первый из меряющей пары — сразу, второй меряющий — следом за
|
||||
первым, и он же определяет, когда стартует триаж.
|
||||
|
||||
**Схема здесь старше прозы.** Она не иллюстрация к тексту, а сам алгоритм
|
||||
планировщика; проза ниже объясняет рёбра и называет их цену. Разошлись — прав
|
||||
@@ -292,7 +330,7 @@ flowchart TD
|
||||
| `adversary` | да | находка есть **построенный путь**: он пишет падающий тест и гоняет его |
|
||||
| `ops` | да | доказывает числами: время удержания блокировки, пик кучи, темп роста журнала |
|
||||
| `triage` | да | проверяет оракул `critical`/`major` запуском — но он сток и тоже один |
|
||||
| `specs`, `code`, `architecture`, `rubric` | нет | читают и рассуждают, ничего не исполняют |
|
||||
| `specs`, `code`, `basics`, `architecture`, `rubric` | нет | читают и рассуждают, ничего не исполняют |
|
||||
|
||||
**Правило про ресурс, а не про имена.** Раньше здесь стояло именованное
|
||||
исключение «`adversary` и `ops`»; оно рассыпается, как только проход начнёт
|
||||
@@ -374,7 +412,7 @@ flowchart TD
|
||||
|
||||
Два applicative-прохода: оба применяют **записанный** критерий, оба дешёвые.
|
||||
Машину не держат ни один, ребра между ними нет — уходят одним сообщением сразу
|
||||
после зелёного гейта, вместе со стадией 2, если она в профиле.
|
||||
после зелёного гейта, вместе со стадией 2 или 3 — той, что в профиле.
|
||||
|
||||
- `review-specs` — критерий взят из **дельта-спек предлагаемого изменения**, а не
|
||||
из proposal, сообщения коммита или описания задачи. Сверка двунаправленная;
|
||||
@@ -385,52 +423,84 @@ flowchart TD
|
||||
перечисляет `conventions/README.md` — повторять это проходом вредно.
|
||||
|
||||
Recall обоих равен длине их источника — это и есть предел applicative-проходов,
|
||||
ради которого существует стадия 2.
|
||||
ради которого существуют стадии 2 и 3.
|
||||
|
||||
## Стадия 2 — Adversarial и operational (`standard`, `wide`)
|
||||
## Стадия 2 — Базовый проход (только `standard`)
|
||||
|
||||
Два прохода:
|
||||
Агент `review-basics`. Один проход, машину не держит, ничего не запускает и не
|
||||
меряет — уходит одним сообщением вместе со стадией 1, сразу после зелёного гейта.
|
||||
|
||||
**Он не самостоятельная оптика, а мелкая осадка двух тяжёлых проходов.** Берёт из
|
||||
эксплуатационного — вопросы, на которые отвечают чтением, а не замером: есть ли
|
||||
таймаут и отличит ли отправитель «медленно» от «упало»; идемпотентна ли повторная
|
||||
операция и не теряют ли данные две одновременные; читает ли старый код новую схему
|
||||
после частичного отката; что останется, если процесс остановят между шагами;
|
||||
увидит ли человек, что поток оборвался ночью. Берёт из архитектурного — только то,
|
||||
что видно рядом с диффом: не появился ли **второй способ** делать то, что уже
|
||||
делается, мимо единой точки проекта, и **что опытный человек отсюда удалил бы**.
|
||||
|
||||
Чего он **не** берёт — и это записано в его уставе отдельным разделом: замеров,
|
||||
эксперимента против драйвера и библиотеки, построенного пути атаки, карты проекта,
|
||||
границы домена, направления зависимостей. Всё это стоит машины или входа шире
|
||||
диффа, то есть ровно того, ради чего и существует `wide`.
|
||||
|
||||
**Он покрывает миграцию и публичный контракт на `standard`.** Это не побочный
|
||||
эффект, а условие, при котором миграция схемы вообще может не поднимать ступень:
|
||||
её шаг гоняет `gate`, спеку сверяет `specs`, а вопросы «обратима ли», «что с
|
||||
записями новой версии после отката» задаёт здесь `basics`. Уберёшь его — и
|
||||
`standard` останется без единственного прохода, который смотрит на ось времени.
|
||||
|
||||
Потолок — **4 находки** плюс короткая секция «дешевле переделать до мерджа».
|
||||
Потолок и узкий вход и есть его «среднее усилие»: модель у него верхняя, потому
|
||||
что дешёвая на опиниативном проходе платит триажем (см. «Модель по проходу»).
|
||||
|
||||
## Стадия 3 — Тяжёлые проходы (только `wide`)
|
||||
|
||||
Три прохода, и все три уходят сразу после зелёного гейта, в одном ряду со
|
||||
стадией 1:
|
||||
|
||||
- `review-adversary` — находка есть **построенный путь**, а не свойство;
|
||||
- `review-ops` — постмортем от симптома у владельца сервиса к строке кода.
|
||||
- `review-ops` — постмортем от симптома у владельца сервиса к строке кода;
|
||||
- `review-architecture` — концептуальная целостность на входе шире диффа.
|
||||
|
||||
**Оба помечены «держит машину», поэтому между ними ребро конфликта: они идут
|
||||
цепочкой, а не разом** (правило и его причина — в «Порядок прогона», раздел «Кто
|
||||
держит машину»). Направления у ребра нет: кто первый — неважно. Со стадией 1 они
|
||||
конфликта не имеют и стартуют одновременно с ней; ждать её незачем.
|
||||
**Первые двое помечены «держит машину», поэтому между ними ребро конфликта: они
|
||||
идут цепочкой, а не разом** (правило и его причина — в «Порядок прогона», раздел
|
||||
«Кто держит машину»). Направления у ребра нет: кто первый — неважно.
|
||||
`architecture` машину не держит и ждать ему нечего — он уходит в первой волне.
|
||||
|
||||
Цепочка не отменяется общим «гони по графу» — она и есть часть графа. Отменяет
|
||||
её только прямое слово оператора про эту пару, и тогда в границы покрытия идёт
|
||||
строка, что числа прогона сняты под соседней нагрузкой.
|
||||
|
||||
**Эта стадия зарабатывает больше всех остальных вместе, и потому стоит уже в
|
||||
`standard`, а не только в верхнем профиле.** Измерено на пяти задачах подряд: враждебный
|
||||
проход дал пять из семи выживших находок дозапуска (включая обе верхние);
|
||||
эксплуатационный — единственный, кто нашёл, что откат бинаря поверх новой схемы
|
||||
стартует молча. Оба несут внешний оракул по построению: один обязан путь
|
||||
**прогнать**, второй смотрит ось времени и эксплуатации, которую не смотрит
|
||||
никто другой.
|
||||
**Эта стадия зарабатывает больше всех остальных вместе — и она же дороже всех
|
||||
остальных вместе.** Измерено на пяти задачах подряд: враждебный проход дал пять из
|
||||
семи выживших находок дозапуска (включая обе верхние); эксплуатационный —
|
||||
единственный, кто нашёл, что откат бинаря поверх новой схемы стартует молча. Оба
|
||||
несут внешний оракул по построению: один обязан путь **прогнать**, второй смотрит
|
||||
ось времени и эксплуатации. Ровно поэтому они и стоят денег: оракул добывается
|
||||
запуском, а запуск — это машина, цепочка и часы.
|
||||
|
||||
Раньше эта пара стояла в `standard`, то есть на большинстве задач. Стадия
|
||||
переехала в `wide` **сознательно и по цене, а не потому, что перестала находить**:
|
||||
она осталась самой ценной, но её ценность оплачивается на каждой задаче, а
|
||||
получается — на немногих. Что из-за этого перестало проверяться на нижних
|
||||
ступенях, названо в «Честном пределе» и обязано идти строкой в границы покрытия
|
||||
каждого прогона `quick` и `standard`.
|
||||
|
||||
Материал берётся из документов: `docs/security.md` — враждебному,
|
||||
`docs/architecture.md`, `docs/research/` и `docs/database.md` —
|
||||
эксплуатационному. Что с чем сшивать и почему — [project-facts.md](references/project-facts.md),
|
||||
раздел «Сшивать обязаны проходы». Без этих документов стадия вырождается в общие
|
||||
места.
|
||||
эксплуатационному, `docs/passport.md` и карта проекта — архитектурному. Что с чем
|
||||
сшивать и почему — [project-facts.md](references/project-facts.md), раздел
|
||||
«Сшивать обязаны проходы». Без этих документов стадия вырождается в общие места.
|
||||
|
||||
## Стадия 3 — Global (`wide`, `design`)
|
||||
**Условие стадии и есть условие ступени `wide`:** изменение крупное или
|
||||
незнакомое. У архитектурного прохода работа появляется тогда, когда трогается
|
||||
несколько узлов разом или в проекте становится больше сущностей, чем было; у
|
||||
меряющей пары — когда форму решения нащупывали по ходу, и потому неизвестно, где
|
||||
она протекает. На мелкой правке вопрос «не появился ли второй способ» отвечается
|
||||
«нет» до запуска, а построенный путь строить негде.
|
||||
|
||||
Агент `review-architecture`. Уходит в первой волне, сразу после зелёного гейта, в
|
||||
одном ряду со стадиями 1 и 2. Машину не держит, ждать ему нечего.
|
||||
|
||||
**Условие этой стадии и есть условие ступени `wide`:** изменение вводит новое
|
||||
понятие или структурную единицу. Не «изменение крупное» и не «изменение опасное»:
|
||||
у прохода появляется работа ровно тогда, когда в проекте становится больше
|
||||
сущностей, чем было, — и тогда осмысленны оба его вопроса. На изменении, которое
|
||||
ничего не вводит, вопрос «не появился ли второй способ» отвечается «нет» до
|
||||
запуска, а вопрос «что опытный человек отсюда удалил бы» вырождается во
|
||||
вкусовщину, которую потом отсеивает триаж.
|
||||
|
||||
Получает **вход шире диффа**: дерево пакетов с
|
||||
`review-architecture` получает **вход шире диффа**: дерево пакетов с
|
||||
назначением, граф внутренних зависимостей, инвентарь существующих концепций.
|
||||
Команду, которая это готовит, даёт раздел команд `CLAUDE.md`; нет команды —
|
||||
проход собирает карту сам и говорит об этом в границах покрытия.
|
||||
@@ -470,12 +540,12 @@ Recall обоих равен длине их источника — это и е
|
||||
имеет `proposal.md` и дельта-спеки, но кода ещё нет.
|
||||
|
||||
**Состав здесь тоже не постоянный, и условие то же самое, что у `wide`:**
|
||||
изменение вводит новое понятие или структурную единицу.
|
||||
изменение крупное или незнакомое.
|
||||
|
||||
- **всегда** — `review-specs` в режиме «дизайн ДО кода». Дельта-спеки сверяются
|
||||
на каждой задаче: это самый дешёвый чекпоинт конвейера, и он ловит то, что на
|
||||
готовом коде уже не чинят;
|
||||
- **при новом понятии** — плюс `review-rubric` (фаза 1 без фазы 2: рубрика на
|
||||
- **при крупном или незнакомом** — плюс `review-rubric` (фаза 1 без фазы 2: рубрика на
|
||||
задуманный узел становится приёмочными критериями и уезжает в `tasks.md`) и
|
||||
`review-architecture` на предложении: можно ли выразить существующими понятиями
|
||||
— **включая конструкции стандартной библиотеки**, — не появляется ли второй
|
||||
@@ -486,10 +556,10 @@ Recall обоих равен длине их источника — это и е
|
||||
|
||||
Причина условия — арифметика, а не экономия на осторожности. Чекпоинт стоит
|
||||
**на каждой задаче**, поэтому три прохода здесь умножаются на число задач, и при
|
||||
мелкой нарезке это самая большая статья конвейера. Рубрика же на узел, который не
|
||||
вводит нового понятия, порождает свойства уже существующего рода — те, что и так
|
||||
записаны конвенциями и спеками; а `architecture` без нового понятия отвечает «нет»
|
||||
на свой главный вопрос ещё до запуска (см. «Стадия 3»).
|
||||
мелкой нарезке это самая большая статья конвейера. Рубрика же на узел знакомого
|
||||
рода порождает свойства уже существующего рода — те, что и так записаны
|
||||
конвенциями и спеками; а `architecture` на мелкой правке отвечает «нет» на свой
|
||||
главный вопрос ещё до запуска (см. «Стадия 3»).
|
||||
|
||||
**Граф этого профиля свой, и он плоский.** Гейта нет — кода ещё нет, запускать
|
||||
нечего; машину не держит ни один проход; сток — не триаж, а шаг 5 пайплайна
|
||||
@@ -500,7 +570,7 @@ Recall обоих равен длине их источника — это и е
|
||||
flowchart TD
|
||||
proposal["предложение: proposal.md + дельта-спеки"]
|
||||
specs["specs (режим «дизайн ДО кода») — всегда"]
|
||||
novelty{{"вводит новое понятие<br/>или структурную единицу?"}}
|
||||
novelty{{"изменение крупное<br/>или незнакомое?"}}
|
||||
rubric["rubric, фаза 1 → приёмочные критерии в tasks.md"]
|
||||
arch["architecture на предложении"]
|
||||
author["вопрос автору: три формы решения и компромисс каждой"]
|
||||
@@ -593,7 +663,22 @@ flowchart TD
|
||||
никто. Класс обратимый — портит форму кода, не данные, — и его надо признавать в
|
||||
границах покрытия, а не считать проверенным.
|
||||
|
||||
Так же честно и про второй упразднённый проход: **«не знаю, чего не знаю» больше
|
||||
**На `quick` и `standard` не проверяется ничего, что требует запуска.** Это самая
|
||||
крупная граница покрытия конвейера, и она обязана идти строкой в каждом таком
|
||||
прогоне — поимённо, а не общим «профиль ниже». Не проверяется: построенный путь
|
||||
атаки (его надо прогнать), поведение библиотеки и драйвера в вырожденном случае
|
||||
(достаётся только экспериментом), любое число — время удержания блокировки, пик
|
||||
кучи, темп роста журнала, стоимость на годовой истории. `basics` задаёт часть тех
|
||||
же вопросов **чтением**, и его ответы поэтому слабее: он формулирует условиями,
|
||||
оракула не приносит и выше гипотезы находку не поднимает — кроме той, что
|
||||
опирается на инвариант `CLAUDE.md`.
|
||||
|
||||
Это сознательная сделка, а не пробел в устройстве: цена ступени `wide` платится на
|
||||
каждой задаче, а окупается на немногих. Проверяется сделка не рассуждением, а
|
||||
журналом дефектов: если класс, который ловят только меряющие проходы, начал
|
||||
всплывать после мерджа — ступень выбирают слишком низко.
|
||||
|
||||
Так же честно и про упразднённый проход: **«не знаю, чего не знаю» больше
|
||||
не достаёт никто.** Проход независимой реализации писал свою версию узла, не
|
||||
открывая существующую, и диффил по решениям — декомпозиция, владение данными,
|
||||
модель конкурентности, форма решения там, где спека выбора не сделала. Он снят по
|
||||
|
||||
@@ -83,6 +83,7 @@ stateDiagram-v2
|
||||
| `review-specs` | поведение вне спеки | добавить незаказанный фолбэк-дефолт на пустом входе |
|
||||
| `review-code` | нарушение прозаической конвенции | увести штатный отказ мимо единой точки трансляции ошибки |
|
||||
| `review-rubric` | нарушенное свойство узла | у клиента внешнего сервиса убрать таймаут и протяжку `context` |
|
||||
| `review-basics` | отказ, видимый чтением | убрать обработку ошибки записи так, чтобы отказ считался успехом |
|
||||
| `review-architecture` | второй способ | завести вторую точку генерации id мимо единой |
|
||||
| `review-adversary` | построенный путь | принять внешний идентификатор без разбора до запроса в хранилище |
|
||||
| `review-ops` | деградация окружения | убрать обработку недоступности внешней зависимости в фоновом цикле |
|
||||
|
||||
@@ -47,6 +47,13 @@
|
||||
нет — она **выводится по обратимости последствия** и помечается «выведена по
|
||||
обратимости», а не выдаётся за решение проекта.
|
||||
|
||||
**У `basics` стыков нет, и это не упущение.** Он не меряет, поэтому сшивать число
|
||||
с настройкой ему нечего; единственное его основание для `critical` — инвариант из
|
||||
`CLAUDE.md`, всё остальное он формулирует условиями и оставляет гипотезой. Его
|
||||
вход намеренно узкий: единые точки и внешние зависимости из `docs/architecture.md`,
|
||||
инварианты из `CLAUDE.md`, журнал из `docs/review.md`. Широкий вход — это профиль
|
||||
`wide`, и там он есть у `architecture`.
|
||||
|
||||
## Деградация — поразрядная
|
||||
|
||||
Документа нет — деградирует то, что из него читалось, и **только оно**. Каждый
|
||||
@@ -67,7 +74,7 @@
|
||||
| `docs/database.md` | замер не с чем сравнить: находка не поднимается выше гипотезы |
|
||||
| `docs/passport.md` | `architecture` теряет границу домена и вырождается в общее мнение |
|
||||
| `docs/review.md` | `triage` отсеивает вслепую: типовых ложноположительных нет |
|
||||
| `docs/architecture.md` | «не появился ли второй способ» не проверяется — единых точек не знает никто |
|
||||
| `docs/architecture.md` | «не появился ли второй способ» не проверяется — единых точек не знает никто; `basics` теряет ещё и перечень внешних зависимостей |
|
||||
|
||||
Строка в границах покрытия обязана называть **причину**: «`docs/security.md` в
|
||||
проекте нет» читается иначе, чем «есть, но периметр не назван». Без причины
|
||||
|
||||
@@ -116,7 +116,11 @@ description: Проводит несколько задач разом — пл
|
||||
|
||||
Ни один триггер не сработал — задача не замеряющая, даже если её ревью
|
||||
окажется `wide`. Профиль про глубину проверки, замеряющая — про соревнование за
|
||||
железо; это разные вопросы, и совпадают они не всегда;
|
||||
железо; это разные вопросы, и совпадают они не всегда. Обратное тоже бывает и
|
||||
тоже законно: помеченная задача, чьё ревью пошло профилем `quick` или
|
||||
`standard`, машину не займёт вовсе — меряющие проходы живут только в `wide`.
|
||||
Пометка от этого не снимается: она ставится **до** выбора профиля, и
|
||||
перестраховка здесь стоит одной волны, а ошибка — испорченных чисел;
|
||||
- **нумерованные артефакты — номера раздаёт оркестратор заранее.** Если проект
|
||||
нумерует миграции (путь — `docs/.pm.json`, ключ `migrations`), посмотри последний
|
||||
номер и **раздай номера всем задачам, которые, вероятно, их добавят**, до
|
||||
|
||||
@@ -223,8 +223,8 @@ flowchart TD
|
||||
|
||||
**Состав чекпоинта решает конвейер, а не ты**: `review-specs` в режиме «дизайн ДО
|
||||
кода» идёт всегда, а `review-rubric` и `review-architecture` — только когда
|
||||
изменение вводит новое понятие или структурную единицу (то же условие, что у
|
||||
ступени `wide`). Причина в том, что чекпоинт стоит на **каждой** задаче: при
|
||||
изменение крупное или незнакомое (то же условие, что у ступени `wide`, и та же
|
||||
доля — 5–10% задач). Причина в том, что чекпоинт стоит на **каждой** задаче: при
|
||||
мелкой нарезке три прохода здесь умножаются на число задач и становятся самой
|
||||
большой статьёй конвейера.
|
||||
|
||||
|
||||
@@ -232,11 +232,12 @@ kebab-case.** Причина не эстетическая: имя файла с
|
||||
- **Вопросы к проходам** — поимённо, в форме `<имя прохода>: <вопрос>
|
||||
(<провенанс>)`;
|
||||
- **Триггеры профиля** — проектная конкретизация правила выбора профиля ревью:
|
||||
что в этом проекте считается **новым понятием или структурной единицей** — это
|
||||
поднимает прогон до `wide`, верхней ступени. Перечнем мест, а не вторым
|
||||
определением класса. Уточняет умолчания, а не отменяет их. Рабочее умолчание —
|
||||
`standard`: миграция схемы и публичный контракт ступень **не** поднимают, их
|
||||
проверяют проходы, которые в `standard` и так есть;
|
||||
что в этом проекте считается **крупным или незнакомым** изменением (поднимает
|
||||
прогон до `wide`, верхней ступени, — и она рассчитана на 5–10% задач) и что
|
||||
считается **мелким** (опускает до `quick`). Перечнем мест, узлами или
|
||||
capability, а не вторым определением класса. Уточняет умолчания, а не отменяет
|
||||
их. Рабочее умолчание — `standard`: миграция схемы и публичный контракт ступень
|
||||
**не** поднимают, их проверяют проходы, которые в `standard` и так есть;
|
||||
- **Недоступно проверке** — два подраздела: «не проверит ни один проход»
|
||||
(принципиальная граница, по факту промаха не пересматривается) и «перестали
|
||||
проверять сознательно» (пересматривается первым).
|
||||
|
||||
@@ -127,13 +127,17 @@ upgrade` идёт по записям снизу вверх от версии п
|
||||
человека. **Переименование ADR это перенос ссылок**: слаг стоит в
|
||||
`adr/README.md`, в `architecture.md` и в чужих документах, и делается одним
|
||||
проходом, иначе останутся битые ссылки (их `docs.py` потом и покажет).
|
||||
8. `docs/review.md`, подраздел «Триггеры профиля»: снести перечень мест для
|
||||
`deep` — профиль упразднён вместе с проходом независимой реализации, и
|
||||
перечень стал указателем в пустоту. Перечень для `wide` (новое понятие или
|
||||
структурная единица) остаётся: он и поднимает прогон до верхней ступени. Там
|
||||
же проверить журнал дефектов и «Недоступно проверке» на упоминания
|
||||
независимой реализации: класс «форма решения, где спека выбора не сделала»
|
||||
переезжает в подраздел «перестали проверять сознательно».
|
||||
8. `docs/review.md`, подраздел «Триггеры профиля» — переписать целиком, он
|
||||
отстал дважды. Снести перечень мест для `deep`: профиль упразднён вместе с
|
||||
проходом независимой реализации, и перечень стал указателем в пустоту.
|
||||
Оставшийся перечень перевести на новое правило: `wide` теперь означает не
|
||||
«новое понятие», а **крупное или незнакомое** изменение и рассчитан на 5–10%
|
||||
задач; отдельным списком назвать, что здесь считается **мелким** (это `quick`).
|
||||
Форма подраздела — в [skeletons.md](skeletons.md). Там же проверить журнал
|
||||
дефектов и «Недоступно проверке» на упоминания независимой реализации: класс
|
||||
«форма решения, где спека выбора не сделала» переезжает в подраздел «перестали
|
||||
проверять сознательно», а рядом с ним встаёт вторая честная строка — на
|
||||
`quick` и `standard` не проверяется ничего, что требует запуска.
|
||||
9. `docs/.pm.json`: `"canon": 4`.
|
||||
10. Позвать **обоих судей** — `doc-consistency` и `doc-code-drift`, шагом 6
|
||||
`upgrade`. Пунктов выше десять, половина из них ручная, и именно здесь видно,
|
||||
|
||||
@@ -283,11 +283,19 @@
|
||||
|
||||
### Триггеры профиля
|
||||
|
||||
Проектная конкретизация правила выбора профиля: что здесь считается **новым
|
||||
понятием или структурной единицей** — это поднимает прогон до `wide`, верхней
|
||||
ступени, и запускает архитектурный проход. Перечнем узлов или capability,
|
||||
поимённо. Уточняет умолчания конвейера, не отменяет их; рабочее умолчание —
|
||||
`standard`.
|
||||
Проектная конкретизация правила выбора профиля, двумя списками и поимённо —
|
||||
узлами или capability.
|
||||
|
||||
**Крупное или незнакомое здесь** — поднимает прогон до `wide`, верхней ступени:
|
||||
там идут враждебный, эксплуатационный и архитектурный проходы, и там же
|
||||
единственные замеры. Ступень рассчитана на **5–10% задач**; если сюда попадает
|
||||
каждая третья, список написан слишком широко.
|
||||
|
||||
**Мелкое здесь** — опускает до `quick`. Помни отрицательный тест конвейера: что
|
||||
после мерджа не откатывается обратной правкой (миграция, формат на диске,
|
||||
публичный контракт, имя), — не `quick`, каким бы маленьким ни был дифф.
|
||||
|
||||
Уточняет умолчания конвейера, не отменяет их; рабочее умолчание — `standard`.
|
||||
|
||||
### Недоступно проверке
|
||||
|
||||
|
||||
@@ -27,9 +27,10 @@
|
||||
|
||||
**Шов — там, где падает ступень ревью.** Раздел «Затрагивает» перечисляет
|
||||
границы; если одна строка перечня поднимает ступень выше остальных, эта часть и
|
||||
режется отдельно. Пример: задача вводит новый пакет и заодно добавляет два поля в
|
||||
существующий ответ. Целиком это `wide` — семь проходов по всему диффу. Разрезанная
|
||||
по шву, она даёт `wide` на маленьком новом пакете и `standard` на остатке.
|
||||
режется отдельно. Пример: задача перекладывает несколько узлов разом и заодно
|
||||
добавляет два поля в существующий ответ. Целиком это `wide` — семь проходов по
|
||||
всему диффу, включая два, что держат машину и идут цепочкой. Разрезанная по шву,
|
||||
она даёт `wide` на маленькой переложенной части и `standard` на остатке.
|
||||
|
||||
**Считай костяк, а не файлы.** У каждой задачи есть несокращаемые четыре прохода
|
||||
(гейт, спеки, код, триаж), и они платятся за каждую. Разрез, после которого обе
|
||||
|
||||
Reference in New Issue
Block a user