ревью по темам: документ проекта стал направлением проверки
Замечено при сверке документов канона с составом ступеней: три документа остались без читателя ниже wide — security.md, database.md и adr/. Проект поддерживал их, а на 90% задач не открывал никто. Причина оказалась не в переезде проходов, а в том, как описан состав прогона. Список тем нигде не был записан: он существовал побочным продуктом списка проходов. Проход уезжал в верхнюю ступень — и тема уезжала с ним беззвучно. Отчёт честно говорил «ops не запускался» и не говорил «эксплуатацию не смотрел никто», а нужно второе. Теперь тема первична, проход вторичен — это правило 0 конвейера, а прогон описывается таблицей «тема → дом → глубина → кто закрывает», и таблица есть в каждом отчёте. Тема есть документ, список открытый. Всё, что проект кладёт в docs/, становится темой ревью; запретить нельзя, разрешения не надо. Не темы ровно две: docs/tasks/ и docs/review — настройка самого конвейера, слой над темами. Отсюда главное: docs/ перестал быть документацией и стал конфигурацией конвейера. Проект настраивает проверку тем, что пишет о себе, а не отдельным файлом настроек, который разошёлся бы с документами. Ядро — requirements, autotests, conventions, architecture, security, operations; всё сверх разбирает basics, потому что именных проходов конечное число, а тем столько, сколько заведёт проект. Тема живёт файлом или каталогом, на выбор проекта: docs/security.md и docs/security/ — одно и то же. Прежде форма была задана поимённо и обосновать её было нечем; заодно в TODO висел вопрос «а если architecture.md разрастётся». Теперь ответ механический: разросся — стал каталогом с README.md, и это не смена версии. Обе формы сразу — ошибка, docs.py её ловит. Заведён review-scope, sonnet, стадия 0, до гейта: находит документы, выводит темы, назначает глубины, выбирает ступень с обоснованием. Довод оказался сильнее синхронизации документов — до сих пор профиль называл тот же оркестратор, который написал код, то есть в точке выбора глубины проверки разведённости с автором не было вовсе, а решала она под давлением «я почти закончил». Вызывающий пайплайн профиль больше не передаёт. Поднять и понизить ступень разметчик вправе одинаково, но обоснование обязательно всегда. Sonnet ему хватает потому, что вывод устроен как список: каждый файл в docs/ обязан попасть в план темой или строкой «не тема, потому что», и план сверяется с ls docs/ за секунду. Выбор ступени — суждение, но у него три независимых корректора: отрицательный тест quick, правило «спорный случай вниз» и сигнал basics о заниженной ступени. Разметчик передаёт адреса, а не пересказ. Проект однажды уже держал review-brief.md и убрал его: второй дом расходится с первым и выглядит актуальным. Пересказ в задании — тот же посредник, живущий один прогон. Исключение одно: отсутствие дома, этого проход сам дёшево не выяснит. quick и standard совпали составом и разошлись глубиной — иначе требование «нижние ступени закрывают все темы, просто не так глубоко» не выполняется. Глубин три, и они про способ доказательства, а не про старательность: сверка (открыть дом, открыть дифф, сравнить), разбор (построить сценарий рассуждением), доказательство (прогнать, померить, построить путь). Третья есть только в wide. Цена принята: это единственное место, где профиль не выводится из списка проходов, поэтому глубина объявляется в отчёте наравне со ступенью. review-code переписан, и это оказалось крупнее исходной находки: код как код не читал никто. specs сверял с требованиями, basics — с отказами окружения, architecture — с устройством, а code был проходом только по прозаическим конвенциям и прямо объявлял, что рантайм и логика не его. «Здесь ошибка в логике» не говорил вообще никто. Теперь у прохода две половины: девять классов технического дефекта (необработанная ветка отказа, пустое и нулевое, граница диапазона, перепутанный операнд, неосвобождённый ресурс, изменение под итерацией, неверно применённый интерфейс библиотеки, недостижимая ветка, «сделано соседнее») и прежняя сверка с конвенциями. Модель поднята до opus по признаку темы 35: цена пропущенной находки — дефект в проде. Канон повышен до версии 5: форма дома на выбор, открытый список тем, AGENTS.md законно лежит рядом с CLAUDE.md, «Вопросы к проходам» → «Вопросы по темам» (имя прохода переезд не переживает, тема переживает), «Недоступно проверке» — тоже по темам. docs.py переписан под темы: ловит двойной дом, принимает обе формы, перечисляет свои темы проекта вместо «файл вне канона». Побочно закрыт давний пункт TODO про каталожную форму architecture.md — решать больше нечего. Прогон от всего этого стал дороже, а не дешевле, впервые за сессию: плюс scope в голове каждого прогона, плюс code на opus, плюс basics теперь и в quick. Куплены разведённость выбора ступени, видимость непокрытых тем и технический разбор кода, которого не было вовсе. Тема 36 в DECISIONS.md, следствия 137-140. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -79,11 +79,14 @@ stateDiagram-v2
|
||||
|
||||
| Проход | Класс дефекта для инъекции | Заготовка пробы |
|
||||
|---|---|---|
|
||||
| `review-scope` | пропущенная тема | положить в `docs/` новый документ и проверить, попал ли он в план темой |
|
||||
| `review-gate` | отсутствующая верификация | убрать тест на изменённую ветку, оставить код рабочим |
|
||||
| `review-specs` | поведение вне спеки | добавить незаказанный фолбэк-дефолт на пустом входе |
|
||||
| `review-code` | нарушение прозаической конвенции | увести штатный отказ мимо единой точки трансляции ошибки |
|
||||
| `review-code` | технический дефект | не проверить возвращённую ошибку в ветке раннего возврата |
|
||||
| `review-rubric` | нарушенное свойство узла | у клиента внешнего сервиса убрать таймаут и протяжку `context` |
|
||||
| `review-basics` | отказ, видимый чтением | убрать обработку ошибки записи так, чтобы отказ считался успехом |
|
||||
| `review-basics` | своя тема проекта | нарушить правило из документа, у которого нет именного прохода |
|
||||
| `review-architecture` | второй способ | завести вторую точку генерации id мимо единой |
|
||||
| `review-adversary` | построенный путь | принять внешний идентификатор без разбора до запроса в хранилище |
|
||||
| `review-ops` | деградация окружения | убрать обработку недоступности внешней зависимости в фоновом цикле |
|
||||
|
||||
@@ -9,26 +9,42 @@
|
||||
второй дом для тех же фактов разошёлся бы и выглядел актуальным.
|
||||
|
||||
Определение канона — в плагине `av-dev-pm`,
|
||||
`skills/canon/references/canon.md`. Здесь только карта «что нужно проходу →
|
||||
где это лежит».
|
||||
`skills/canon/references/canon.md`. Здесь только карта «тема → её дом → что
|
||||
оттуда берётся».
|
||||
|
||||
## Карта
|
||||
## Карта тем
|
||||
|
||||
**Дом бывает файлом или каталогом** — `docs/security.md` и `docs/security/`
|
||||
называют одну и ту же тему. Форму дома называет план разметчика; проход её не
|
||||
угадывает.
|
||||
|
||||
| Тема | Дом | Что оттуда берётся |
|
||||
| --- | --- | --- |
|
||||
| `requirements` | `openspec/specs/`, `openspec/changes/<id>/specs/` | нормативное поведение и дельты изменения |
|
||||
| `autotests` | `CLAUDE.md`, семантика гейта | команда гейта, чем краснеет безусловно, чего в нём нет, кто гоняет дорогое |
|
||||
| `conventions` | `docs/conventions.*` | конвенции прозой и **что уже механизировано** правилом |
|
||||
| `architecture` | `docs/architecture.*` | компоненты и capability, единые точки проекта |
|
||||
| | `docs/passport.*` | что система делает и **чего не делает**, граница домена |
|
||||
| | `docs/adr/` | почему решено так, отвергнутые варианты |
|
||||
| `security` | `docs/security.*` | периметр, недоверенный вход, из чего строятся пути и ключи, что вне модели |
|
||||
| `operations` | `docs/architecture.*`, раздел эксплуатации | окружение, внешние зависимости поимённо, наблюдатель, характер потока |
|
||||
| | `docs/database.*` | чем физически лежит запись, что при чтении и записи, настройки с числовым значением |
|
||||
| | `docs/research/` | измеренные числа **с провенансом**, поведение внешних систем на самом деле |
|
||||
| *тема проекта* | её документ в `docs/` | то, что проект счёл нужным записать |
|
||||
|
||||
Сквозное, не привязанное к теме:
|
||||
|
||||
| Что нужно проходу | Где лежит |
|
||||
| --- | --- |
|
||||
| что система делает и **чего не делает**, граница домена | `docs/passport.md` |
|
||||
| инварианты **с severity рядом с формулировкой** | `CLAUDE.md`, раздел инвариантов |
|
||||
| команда гейта, чем краснеет безусловно, чего в нём нет, кто гоняет дорогое | `CLAUDE.md`, семантика гейта |
|
||||
| инварианты **с severity рядом с формулировкой** | `CLAUDE.md` (и `AGENTS.md`, если он рядом), раздел инвариантов |
|
||||
| что запускать запрещено, с путями; `testdata`; куда писать временное; имя основной ветки | `CLAUDE.md` |
|
||||
| компоненты и capability, окружение, внешние зависимости поимённо, наблюдатель, характер потока, единые точки проекта | `docs/architecture.md` |
|
||||
| чем физически лежит запись, что при чтении и записи, настройки с числовым значением | `docs/database.md` |
|
||||
| периметр, недоверенный вход, из чего строятся пути и ключи, что вне модели | `docs/security.md` |
|
||||
| измеренные числа **с провенансом**, поведение внешних систем на самом деле | `docs/research/` |
|
||||
| конвенции прозой и **что уже механизировано** правилом | `docs/conventions/` |
|
||||
| почему решено так, отвергнутые варианты | `docs/adr/` |
|
||||
| типовые узлы, типовые ложноположительные, вопросы к проходам, **триггеры профиля**, недоступно проверке | `docs/review.md`, раздел настройки |
|
||||
| прецеденты: воспроизведённые дефекты с оракулом | `docs/review.md`, журнал |
|
||||
| нормативное поведение и дельты изменения | `openspec/specs/`, `openspec/changes/<id>/specs/` |
|
||||
| типовые узлы, типовые ложноположительные, **вопросы по темам**, триггеры профиля, недоступно проверке | `docs/review.*`, раздел настройки |
|
||||
| прецеденты: воспроизведённые дефекты с оракулом | `docs/review.*`, журнал |
|
||||
|
||||
**Вопросы проекта привязаны к теме, а не к имени прохода.** Раньше блок в
|
||||
`docs/review.md` адресовался поимённо (`ops: <вопрос>`), и когда проход уехал в
|
||||
верхнюю ступень, вопрос перестал задаваться молча. Тема переезд прохода
|
||||
переживает.
|
||||
|
||||
## Сшивать обязаны проходы
|
||||
|
||||
@@ -50,9 +66,13 @@
|
||||
**У `basics` стыков нет, и это не упущение.** Он не меряет, поэтому сшивать число
|
||||
с настройкой ему нечего; единственное его основание для `critical` — инвариант из
|
||||
`CLAUDE.md`, всё остальное он формулирует условиями и оставляет гипотезой. Его
|
||||
вход намеренно узкий: единые точки и внешние зависимости из `docs/architecture.md`,
|
||||
инварианты из `CLAUDE.md`, журнал из `docs/review.md`. Широкий вход — это профиль
|
||||
`wide`, и там он есть у `architecture`.
|
||||
вход намеренно узкий: дома тем из плана плюс инварианты и журнал. Широкий вход —
|
||||
это профиль `wide`, и там он есть у `architecture`.
|
||||
|
||||
**У `scope` стыков нет по другой причине: он не читает содержимого.** Его дело —
|
||||
найти дома и раздать темы, а не пересказать написанное. Пересказ сделал бы его
|
||||
посредником между документом и проходом, а посредник расходится с источником и при
|
||||
этом выглядит актуальным.
|
||||
|
||||
## Деградация — поразрядная
|
||||
|
||||
@@ -66,15 +86,17 @@
|
||||
только **последствие** отсутствия, и оно называет самое дорогое, а не всех
|
||||
пострадавших. Два списка читателей уже однажды разошлись; второго раза не надо.
|
||||
|
||||
| Нет документа | Что деградирует |
|
||||
| Нет дома | Что деградирует |
|
||||
| --- | --- |
|
||||
| `CLAUDE.md` без инвариантов | `critical` по основанию «нарушен инвариант проекта» не присваивается никем |
|
||||
| `docs/security.md` | `adversary` не знает периметра — формулирует условиями, `critical` не ставит |
|
||||
| `docs/research/` | числа неизвестны `specs`, `ops`, `adversary` — формулируют условиями, а `specs` теряет проверку «требование против наблюдения» |
|
||||
| `docs/database.md` | замер не с чем сравнить: находка не поднимается выше гипотезы |
|
||||
| `docs/passport.md` | `architecture` теряет границу домена и вырождается в общее мнение |
|
||||
| `docs/review.md` | `triage` отсеивает вслепую: типовых ложноположительных нет |
|
||||
| `docs/architecture.md` | «не появился ли второй способ» не проверяется — единых точек не знает никто; `basics` теряет ещё и перечень внешних зависимостей |
|
||||
| `docs/security.*` | тема `security` остаётся без дома: вопросы задаются по коду, `critical` не ставится, периметр неизвестен |
|
||||
| `docs/research/` | числа неизвестны темам `operations` и `requirements` — формулируют условиями, а `specs` теряет проверку «требование против наблюдения» |
|
||||
| `docs/database.*` | замер не с чем сравнить: находка темы `operations` не поднимается выше гипотезы |
|
||||
| `docs/passport.*` | тема `architecture` теряет границу домена и вырождается в общее мнение |
|
||||
| `docs/adr/` | «не отменяет ли изменение записанное решение» не спрашивает никто |
|
||||
| `docs/review.*` | `triage` отсеивает вслепую: типовых ложноположительных нет; вопросы проекта по темам не задаются |
|
||||
| `docs/conventions.*` | вторая половина `code` идёт вхолостую: записанных конвенций нет |
|
||||
| `docs/architecture.*` | «не появился ли второй способ» не проверяется — единых точек не знает никто; тема `operations` теряет перечень внешних зависимостей |
|
||||
|
||||
Строка в границах покрытия обязана называть **причину**: «`docs/security.md` в
|
||||
проекте нет» читается иначе, чем «есть, но периметр не назван». Без причины
|
||||
|
||||
@@ -80,9 +80,10 @@
|
||||
факта, и карта их всех — [project-facts.md](project-facts.md): объём и
|
||||
измеренное число → `docs/research/`; настройка хранилища → `docs/database.md`;
|
||||
что необратимо и какой шаг гейта красит безусловно → `CLAUDE.md`; периметр и
|
||||
недоверенный вход → `docs/security.md`. **Вопрос конкретному проходу**, если
|
||||
промах лечится не фактом, а заданным вопросом, → раздел «Вопросы к проходам»
|
||||
того же `docs/review.md`. Самый частый адрес и самый дешёвый. Прежде чем
|
||||
недоверенный вход → `docs/security.*`. **Вопрос по теме**, если промах лечится
|
||||
не фактом, а заданным вопросом, → раздел «Вопросы по темам» того же
|
||||
`docs/review.*`; адресуй теме, а не имени прохода — проход уедет между
|
||||
ступенями, тема останется. Самый частый адрес и самый дешёвый. Прежде чем
|
||||
править charter, проверь, не хватит ли факта или вопроса: charter общий для
|
||||
всех проектов, документ — про этот.
|
||||
- **в конвенции или в правило линтера** — если свойство выражается
|
||||
|
||||
Reference in New Issue
Block a user