Канон 5 объявил «каждый документ docs/ — тема ревью». Правило верно ровно наполовину и потому вредно целиком. Паспорт и схему хранилища ревью читает, но темами они не являются: по ним нельзя сказать «в этом изменении сделано не так», они задают границу, по которой судит чужая тема. Журнал решений и журнал наблюдений ревью изменения не нужны вовсе — ADR объясняет прошлое, а не предъявляет требование. Разметчик, применявший правило буквально, обязан был либо завести фантомные темы passport, adr, database, research и продублировать ими работу architecture и operations, либо потерять четыре документа молча; случались обе ветки, и в собственном образце плана docs/passport.md не попадал ни строкой, а обязательная арифметика покрытия при этом не сходилась. Категорий теперь три, разрез проверяемый. Тема — да, прямо: conventions, security, architecture и любой свой документ проекта. Источник темы — нет, но он задаёт границу для чужой: passport, database, CLAUDE.md, openspec/specs. Процессный — нет, он про то, как мы работаем: tasks, review, adr, research, .pm.json. Открыта одна категория из трёх, две другие перечислены поимённо, так что документ вне раскладки — однозначно своя тема. adr и research прогон больше не открывает ни одним проходом; docs/review остаётся читаемым, но как настройка конвейера, а не критерий. Цена записана и стала обязательной строкой границ покрытия: расхождение с записанным решением ловит теперь только сверка документации, а число под находкой обязано быть снято на этом прогоне, с приложенной командой. Классификация выдаёт задаче метку — small, medium, large. Прежние quick, standard и wide назывались ступенью и описывали ревью: как глубоко смотрим. Классифицируется же задача, и пока величина называлась свойством прогона, её естественно было пересчитывать на каждом прогоне — что конвейер и делал. Слово «ступень» удалено, а не оставлено синонимом: два имени одной вещи расходятся. Выводится метка из двух разведённых осей — размер (малое, среднее, крупное) и сложность (знакомое, незнакомое), — и равна максимуму по ним. Метка не синоним размера: малое незнакомое изменение получает large, трогая один узел, поэтому план печатает три строки с обоснованием каждая и выводить одну из другой запрещено. Оси остались русскими словами — это суждение прозой; метка английская — это идентификатор, который проходы сравнивают. Разметка переехала из ревью кода в шаг 4 пайплайна, сразу после propose. Она шла первым проходом каждого ревью кода, а перед ревью дизайна ту же величину называл сам пайплайн — то есть оркестратор, который только что довёл предложение до propose. Одно и то же измерялось дважды, и один из двух раз без разведённости с автором, ровно в той точке, ради которой разметчик заведён. Теперь запуск один на задачу, диффа он не видит, план обслуживает обе стадии, и метка после кода не пересматривается: расхождение факта с разметкой ловит журнал дефектов постфактум, как и всякую другую ошибку выбора. На диск план не пишется — четвёртый артефакт рядом с proposal, tasks и design пережил бы задачу и разошёлся бы с ней молча. Ревью дизайна тоже растёт меткой: small — specs, medium — плюс rubric, large — плюс architecture и вопрос автору о трёх формах решения. Раньше rubric и architecture включались одним условием, и medium получал ровно один проход, то есть не отличался от quick ничем. Разведены они потому, что зарабатывают на разном: рубрика порождает свойства узла и окупается уже на среднем изменении, её выход уезжает приёмочными критериями в tasks.md; архитектура отвечает на вопрос про второй способ, а он на среднем знакомом изменении отвечается «нет» ещё до запуска. small подешевел тремя способами сразу. Составом: приёмник тем не запускается, три темы ядра переходят к code сверкой по записанным инвариантам CLAUDE.md с потолком в одну находку, и это не «глубина ниже», а другой дом темы. Входом: specs читает только дельта-спеку, code — только индекс конвенций. Потолком: он появился у каждого опиниативного прохода, а не у одного basics, и у половин code он раздельный, потому что конвенционных находок больше по построению и в общем списке они вытеснили бы техническую половину. Сработавший потолок обязан быть объявлен строкой — молчащий срез неотличим от «больше не нашлось». Отрицательный тест small от этого стал жёстче, а не мягче: вопросы про обратимость миграции задавал приёмник тем, и на этой метке их не задаст никто. Пайплайн задачи вырос до двенадцати шагов. Тривиальность перестала решать состав ревью — она влияет только на explore; глубину обеих стадий называет метка. Проверено прогоном ревьюверов по готовому результату: девять расхождений найдено и починено — контракт находок печатал старый перечень проходов вместо плана по темам, три ссылки в task-batch указывали на шаг коммита вместо закрытия, запись changelog не переводила вопросы, адресованные passport и database, ops и adversary утверждали, что на нижних метках их вопросы задаёт basics, шаблон покрытия в review-code зашивал потолки small намертво, триггеры метки рассыпались на два списка против трёх, тема из директивы CLAUDE.md могла остаться без запуска исполнителя. Гейт зелёный: фронтматтеры, копии, одиннадцать диаграмм, ruff, pyrefly; docs.py прогнан на живом фикстуре и печатает категорию в отказе. Канон повышен до версии 6 с записью, выполнимой upgrade. Решения — 40–44. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
107 lines
9.1 KiB
Markdown
107 lines
9.1 KiB
Markdown
# Журнал дефектов
|
||
|
||
Артефакт проекта, а не плагина: файл живёт в репозитории — **`docs/review.md`**,
|
||
слот канона `av-dev-pm`. Здесь описано, зачем он и какой формы, потому что без
|
||
него конвейер не учится: находки закрываются, а почему их не поймали — забывается,
|
||
и один и тот же класс проскакивает второй раз.
|
||
|
||
Тот же файл держит **настройку конвейера под проект** — типовые узлы, типовые
|
||
ложноположительные, вопросы по темам, недоступно проверке. Это не соседство по
|
||
случаю: все четыре раздела — производные калибровки, а журнал им источник.
|
||
|
||
## Что туда попадает
|
||
|
||
**Воспроизведённый дефект — с пометкой `проскочил` или `пойман ревью`.**
|
||
Записывается **сразу**, а не ретроспективно: со временем теряется не сам факт, а то,
|
||
почему дефект не поймали, — единственное, ради чего журнал существует.
|
||
|
||
Пометка делит журнал на две выборки с разным назначением:
|
||
|
||
- **проскочил** — проверочный набор для калибровки конвейера. Реальный промах сильнее
|
||
синтетической пробы: синтетические смещены в сторону тех, которые уже умеешь
|
||
придумывать;
|
||
- **пойман ревью** — прецеденты с оракулом. Самая сильная опора, какая у прохода
|
||
бывает: проектная, воспроизводимая и однажды уже оказавшаяся правдой. Без
|
||
журнала они остаются только в отчётах триажа в архиве change, где их никто не
|
||
ищет.
|
||
|
||
Реализованные задачи и принятые решения сюда не пишутся: у них есть коммит, спека
|
||
и `docs/adr/`.
|
||
|
||
Отдельно сюда попадают **решения о составе прогонов**: перестали звать проход,
|
||
понизили метку правилом, сузили класс проверяемого. Не потому, что это промах,
|
||
а потому, что здесь лежит цена: если что-то теперь проскочит, первый вопрос —
|
||
«не тот ли это класс, который мы перестали проверять».
|
||
|
||
Каждое такое решение обязано получить строку в подразделе **«Перестали проверять
|
||
сознательно»** раздела «Недоступно проверке» того же файла. Журнал хранит «почему
|
||
тогда так решили», раздел настройки — то, во что смотрит каждый прогон. Решение,
|
||
оставшееся только в журнале, в границы покрытия не доедет.
|
||
|
||
## Форма записи
|
||
|
||
**Это дом формы, и у него есть копия.** Скелет `docs/review.md`, который кладёт
|
||
в проект `av-dev-pm` (`skills/canon/references/skeletons.md`), повторяет её
|
||
дословно — он уезжает в репозиторий и обязан там что-то говорить. Правка формы
|
||
здесь **обязана** тянуть правку скелета и запись в журнал версий канона; иначе
|
||
проекты продолжат писать по старой форме, а конвейер — ждать поля, которого нет.
|
||
Дословность сверяет `scripts/copies.py` маркетплейса по маркерам ниже — но
|
||
запись в журнал версий он не проверит, это остаётся на человеке.
|
||
|
||
<!-- дом: журнал-дефектов-форма -->
|
||
```
|
||
## ГГГГ-ММ-ДД — <краткое последствие> [проскочил|пойман]
|
||
|
||
- **Где:** путь:строка либо «конвейер, а не код»
|
||
- **Симптом:** как обнаружилось, кем и когда
|
||
- **Причина:** что на самом деле было не так
|
||
- **Чем воспроизведён:** тест, команда, замер — с числами
|
||
- **Почему не поймали:** только для проскочивших — какой проход обязан был найти
|
||
и что ему помешало
|
||
- **Что меняем:** правило прохода, шаг гейта, конвенция, факт в документе
|
||
проекта — либо «ничего, цена поимки выше цены дефекта»
|
||
```
|
||
<!-- /дом: журнал-дефектов-форма -->
|
||
|
||
Пункт «чем воспроизведён» отличает запись от байки: без него на неё нельзя
|
||
сослаться как на оракул. Регрессионный тест, написанный вместе с починкой,
|
||
годится наравне с независимым экспериментом — он исполняемый и падает на старом
|
||
коде. Слабее он ровно в одном: сформулирован уже зная ответ, и это отмечается
|
||
словом.
|
||
|
||
Последний пункт важнее остальных. Вывод «ничего не меняем» — законный исход: не
|
||
всякий дефект стоит того, чтобы усложнять ради него ревью каждой задачи.
|
||
|
||
## Куда ведёт запись
|
||
|
||
Три адреса, и выбор между ними — половина ценности журнала:
|
||
|
||
- **в документ проекта** — если проход не мог знать факта. Адрес зависит от рода
|
||
факта, и карта их всех — [project-facts.md](project-facts.md):
|
||
настройка хранилища → `docs/database.md`;
|
||
что необратимо и какой шаг гейта красит безусловно → `CLAUDE.md`; периметр и
|
||
недоверенный вход → `docs/security.*`. **Вопрос по теме**, если промах лечится
|
||
не фактом, а заданным вопросом, → раздел «Вопросы по темам» того же
|
||
`docs/review.*`; адресуй теме, а не имени прохода — проход уедет между
|
||
метками, тема останется. Самый частый адрес и самый дешёвый. Прежде чем
|
||
править charter, проверь, не хватит ли факта или вопроса: charter общий для
|
||
всех проектов, документ — про этот.
|
||
- **в конвенции или в правило линтера** — если свойство выражается
|
||
детерминированно (процедура — [promote.md](promote.md)).
|
||
- **в charter прохода** — если сломан **метод**, а не знание. Правка charter'а
|
||
меняет поведение во всех проектах, поэтому она требует калибровки
|
||
([calibration.md](calibration.md)) и обоснования, почему это не лечится фактом
|
||
в документе проекта.
|
||
|
||
## Что журнал даёт конвейеру
|
||
|
||
- **пробы для калибровки** — выборка по пометке `проскочил`;
|
||
- **готовые оракулы** — выборка по пометке `пойман ревью`: находка того же
|
||
класса подтверждается ссылкой на запись, а не рассуждением;
|
||
- **основание для правил конвейера** — требование называть запущенные проходы
|
||
поимённо, отказ от чисел, производных от размера корпуса, и правило очереди для
|
||
меряющих проходов выведены из конкретных записей, а не из общих соображений;
|
||
- **счётчик обратимости решений** — сузили состав проходов и через месяц поймали
|
||
дефект ровно того класса, который перестали проверять: решение пересматривается
|
||
фактом, а не спором.
|