Конвейер собран по типу проходов, а не по ролям: гейт (детерминированный, блокирующий) → сверка с дельта-спеками в обе стороны → generative-проходы → архитектура → враждебные постановки → обязательный триаж. Профили quick / standard / deep / design с правилом выбора по факту изменения. Контракт находок: заголовок через последствие, обязательное поле «Последствие», critical без оракула или построенного пути не существует, потолок 7 пунктов и разметка «инлайн | развилка» — отчёт читает оркестратор и молча реализует прочитанное, поэтому потолок защищает код от незаказанных правок. Храповик находка → конвенция → правило → удаление из прозы и промптов; журнал проскочивших дефектов и калибровка инъекцией с вердиктами keep/retune/drop. Секция границ покрытия обязательна: отчёт без неё потребляет ощущение проверенности, ничего не гарантируя. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
90 lines
6.8 KiB
Markdown
90 lines
6.8 KiB
Markdown
# Промоут: находка → конвенция → правило → удаление
|
|
|
|
Механизм храповика. Без него конвейер выдаёт одни и те же находки бесконечно, а
|
|
конвенции не растут — то есть внимание тратится повторно на уже решённое.
|
|
|
|
Роли уровней:
|
|
|
|
- **generative-проходы** — механизм *открытия* неявного (дорого, шумно, но
|
|
только они достают то, чего нет в списках);
|
|
- **конвенции** — дешёвая *регрессионная сетка* на уже открытое;
|
|
- **правила линтера** — то же с детерминированным оракулом и нулевой ценой
|
|
внимания.
|
|
|
|
## Шаг 1. Находка → конвенция
|
|
|
|
Условия: находка **принята** при ревью (не отвергнута, не понижена в гипотезу) и
|
|
**не специфична для одного места**.
|
|
|
|
- Формулируется как **проверяемое свойство**, а не как совет: «уровень доменного
|
|
отказа выбирает единственный логирующий чокпоинт», а не «внимательнее с
|
|
уровнями логов».
|
|
- Записывается источник — какой проход нашёл. Это единственные данные для
|
|
калибровки: проход, чьи находки регулярно доезжают до конвенции, оправдан;
|
|
проход, чьи находки не доезжают никогда, — кандидат на `drop`.
|
|
- Место записи — соответствующий файл `docs/conventions/*.md`. Если тема
|
|
относится к поведению системы, а не к тому, как мы пишем код, — это не
|
|
конвенция, а требование: заводится дельта-спека OpenSpec обычным путём.
|
|
|
|
Промоут идёт **тем же путём, что change → spec**: правка попадает в тот же
|
|
коммит, что и исправление кода, с пометкой в сообщении — история промоутов
|
|
видна в `git log docs/conventions/`.
|
|
|
|
## Шаг 2. Конвенция → правило
|
|
|
|
Как только свойство выражается детерминированно, оно переезжает в инструмент.
|
|
Порядок предпочтения — от дешёвого к дорогому:
|
|
|
|
1. **готовый линтер** в `.golangci.yml` (`sloglint`, `errorlint`, `depguard`,
|
|
`forbidigo`, `misspell`, стандартный набор v2);
|
|
2. **`forbidigo`/`depguard` с собственным паттерном** — запрет идентификатора или
|
|
импорта;
|
|
3. **`revive`/`gocritic` с настройкой** — когда нужна форма, а не имя;
|
|
4. **тест-сканер исходников** `internal/arch_test.go` — когда правило про
|
|
структуру проекта или SQL: направление зависимостей, `AUTOINCREMENT` в
|
|
миграциях, матчинг ошибки по тексту, бизнес-логика в транспорте;
|
|
5. **`go/analysis`-анализатор** — последний рубеж, заводим только если 1–4 не
|
|
выражают правило.
|
|
|
|
Правило обязано быть **зелёным на текущем коде в момент включения**: иначе
|
|
lefthook блокирует любой коммит, и правило снимут первым же раздражённым
|
|
движением. Приводить код в соответствие — часть шага 2, отдельным коммитом.
|
|
|
|
## Шаг 3. Удаление из конвенций и из промптов
|
|
|
|
**Шаг, который пропускают чаще всего, и единственный, ради которого затевались
|
|
первые два.**
|
|
|
|
Как только правило работает:
|
|
|
|
- из `docs/conventions/*.md` убирается формулировка правила; остаётся, если
|
|
нужно, одна строка «проверяется линтером `<имя>`» — но только там, где без неё
|
|
раздел теряет связность;
|
|
- из charter'ов агентов (`.claude/agents/jellybit-review-*.md`) убирается
|
|
соответствующий пункт;
|
|
- из `openspec/config.yaml` → `context` убирается дубль, если он там был.
|
|
|
|
Практический критерий: **в прозаических конвенциях остаётся только то, что
|
|
принципиально не выражается правилом.** Файл конвенций на несколько сотен строк
|
|
размазывает внимание модели по тривиальному — она добросовестно проверит
|
|
именование полей лога и не дойдёт до формы решения. Каждая строка конвенций,
|
|
которую можно было бы проверить машиной, оплачивается непойманным дефектом
|
|
где-то ещё.
|
|
|
|
## Обратное движение
|
|
|
|
Правило, которое даёт ложные срабатывания чаще, чем ловит (порядка трети от
|
|
общего числа), снимается и возвращается в прозу — или удаляется совсем, если
|
|
свойство перестало быть важным. Снятие фиксируется там же, где включалось, с
|
|
одной строкой «почему».
|
|
|
|
## Что промоуту не подлежит
|
|
|
|
- Находка, специфичная для одного места (её лечит комментарий в коде).
|
|
- Вкусовщина: не меняет поведения, не влияет на стоимость следующего изменения,
|
|
не нарушает записанного. Такое выбрасывается на триаже и не хранится.
|
|
- Свойство, требующее знания рантайма (профиль нагрузки, история инцидентов) —
|
|
его нельзя проверить ни промптом, ни линтером; место такому — в
|
|
[journal.md](../../../../docs/review/journal.md) как «признано
|
|
неавтоматизируемым».
|