Синк документации делил правки по документам, а делить их надо по роду. Отражение сделанного (вливание дельт, миграция, компонент в обзоре) пишется молча: без правки документ станет ложным. Новая запись и новая норма — ADR, конвенция, записка разведки, инвариант, периметр, дефект в журнале — только предлагаются, а пишет их третий такт шага 6 после слова человека. Реплика при этом одна на весь хвост: вопрос про урожай ревью переехал с шага 5 на шаг 6 и слился с предложениями синка — решение одно, «что из найденного переживёт задачу». Плановых стопов в сценарии решения стало ровно два, и оба про решения человека. Сверка документов получила счётчик: doc-healthcheck оставляет след ключом [healthcheck] last в .av-dev.toml, синк считает по нему задачи с прошлого прогона и говорит строкой. Прежде признак «десяток задач» держался в памяти, то есть не срабатывал. Журнал — тема 78.
135 lines
11 KiB
Markdown
135 lines
11 KiB
Markdown
# Промоут: находка → конвенция → правило → удаление
|
|
|
|
Механизм храповика. Без него конвейер выдаёт одни и те же находки бесконечно, а
|
|
конвенции не растут — то есть внимание тратится повторно на уже решённое.
|
|
|
|
Роли уровней:
|
|
|
|
- **generative-проходы** — механизм *открытия* неявного (дорого, шумно, но
|
|
только они достают то, чего нет в списках);
|
|
- **конвенции** — дешёвая *регрессионная сетка* на уже открытое;
|
|
- **правила линтера** — то же с детерминированным оракулом и нулевой ценой
|
|
внимания.
|
|
|
|
```mermaid
|
|
flowchart TD
|
|
f["находка ревью"]
|
|
cond{"принята и не специфична<br/>для одного места?"}
|
|
no["промоуту не подлежит:<br/>место одно — комментарий в коде;<br/>вкусовщина — вон на триаже;<br/>нужен рантайм — в журнал ревью"]
|
|
conv["конвенция:<br/>проверяемое свойство + какой проход нашёл"]
|
|
rule["правило линтера, запретитель,<br/>тест-сканер или анализатор"]
|
|
clean["шаг 3: формулировка удалена из конвенций,<br/>строка — в перечень механизированного"]
|
|
|
|
f --> cond
|
|
cond -->|нет| no
|
|
cond -->|да| conv
|
|
conv --> rule
|
|
rule --> clean
|
|
rule -->|"ложных чаще, чем ловит (~треть)"| conv
|
|
```
|
|
|
|
Ребро назад — обратное движение (внизу): правило, дающее ложные срабатывания
|
|
чаще, чем ловит, снимается в прозу. Ребро `rule → clean` **обязательное**: без
|
|
него первые два шага не окупаются, а именно его и пропускают.
|
|
|
|
Схема — **сводка**: условия каждого шага в его разделе, и при расхождении прав
|
|
текст.
|
|
|
|
## Шаг 1. Находка → конвенция
|
|
|
|
Условия: находка **принята** при ревью (не отвергнута, не понижена в гипотезу) и
|
|
**не специфична для одного места**.
|
|
|
|
- Формулируется как **проверяемое свойство**, а не как совет: «уровень доменного
|
|
отказа выбирает единственный логирующий чекпоинт», а не «внимательнее с
|
|
уровнями логов».
|
|
- Записывается источник — какой проход нашёл. Это единственные данные для
|
|
калибровки: проход, чьи находки регулярно доезжают до конвенции, оправдан;
|
|
проход, чьи находки не доезжают никогда, — кандидат на `drop` (см.
|
|
[calibration.md](calibration.md)).
|
|
- Место записи — конвенции проекта, файл или нужный файл каталога (путь — в
|
|
каталог `docs/conventions/`). Если
|
|
тема относится к поведению системы, а не к тому, как мы пишем код, — это не
|
|
конвенция, а требование: заводится дельта-спека обычным путём.
|
|
|
|
**Конвенция заводится по слову человека, и это не формальность.** Одна её строка
|
|
становится входом каждого следующего прогона ревью и критерием для всех будущих
|
|
задач — из всего, что пишет хвост задачи, конвенция связывает дальше всего.
|
|
В цикле задачи она поэтому **предлагается**, а не заводится: строка предложения
|
|
называет проверяемое свойство и проход, который его нашёл, и по этой паре человек
|
|
решает (`av-dev:code-resolve`, `references/solve.md`, шаг 6, такт второй).
|
|
|
|
Промоут идёт **тем же путём, что change → spec**: правка попадает в тот же
|
|
коммит, что и исправление кода, с пометкой в сообщении — история промоутов
|
|
остаётся видна в `git log` по файлу конвенций.
|
|
|
|
## Шаг 2. Конвенция → правило
|
|
|
|
Как только свойство выражается детерминированно, оно переезжает в инструмент.
|
|
Порядок предпочтения — от дешёвого к дорогому:
|
|
|
|
1. **готовое правило существующего линтера** — включить в конфиг;
|
|
2. **запрет идентификатора или импорта** правилом-«запретителем» с собственным
|
|
паттерном;
|
|
3. **правило с настройкой формы** — когда важно не имя, а конструкция;
|
|
4. **тест-сканер исходников** — когда правило про структуру проекта или про
|
|
схему: направление зависимостей, форма миграций, матчинг ошибки по тексту,
|
|
бизнес-логика в транспорте;
|
|
5. **собственный анализатор** — последний рубеж, заводим только если 1–4 не
|
|
выражают правило.
|
|
|
|
Правило обязано быть **зелёным на текущем коде в момент включения**: иначе
|
|
хук блокирует любой коммит, и правило снимут первым же раздражённым движением.
|
|
Приводить код в соответствие — часть шага 2, отдельным коммитом.
|
|
|
|
**Отсюда и место шага 2: он не помещается в хвост чужой задачи.** Конфиг,
|
|
сканер и приведение кода к зелёному — это работа размером с задачу, и сделанная
|
|
попутно она удваивает прогон, который человек заводил ради другого. Согласованный
|
|
промоут даёт **строку конвенции сейчас** и **задачу `chore` на механизацию**;
|
|
задачу заводит `av-dev:task-track` тем же словом, что и саму конвенцию.
|
|
|
|
## Шаг 3. Удаление из конвенций и из промптов
|
|
|
|
**Шаг, который пропускают чаще всего, и единственный, ради которого затевались
|
|
первые два.**
|
|
|
|
Как только правило работает:
|
|
|
|
- из файла конвенций убирается формулировка правила; остаётся, если нужно, одна
|
|
строка «проверяется линтером `<имя>`» — но только там, где без неё раздел
|
|
теряет связность;
|
|
- правило переезжает в **перечень механизированного в доме конвенций**
|
|
(`docs/conventions/README.md` у каталога, отдельный раздел
|
|
`docs/conventions.md` у файла) — со ссылкой на место механизации: конфиг
|
|
линтера, собственный анализатор, тест-сканер исходников. Не названное место
|
|
означает, что проход будет добросовестно проверять уже проверенное;
|
|
- из контекста инструмента спек убирается дубль, если он там был.
|
|
|
|
Charter'ы проходов при этом **не правятся**: они общие и живут в плагине, а
|
|
предмет проверки приходит из документов проекта. Именно поэтому шаг 3 дешевле,
|
|
чем был:
|
|
вычеркнуть строку в одном файле проекта, а не в девяти промптах.
|
|
|
|
Практический критерий: **в прозаических конвенциях остаётся только то, что
|
|
принципиально не выражается правилом.** Файл конвенций на несколько сотен строк
|
|
размазывает внимание модели по тривиальному — она добросовестно проверит
|
|
именование полей лога и не дойдёт до формы решения. Каждая строка конвенций,
|
|
которую можно было бы проверить машиной, оплачивается дефектом, который не
|
|
поймали где-то ещё.
|
|
|
|
## Обратное движение
|
|
|
|
Правило, которое даёт ложные срабатывания чаще, чем ловит (порядка трети от
|
|
общего числа), снимается и возвращается в прозу — или удаляется совсем, если
|
|
свойство перестало быть важным. Снятие фиксируется там же, где включалось, с
|
|
одной строкой «почему».
|
|
|
|
## Что промоуту не подлежит
|
|
|
|
- Находка, специфичная для одного места (её лечит комментарий в коде).
|
|
- Вкусовщина: не меняет поведения, не влияет на стоимость следующего изменения,
|
|
не нарушает записанного. Такое выбрасывается на триаже и не хранится.
|
|
- Свойство, требующее знания рантайма (профиль нагрузки, история инцидентов) —
|
|
его нельзя проверить ни промптом, ни линтером; место такому — в журнале ревью
|
|
как «признано неавтоматизируемым» (см. [review-journal.md](review-journal.md)).
|