- DECISIONS.md (4040 строк, 65 тем) → decisions/, файл на тему плюс указатель; - буквенные метки решений заменены сквозными Р1–Р234, следствия получили префикс С при прежних номерах: схема букв выродилась до пятибуквенных и сломалась — `АЕАКЛ` была занята и темой 53, и темой 65; - 42 перекрёстные ссылки переписаны под новые номера и стали живыми; где номер означал тему, а слово стояло «решение», формулировка исправлена.
10 KiB
18. Ступень поднимает проход, а не риск (2026-08-04)
Что было
Наблюдение с живых проектов: полный набор проходов гоняется чаще, чем оправдано — архитектура и независимая реализация нужны заметно реже, чем запускаются. Развилка названа сразу: крупные задачи с частым полным ревью либо мелкие и средние задачи со средним ревью. Выбран второй путь.
Разбор показал, что размер задач — только половина причины, и не главная.
Решено
Р70. Профиль — максимум по поверхности, а не средневзвешенное. Условия
читаются сверху вниз, первое подошедшее отвечает за весь дифф. Значит цена ревью
растёт быстрее размера задачи: на крупной задаче верхний профиль оплачивается в
том числе за ту её часть, которая сама по себе была бы quick. Это и есть
механизм, ради которого выбран путь мелких задач.
Р71. Ступень поднимает то, что даёт работу новому проходу, а не то, что кажется рискованным. Правило вывода, по которому спорные случаи решаются без нового списка. Проверка нынешних триггеров этим правилом:
| Триггер | Кто закрывает | Где этот проход |
|---|---|---|
| миграция схемы | gate (шаг миграций), ops (миграция под потоком, откат при двух версиях) |
уже в standard |
| публичный контракт | specs, направление code → spec |
во всех профилях |
| инвариант проекта | основание для critical у любого прохода |
во всех |
| новый пакет, новое понятие | architecture |
только wide |
| новое правило слияния | reimpl |
только deep |
Три верхних триггера не добавляли ни одного прохода — они поднимали ступень «на всякий случай». На проекте с базой и эндпоинтами это делало верхнюю ступень умолчанием, то есть правило объявляло исключением то, что происходит всегда.
Р72. Миграция схемы, публичный контракт и инвариант уехали в standard.
wide теперь означает ровно одно: изменение вводит новое понятие или
структурную единицу — новый пакет или слой, новая точка входа, второй способ
делать то, что уже делается, перенос ответственности между узлами. Добавленное
поле в существующем ответе концептом не является. Это отменяет часть JJJ темы
17: ступень wide остаётся, её содержание меняется. Проект, где изменение
контракта и правда архитектурное (публичный SDK, чужие потребители), поднимает
его сам в docs/review.md — уточнением, а не возвратом прежнего умолчания.
Р73. Чекпоинт design получил то же условие. review-specs в режиме
«дизайн ДО кода» идёт всегда — это самый дешёвый чекпоинт конвейера.
review-rubric и review-architecture — только при новом понятии. Причина
арифметическая: чекпоинт стоит на каждой задаче, поэтому при мелкой нарезке
три прохода умножаются на число задач и становятся самой большой статьёй.
Причина по существу та же, что в SSS: рубрика на узел без нового понятия
порождает свойства уже существующего рода, записанные конвенциями и спеками.
Р74. Шов нарезки — граница, за которой падает ступень. Тест декомпозиции отвечает, допустим ли разрез; шов отвечает, где его провести. Раздел «Затрагивает» перечисляет границы; строка, поднимающая ступень выше остальных, и есть кандидат на отдельную задачу.
Р75. Костяк из четырёх проходов платится за каждую задачу. Гейт, спеки, код, триаж несокращаемы, поэтому разрез, после которого обе половины остаются в одной ступени, делает ревью дороже: тот же объём тем же составом, но костяк оплачен дважды. Резать — когда разрез снимает дорогой проход с большей части диффа.
Р76. Верхняя ступень задана тестом, а не списком. «Идентичность, слияние,
разбор» — формулировка, пришедшая из одного проекта, и в общем виде она не
читалась: вопрос «как это применить к моему проекту» не имел ответа в тексте.
Теперь класс задан тремя условиями, независимыми от домена и языка: вариантов
несколько и оба защитимы; спека между ними не выбирает; неверный выбор не
падает, а молча меняет смысл данных. Отрицательный тест сильнее положительных —
то, что красит гейт или роняет запрос, в класс не входит. Три слова остались как
три места, где такие правила водятся (граница входа данных и место их
встречи), а проект перечисляет свои места в docs/review.md — перечень
производен от теста и не расширяет класс.
Оговорка, без которой правило вырождается: триггер — новое или изменённое по
существу правило, а не код рядом с ним. Проект, чей домен и состоит из таких
правил, иначе оказывался бы в deep всегда — та же болезнь, от которой лечилась
ступень wide.
Что из этого следует
С72. Порога в числе границ не заводится. Тот же принцип, что в теме 16 (Р55): размер не триггер. Шов проходит по скачку ступени, а не по длине перечня.
С73. Ступень — признак для планирования, но не запись в задаче. Строка «делать профилем standard» в теле — тот самый второй дом правила выбора, который снимает гигиена полей. Профиль выбирает тот, кто видит изменение.
С74. Дешёвое место заметить разнородную задачу — показ набора спринта. Там
«Затрагивает» уже написан, а предложение об изменении ещё не заведено: разрез
стоит одного edit вместо выброшенного предложения.
С75. Замер остаётся за обкаткой. Правило выведено из состава проходов, а не из статистики прогонов: считать, какая доля задач попадает в каждую ступень, можно только на спринтах нового процесса (TODO шаг 4).
С76. Отсутствие верхней ступени — законное состояние проекта. Бывают
проекты, где данные приходят нормализованными, ничего ни с чем не сливается, а
внешних форматов нет: deep там не срабатывает никогда, и придумывать ему повод
не надо. Раньше это читалось как недонастройка.
С77. Ступень определяет класс правила, а не вид работы. Миграция схемы —
standard, но миграция, переносящая данные по правилу («сложить дубли»,
«привести к одному виду перед сравнением»), несёт правило идентичности и потому
deep. Одно слово в описании задачи попадает в разные ступени — это не
противоречие, смотрят не на слово.