diff --git a/DECISIONS.md b/DECISIONS.md index 1088f49..fd26301 100644 --- a/DECISIONS.md +++ b/DECISIONS.md @@ -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. **Ступень, выбираемая по классу изменения, слепа к объёму.** Правило, + запрещавшее смотреть на размер, защищало от выбора по ощущению важности — и + заодно отправляло трёхстрочную правку и переборку пяти узлов в один профиль. + Признаков нужно два: класс отвечает за обратимость, объём — за цену + разбирательства. diff --git a/README.md b/README.md index bae25f1..4c2dba4 100644 --- a/README.md +++ b/README.md @@ -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-`, имена diff --git a/TODO.md b/TODO.md index 9246fe4..48fb3f2 100644 --- a/TODO.md +++ b/TODO.md @@ -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`) diff --git a/av-dev-pipeline/agents/review-adversary.md b/av-dev-pipeline/agents/review-adversary.md index e382011..0f5391f 100644 --- a/av-dev-pipeline/agents/review-adversary.md +++ b/av-dev-pipeline/agents/review-adversary.md @@ -22,6 +22,14 @@ color: yellow падающий тест, которым ты доказываешь путь, воспроизводим — и ссылка на него законный оракул. +**Тебя запускают только в профиле `wide`** — на изменении крупном или незнакомом, +и это 5–10% задач. Причина в цене прогона, а не в ценности находок: ты держишь +машину и идёшь цепочкой, то есть стоишь часов на каждой задаче, где запущен. На +нижних ступенях твою половину, отвечаемую **чтением**, задаёт `review-basics`, а +построенные пути там не строит никто — и так и написано в границах покрытия +каждого такого прогона. Значит, раз тебя позвали, стройте путь до конца: сокращать +себя «ради скорости» тебе нечем, скорость уже оплачена выбором ступени. + ## Модель угроз — из `docs/security.md`, и не расширяй её самовольно **Первая строка `docs/security.md` — периметр,** и она задаёт смысл всему diff --git a/av-dev-pipeline/agents/review-architecture.md b/av-dev-pipeline/agents/review-architecture.md index 1fa8249..3b20fba 100644 --- a/av-dev-pipeline/agents/review-architecture.md +++ b/av-dev-pipeline/agents/review-architecture.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` diff --git a/av-dev-pipeline/agents/review-basics.md b/av-dev-pipeline/agents/review-basics.md new file mode 100644 index 0000000..ebb29f5 --- /dev/null +++ b/av-dev-pipeline/agents/review-basics.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`, перечисление +файлов. Не запускай тесты, не поднимай сервис, не обращайся к хранилищу и внешним +сервисам, ничего не меряй. Код и спеки не редактируй. diff --git a/av-dev-pipeline/agents/review-code.md b/av-dev-pipeline/agents/review-code.md index 45f7941..842d07b 100644 --- a/av-dev-pipeline/agents/review-code.md +++ b/av-dev-pipeline/agents/review-code.md @@ -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`. Видишь такое — не выводи находкой; максимум упомяни строкой в границах покрытия, diff --git a/av-dev-pipeline/agents/review-ops.md b/av-dev-pipeline/agents/review-ops.md index 09fb489..1e5bbe1 100644 --- a/av-dev-pipeline/agents/review-ops.md +++ b/av-dev-pipeline/agents/review-ops.md @@ -20,6 +20,15 @@ color: green её надо назвать, а не списать на соседа. Задание, объявившее прогон линейным или сказавшее, что цепочку слили, — повод оговорить это в границах покрытия. +**Тебя запускают только в профиле `wide`** — на изменении крупном или незнакомом, +и это 5–10% задач. На нижних ступенях шесть твоих вопросов, на которые отвечают +чтением (отказ соседа, повтор и одновременность, остановка на середине, частичный +откат, наблюдаемость, очевидный рост), задаёт `review-basics` — **без замеров и +без запуска**. Тебя же зовут ровно за тем, чего он не может: **число и +эксперимент**. Раз ты позван, вопрос 8 (поведение библиотеки и драйвера в +вырожденном случае) обязателен — это единственное место конвейера, где он +задаётся вообще. + ## Что такое «прод» здесь — из документов проекта **`docs/architecture.md`, раздел эксплуатации:** где это работает и что рядом; diff --git a/av-dev-pipeline/skills/review-pipeline/SKILL.md b/av-dev-pipeline/skills/review-pipeline/SKILL.md index c325cc3..c907805 100644 --- a/av-dev-pipeline/skills/review-pipeline/SKILL.md +++ b/av-dev-pipeline/skills/review-pipeline/SKILL.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
(стадия 0, держит машину)"] specs["specs"] code["code"] - adversary["adversary
(держит машину)"] - ops["ops
(держит машину)"] + basics["basics
(standard)"] + adversary["adversary
(wide, держит машину)"] + ops["ops
(wide, держит машину)"] architecture["architecture
(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{{"вводит новое понятие
или структурную единицу?"}} + novelty{{"изменение крупное
или незнакомое?"}} rubric["rubric, фаза 1 → приёмочные критерии в tasks.md"] arch["architecture на предложении"] author["вопрос автору: три формы решения и компромисс каждой"] @@ -593,7 +663,22 @@ flowchart TD никто. Класс обратимый — портит форму кода, не данные, — и его надо признавать в границах покрытия, а не считать проверенным. -Так же честно и про второй упразднённый проход: **«не знаю, чего не знаю» больше +**На `quick` и `standard` не проверяется ничего, что требует запуска.** Это самая +крупная граница покрытия конвейера, и она обязана идти строкой в каждом таком +прогоне — поимённо, а не общим «профиль ниже». Не проверяется: построенный путь +атаки (его надо прогнать), поведение библиотеки и драйвера в вырожденном случае +(достаётся только экспериментом), любое число — время удержания блокировки, пик +кучи, темп роста журнала, стоимость на годовой истории. `basics` задаёт часть тех +же вопросов **чтением**, и его ответы поэтому слабее: он формулирует условиями, +оракула не приносит и выше гипотезы находку не поднимает — кроме той, что +опирается на инвариант `CLAUDE.md`. + +Это сознательная сделка, а не пробел в устройстве: цена ступени `wide` платится на +каждой задаче, а окупается на немногих. Проверяется сделка не рассуждением, а +журналом дефектов: если класс, который ловят только меряющие проходы, начал +всплывать после мерджа — ступень выбирают слишком низко. + +Так же честно и про упразднённый проход: **«не знаю, чего не знаю» больше не достаёт никто.** Проход независимой реализации писал свою версию узла, не открывая существующую, и диффил по решениям — декомпозиция, владение данными, модель конкурентности, форма решения там, где спека выбора не сделала. Он снят по diff --git a/av-dev-pipeline/skills/review-pipeline/references/calibration.md b/av-dev-pipeline/skills/review-pipeline/references/calibration.md index 6ba3619..72ea9c5 100644 --- a/av-dev-pipeline/skills/review-pipeline/references/calibration.md +++ b/av-dev-pipeline/skills/review-pipeline/references/calibration.md @@ -83,6 +83,7 @@ stateDiagram-v2 | `review-specs` | поведение вне спеки | добавить незаказанный фолбэк-дефолт на пустом входе | | `review-code` | нарушение прозаической конвенции | увести штатный отказ мимо единой точки трансляции ошибки | | `review-rubric` | нарушенное свойство узла | у клиента внешнего сервиса убрать таймаут и протяжку `context` | +| `review-basics` | отказ, видимый чтением | убрать обработку ошибки записи так, чтобы отказ считался успехом | | `review-architecture` | второй способ | завести вторую точку генерации id мимо единой | | `review-adversary` | построенный путь | принять внешний идентификатор без разбора до запроса в хранилище | | `review-ops` | деградация окружения | убрать обработку недоступности внешней зависимости в фоновом цикле | diff --git a/av-dev-pipeline/skills/review-pipeline/references/project-facts.md b/av-dev-pipeline/skills/review-pipeline/references/project-facts.md index 6f01a5d..fad7018 100644 --- a/av-dev-pipeline/skills/review-pipeline/references/project-facts.md +++ b/av-dev-pipeline/skills/review-pipeline/references/project-facts.md @@ -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` в проекте нет» читается иначе, чем «есть, но периметр не назван». Без причины diff --git a/av-dev-pipeline/skills/task-batch/SKILL.md b/av-dev-pipeline/skills/task-batch/SKILL.md index 201b247..bd113a6 100644 --- a/av-dev-pipeline/skills/task-batch/SKILL.md +++ b/av-dev-pipeline/skills/task-batch/SKILL.md @@ -116,7 +116,11 @@ description: Проводит несколько задач разом — пл Ни один триггер не сработал — задача не замеряющая, даже если её ревью окажется `wide`. Профиль про глубину проверки, замеряющая — про соревнование за - железо; это разные вопросы, и совпадают они не всегда; + железо; это разные вопросы, и совпадают они не всегда. Обратное тоже бывает и + тоже законно: помеченная задача, чьё ревью пошло профилем `quick` или + `standard`, машину не займёт вовсе — меряющие проходы живут только в `wide`. + Пометка от этого не снимается: она ставится **до** выбора профиля, и + перестраховка здесь стоит одной волны, а ошибка — испорченных чисел; - **нумерованные артефакты — номера раздаёт оркестратор заранее.** Если проект нумерует миграции (путь — `docs/.pm.json`, ключ `migrations`), посмотри последний номер и **раздай номера всем задачам, которые, вероятно, их добавят**, до diff --git a/av-dev-pipeline/skills/task-pipeline/SKILL.md b/av-dev-pipeline/skills/task-pipeline/SKILL.md index 63d9627..827fa7d 100644 --- a/av-dev-pipeline/skills/task-pipeline/SKILL.md +++ b/av-dev-pipeline/skills/task-pipeline/SKILL.md @@ -223,8 +223,8 @@ flowchart TD **Состав чекпоинта решает конвейер, а не ты**: `review-specs` в режиме «дизайн ДО кода» идёт всегда, а `review-rubric` и `review-architecture` — только когда -изменение вводит новое понятие или структурную единицу (то же условие, что у -ступени `wide`). Причина в том, что чекпоинт стоит на **каждой** задаче: при +изменение крупное или незнакомое (то же условие, что у ступени `wide`, и та же +доля — 5–10% задач). Причина в том, что чекпоинт стоит на **каждой** задаче: при мелкой нарезке три прохода здесь умножаются на число задач и становятся самой большой статьёй конвейера. diff --git a/av-dev-pm/skills/canon/references/canon.md b/av-dev-pm/skills/canon/references/canon.md index 87a6ebc..f1b63e9 100644 --- a/av-dev-pm/skills/canon/references/canon.md +++ b/av-dev-pm/skills/canon/references/canon.md @@ -232,11 +232,12 @@ kebab-case.** Причина не эстетическая: имя файла с - **Вопросы к проходам** — поимённо, в форме `<имя прохода>: <вопрос> (<провенанс>)`; - **Триггеры профиля** — проектная конкретизация правила выбора профиля ревью: - что в этом проекте считается **новым понятием или структурной единицей** — это - поднимает прогон до `wide`, верхней ступени. Перечнем мест, а не вторым - определением класса. Уточняет умолчания, а не отменяет их. Рабочее умолчание — - `standard`: миграция схемы и публичный контракт ступень **не** поднимают, их - проверяют проходы, которые в `standard` и так есть; + что в этом проекте считается **крупным или незнакомым** изменением (поднимает + прогон до `wide`, верхней ступени, — и она рассчитана на 5–10% задач) и что + считается **мелким** (опускает до `quick`). Перечнем мест, узлами или + capability, а не вторым определением класса. Уточняет умолчания, а не отменяет + их. Рабочее умолчание — `standard`: миграция схемы и публичный контракт ступень + **не** поднимают, их проверяют проходы, которые в `standard` и так есть; - **Недоступно проверке** — два подраздела: «не проверит ни один проход» (принципиальная граница, по факту промаха не пересматривается) и «перестали проверять сознательно» (пересматривается первым). diff --git a/av-dev-pm/skills/canon/references/changelog.md b/av-dev-pm/skills/canon/references/changelog.md index 0e56b65..192427f 100644 --- a/av-dev-pm/skills/canon/references/changelog.md +++ b/av-dev-pm/skills/canon/references/changelog.md @@ -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`. Пунктов выше десять, половина из них ручная, и именно здесь видно, diff --git a/av-dev-pm/skills/canon/references/skeletons.md b/av-dev-pm/skills/canon/references/skeletons.md index efa2a49..ae3dd77 100644 --- a/av-dev-pm/skills/canon/references/skeletons.md +++ b/av-dev-pm/skills/canon/references/skeletons.md @@ -283,11 +283,19 @@ ### Триггеры профиля -Проектная конкретизация правила выбора профиля: что здесь считается **новым -понятием или структурной единицей** — это поднимает прогон до `wide`, верхней -ступени, и запускает архитектурный проход. Перечнем узлов или capability, -поимённо. Уточняет умолчания конвейера, не отменяет их; рабочее умолчание — -`standard`. +Проектная конкретизация правила выбора профиля, двумя списками и поимённо — +узлами или capability. + +**Крупное или незнакомое здесь** — поднимает прогон до `wide`, верхней ступени: +там идут враждебный, эксплуатационный и архитектурный проходы, и там же +единственные замеры. Ступень рассчитана на **5–10% задач**; если сюда попадает +каждая третья, список написан слишком широко. + +**Мелкое здесь** — опускает до `quick`. Помни отрицательный тест конвейера: что +после мерджа не откатывается обратной правкой (миграция, формат на диске, +публичный контракт, имя), — не `quick`, каким бы маленьким ни был дифф. + +Уточняет умолчания конвейера, не отменяет их; рабочее умолчание — `standard`. ### Недоступно проверке diff --git a/av-dev-pm/skills/tasks/references/split.md b/av-dev-pm/skills/tasks/references/split.md index c3e7e89..53dc115 100644 --- a/av-dev-pm/skills/tasks/references/split.md +++ b/av-dev-pm/skills/tasks/references/split.md @@ -27,9 +27,10 @@ **Шов — там, где падает ступень ревью.** Раздел «Затрагивает» перечисляет границы; если одна строка перечня поднимает ступень выше остальных, эта часть и -режется отдельно. Пример: задача вводит новый пакет и заодно добавляет два поля в -существующий ответ. Целиком это `wide` — семь проходов по всему диффу. Разрезанная -по шву, она даёт `wide` на маленьком новом пакете и `standard` на остатке. +режется отдельно. Пример: задача перекладывает несколько узлов разом и заодно +добавляет два поля в существующий ответ. Целиком это `wide` — семь проходов по +всему диффу, включая два, что держат машину и идут цепочкой. Разрезанная по шву, +она даёт `wide` на маленькой переложенной части и `standard` на остатке. **Считай костяк, а не файлы.** У каждой задачи есть несокращаемые четыре прохода (гейт, спеки, код, триаж), и они платятся за каждую. Разрез, после которого обе