Files
av 7fb60828db guide: граница со спекой переписана на тест наблюдаемости вердикта
- «что против как» на пограничных правилах не работает: capability
  проверяется снаружи работающей системы, конвенция — только в исходном
  тексте, и отсюда расходятся направление, распространение и шкала
- добавлен признак для спорного случая: обязательство перед внешним
  потребителем — в спеку, зависимость автора следующего патча — в конвенцию
2026-07-27 08:57:35 +03:00

573 lines
48 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
prefix: META
---
# Как мы ведём конвенции
Конвенция описывает повторяющийся выбор: как называть директории, как
раскладывать данные, как оформлять ошибки. Она отвечает на вопрос «как
принято», а не «что здесь происходит».
Как записывается сама конвенция — правила, модальность, обоснования — в
[LANGUAGE.md](LANGUAGE.md). Здесь — про то, зачем конвенции заводятся, где
живут и как соотносятся с соседними видами документов.
Правила ниже записаны тем же языком, что и сами конвенции, и проверяются так
же.
Ключевые слова ДОЛЖЕН, НЕ ДОЛЖЕН, СЛЕДУЕТ, НЕ СЛЕДУЕТ, ДОПУСКАЕТСЯ и метки
ПОЧЕМУ, ПРИМЕРЫ, МЕХАНИЗИРОВАНО и СНЯТО толкуются как описано в языке
конвенций версии 1 — тогда и только тогда, когда написаны заглавными.
## Область действия
Правила ниже адресованы автору конвенции — тому, кто заводит новый файл или
правит существующий, в каноне и в копиях репозиториев. Обязательность живёт
на отдельном правиле, а не на файле; шкала модальных слов — в
[LANGUAGE.md](LANGUAGE.md).
## Отличие от соседей
- `docs/adr/`**решение**, принятое однажды и постфактум («почему выбрали
Authelia, а не Keycloak»). Запись неизменяема.
- `docs/specs/` и OpenSpec, где они есть, — контракт наблюдаемого поведения.
Конвенция в спеки не переносится: это не capability.
- `docs/drafts/` — оперативная хроника и черновики, «что собираюсь сделать».
- `docs/conventions/`**правило на будущее**, применяемое многократно.
Живой документ: правится, когда договорённость меняется.
Со спекой конвенцию путают чаще прочего, а «что против как» на границе не
работает. Разводит их то, **где наблюдается вердикт**. У capability он виден
снаружи работающей системы: подали вход, получили выход, совпало или нет. У
конвенции — только в исходном тексте: снаружи не различить, обёрнута ошибка
или проглочена и по какому признаку выбран уровень записи.
Отсюда расходится остальное. Спека едет за системой — изменилось поведение,
меняется контракт; конвенция ведёт код, и факт «в приложении уже иначе»
аргументом не считается (META-5), а утверждений о состоянии репозитория в ней
нет вовсе (META-4). Спека принадлежит одной системе; конвенция ездит копиями
и потому знает про темы, слои и локальную часть. Capability бинарна —
реализована или нет; у конвенции есть ступени и постоянный список отступлений
(META-13). Спеку пишут до кода, конвенцию — на третий раз (META-2).
Пограничное правило разбирается признаком внешнего потребителя. Формат логов,
который собирает чужой агрегатор, — обязательство перед кем-то снаружи, и
место ему в спеке. Если от правила зависит только автор следующего патча —
это конвенция.
## Оформление
Имя файла повторяет имя темы: `app-directories.md`. Правилом это не
записано, и это случай META-25: регуляркой имя проверяется тривиально, но
вреда от нарушения нет — тема объявлена в шапке (META-28), и сборка идёт по
объявленному имени, а не по имени файла. Значит, и высшей модальности нет, а
ступенью ниже такое правило не окупает строчку.
## Канон и копии
Файлы в `docs/conventions/` с шапкой `origin:` — копии из общего канона
`dev-conventions`, а не собственные документы репозитория. Копия собирается
из канона целиком, поэтому репозиторное живёт ниже маркера локальной части
в конце файла: обновление сохраняет всё, что ниже маркера, и переписывает
всё, что выше. Откуда взяты копии и где брать обновления — в манифесте
`.conventions.toml` в корне репозитория.
Отдельного механизма отчёта о расхождении нет: обновление перезаписывает
файлы в рабочем дереве, а что именно изменилось, показывает `git diff` до
коммита. Поэтому в шапке копии хранится только `origin:` — отпечатков
канона и дат синхронизации в ней нет, историю держит git.
Правка выше маркера означает одно из двух: улучшение, которое переносят в
канон, или документ, переставший быть копией, — тогда `origin:` из шапки
убирают.
## Как проверить границу темы
Готовая тема проходится по шести вопросам; на каждый отвечает своё правило:
- на какой вопрос отвечает правило — и тот ли это вопрос, что у темы
(META-33);
- нужна ли тема правдоподобному потребителю целиком (META-34);
- слой сужает базу или отменяет её (META-35);
- зависит ли норма от вида приложения и назван ли он (META-36);
- названа ли тема решением и адресатом, а не ролью части проекта (META-37);
- исполнима ли норма, если соседних тем в репозитории нет (META-20).
Расхождение на любом из них означает, что граница проходит не там, где
нарисована: тема собрана вокруг вещества, склеила два решения или молча
предполагает вид приложения. Чинится это разрезом темы или областью
действия, а не смягчением нормы.
## Правила
### META-1. Одна конвенция — один файл
**ДОЛЖЕН.** Файл описывает ровно один повторяющийся выбор.
**ПОЧЕМУ.** Подписка перечисляется по темам, и тему берут целиком. Файл,
собравший две темы, вынуждает репозиторий взять правила, которые ему не
нужны, и вычитывать чужую половину при каждом обновлении. Разрезать позже
дорого: перенос правила в другой файл — это новый префикс и новая
нумерация, поэтому после разреза все внешние ссылки обходят руками.
### META-33. Правило стоит в теме, чей вопрос оно решает
**ДОЛЖЕН.** Тема правила определяется вердиктом, который правило выносит, а
не веществом, о котором оно говорит.
**ПОЧЕМУ.** Одно и то же вещество — время, идентификатор, конфигурация —
проходит через несколько решений сразу, и тема, собранная вокруг вещества,
склеивает чужие решения: «в каком виде хранить в базе», «что писать в лог»,
«что отдавать наружу» попадают в один файл на том основании, что все три
говорят о моментах. Подписка после этого промахивается в обе стороны:
репозиторий без базы получает правила о колонках, а репозиторий с базой, не
подписанный на время, правил о своих колонках не получает — хотя они про его
схему. Отличить одно от другого дёшево: вопрос темы выписывается одной
фразой, и норма читается как ответ на него; ответ на чужой вопрос означает,
что правило лежит не в своей теме.
### META-34. Тема нужна потребителю целиком
**СЛЕДУЕТ.** Тема нарезается так, чтобы правдоподобному потребителю
требовалась вся она, а не часть.
**ПОЧЕМУ.** Взять половину темы нечем: подписка перечисляется темами, и
сборщик кладёт файл целиком. Потребитель, которому нужна треть правил,
платит за остальные две трети вычиткой при каждом обновлении и пачкой
отступлений — а пачка отступлений неотличима от небрежности и обесценивает
список, по которому считают реальное соблюдение (META-14). Линия разреза
видна заранее: если два правдоподобных потребителя хотят непересекающиеся
части одной темы, между этими частями и проходит граница. Ступень ниже
высшей потому, что «правдоподобный потребитель» — суждение: двое разойдутся
в том, бывает ли такой репозиторий вообще.
### META-35. Слой сужает базу, но не отменяет её
**НЕ ДОЛЖЕН.** Правило языкового или стекового слоя не требует
противоположного норме арх-слоя своей темы и не снимает её требование.
**ПОЧЕМУ.** Слои темы приезжают в копию одним файлом, секция за секцией, и
исполняются подряд: база и отменяющее её уточнение стоят рядом без указания,
какое из них главнее, — читатель выбирает сам, и вердикт перестаёт быть
воспроизводимым (META-6). Отсюда же тест на границу: если ради нового случая
базу приходится отменять, это не слой, а другая тема — общим у них осталось
слово, а не решение. Сужение слоем остаётся: уточнить, ограничить, назвать
инструмент, разобрать случай, который база предусмотрела.
### META-36. Вид приложения называется, если норма от него зависит
**ДОЛЖЕН.** Норма, верная не для всякого приложения, сопровождается областью
действия, называющей вид приложения, для которого она написана.
**ПОЧЕМУ.** Вид приложения — веб-сервис, программа командной строки, набор
плейбуков, библиотека — меняет вердикт там, где язык и инструмент его не
меняют: лог сервиса читают через месяц запросом, вывод команды — сейчас и
глазами, поэтому уровень записи у них выбирается по-разному. Осями это
измерение не выражено: они отвечают на вопрос, от чего правило умирает, а не
к чему оно применяется, — и единственное место, где вид может быть назван,
область действия. Не названный, он остаётся молчаливым допущением автора:
потребитель другого вида не отличает «правило написано не про меня» от «мы
его нарушаем» и записывает второе, хотя чинится первое — условие
применимости в каноне (META-15.2).
### META-37. Имя темы называет решение и адресата, а не место в архитектуре
**СЛЕДУЕТ.** Именем темы служит решение вместе с тем, кому оно адресовано, а
не роль части конкретного проекта.
**ПОЧЕМУ.** Имя темы вечно и не переиспользуется (META-29): оно стоит в
`origin:` каждой копии, в подписках, в чужих ссылках. Роль же принадлежит
сегодняшнему устройству одного проекта — «фронтенд», который через три года
рендерится на сервере, называется по-прежнему, а означает другое, и заметить
расхождение нечем: имя ни на что не ссылается, кроме привычки. Пара имён вида
`logging-backend` и `logging-frontend` вдобавок навязывает чтение «две
разновидности одного», хотя по границе это две темы: серверную запись читают
постфактум инструментом, клиентскую — разработчик в консоли или сборщик ошибок
на той стороне сети, и общего у них остаётся три правила из сорока. Названные
по адресату — `logging` и `client-logging` — они и читаются как разные.
Ступень ниже высшей потому, что «решение против роли» — суждение о слове: на
границе двое разойдутся.
### META-38. Ось слоя объявляется в шапке файла
**ДОЛЖЕН.** Принадлежность слоя оси объявляется в шапке ключами `lang:` и
`stack:`, а не выводится из пути файла; отсутствие обоих ключей означает
базовый слой темы.
**ПОЧЕМУ.** Ось, выведенная из пути, ломается тем же способом, что и тема,
выведенная из имени файла (META-28), только тише: переезд файла между
директориями не меняет ни одного идентификатора, но меняет состав копии у
каждого потребителя — слой начинает выбираться при другом языке или всегда.
Сверить это не с чем, потому что путь ничего не утверждает, а объявления нет.
Объявление вдобавок выражает то, чего дерево директорий не выражает: слой,
осмысленный только при совпадении языка и инструмента сразу; и набор, у
которого осей нет вовсе, перестаёт требовать директорий-заглушек. Дерево при
этом остаётся — но тем же, чем уже является `extends:`, документацией связи
для человека.
### META-28. Тема объявляется в шапке файла и стоит в манифесте набора
**ДОЛЖЕН.** Шапка несёт ключ `topic:` с именем темы, и это имя стоит в
манифесте набора.
**ПОЧЕМУ.** Тема — единица подписки и единица сборки: потребитель перечисляет
темы в своём манифесте, а сборщик складывает в один файл все слои темы. Пока
имя выводится из имени файла, у сборщика нет способа узнать, что два слоя,
названные по-разному, — один документ; переименование файла при этом молча
заводит новую тему, подписка перестаёт находить прежнюю, а ссылки «конвенция
`logging`» в копиях остаются висеть. Объявленное имя вдобавок сверяется с
манифестом — выведенное сверять не с чем.
### META-29. Имя темы не переиспользуется
**НЕ ДОЛЖЕН.** Снятое или переименованное имя темы другой теме не выдаётся:
оно уходит в раздел выбывших манифеста с причиной и датой.
**ПОЧЕМУ.** Имя темы живёт в чужих репозиториях — в шапке `origin:` каждой
копии, в подписке потребителя, в тексте ссылок. Выданное второй теме, оно
начинает указывать на другой набор правил, и обнаруживается это не на сборке,
а по содержанию: файл обновится штатно, изменится текст. Та же дисциплина и по
той же причине действует для префиксов правил.
### META-30. Правка словаря или формы правила доходит до документа для читателя
**ДОЛЖЕН.** Изменение ключевых слов, их значений или состава частей правила
вносится и в короткое описание языка, которое едет в копию.
**ПОЧЕМУ.** Полное описание языка остаётся у автора набора, а по правилам код
проверяет читатель копии — человек или агент в чужом репозитории, у которого
из двух документов есть только короткий. Разошедшись, он начинает толковать
слова по прежней версии: ДОПУСКАЕТСЯ читается как бытовое «можно», отступление
от ДОЛЖЕН перестаёт требовать записи — то есть отказывает ровно то, ради чего
слова вводились, и молча. Проверить расхождение дёшево: словари в двух
документах либо совпадают, либо нет.
### META-31. Нумерация правил в файле сплошная
**ДОЛЖЕН.** Номера идут от единицы до наибольшего без пропусков: снятое
правило остаётся на месте заглушкой с меткой СНЯТО, а не исчезает.
**ПОЧЕМУ.** Дыра в нумерации неотличима от опечатки в номере и от правила,
которое забыли дописать, — проверка, увидев пропуск, не может сказать, ошибка
это или норма, поэтому либо молчит всегда, либо краснеет на живом файле.
Заглушка отвечает на тот же вопрос текстом: номер занят, правило снято
тогда-то и по такой-то причине. Переиспользовать номер по-прежнему нельзя —
ссылка из чужого репозитория обязана указывать на то же утверждение, — но и
отдельный
реестр снятых номеров не нужен: он был бы вторым источником правды рядом с
файлом, который и так всё сказал.
### META-32. Ссылка ведёт на правило, которое существует
**НЕ ДОЛЖЕН.** Идентификатор в тексте не указывает на правило, которого в
наборе нет.
**ПОЧЕМУ.** Неразрешимая ссылка означает одно из двух: опечатку в номере или
след переноса правила в другой файл. Читатель — тем более в чужом
репозитории — не различит эти случаи и решит, что правила больше нет, хотя оно
могло переехать. С заглушками (META-31) проверка становится однозначной:
идентификатор либо ведёт к правилу, либо к объяснению, почему его сняли, а
третьего исхода нет — и любой неразрешённый идентификатор точно ошибка.
### META-2. Конвенция заводится, когда решение принимается третий раз
**СЛЕДУЕТ.** Поводом служит одно и то же решение, принятое третий раз и
каждый раз чуть по-другому.
**ПОЧЕМУ.** По одному-двум случаям не видно, что в решении повторяется, а
что было частностью места: правило, выведенное из первого случая, кодирует
частность и дальше мешает больше, чем помогает. Единичный выбор, к тому же
спорный, читателю нужен вместе с мотивом — это ADR, где мотив и есть
содержание записи.
### META-3. Новая конвенция пишется там, где заболело
**СЛЕДУЕТ.** Первые шаги пути «находка → конвенция → правило линтера»
делаются в репозитории, где случилась находка; в канон продвигается общая
часть.
**ПОЧЕМУ.** Правило, написанное сразу в общем виде, не проверено ни одним
применением, и условие применимости у него придумано, а не найдено, —
платят за это все потребители сразу. Формулировка, обкатанная на одном
репозитории, приезжает в канон уже с известной границей.
### META-4. В тексте конвенции нет утверждений о состоянии репозитория
**НЕ ДОЛЖЕН.** Норма пишется в настоящем предписывающем времени, без
описаний того, как сейчас устроен конкретный репозиторий.
**ПОЧЕМУ.** Такое утверждение устаревает молча и подменяет норму описанием:
читатель перестаёт понимать, что от него требуется, а что просто
констатировано. В копиях у остальных потребителей чужой факт вдобавок ложен
с первого дня. «Так сделано у нас» — содержимое региона отступлений, где оно
и локально, и проверяемо.
### META-20. Норма самодостаточна, наружу смотрит только обоснование
**ДОЛЖЕН.** Норму правила можно исполнить, имея один этот файл. Ссылка на
правило чужой темы допустима в обосновании, в «Связано» и в разграничении
области действия — но не в самой норме. Если норме нужен концепт соседней
темы, он коротко повторяется здесь, а сосед называется в обосновании как
источник решения.
**ПОЧЕМУ.** Репозиторий подписывается на произвольное подмножество
конвенций, и графа зависимостей у него нет по построению. Норма, которую
нельзя исполнить без отсутствующего файла, делает такое подмножество
невалидным молча: читатель видит связный текст и не замечает, что часть
нормы не определена. Обоснование, потерявшее адресата, деградирует честно —
пропадает перекрёстная проверка, смысл остаётся. Цена повтора — риск
разойтись с источником; она платится сознательно и видна, в отличие от
скрытой зависимости.
### META-21. Ссылка ведёт на тему или на правило, но не на путь в каноне
**ДОЛЖЕН.** На соседнюю конвенцию ссылаются именем темы (конвенция
`logging`), на конкретное правило — идентификатором (`SLOG-27`); путь файла
канона в тексте конвенции не употребляется.
**ПОЧЕМУ.** В репозитории конвенция лежит собранной: слои одной темы — это
секции одного файла, и пути `lang/go/logging.md` там не существует. Ссылка
на путь канона умирает при сборке, причём молча — текст остаётся связным.
Имя темы и идентификатор правила переживают и сборку, и переезд файла между
осями. Слой своей темы поэтому называют идентификатором его правила, а не
словами «базовый слой»: слова не проверяются и не ведут к утверждению.
### META-24. Слой ссылается на идентификаторы своего базового слоя
**ДОПУСКАЕТСЯ.** Правило языкового или стекового слоя называет идентификатор
правила арх-слоя своей темы прямо в норме.
**ПОЧЕМУ.** Подписываются темой, а не слоем: собранный файл начинается с
арх-слоя независимо от того, какие язык и стек выбраны, — базовое правило в
копии всегда рядом, и ссылка на него никуда не ведёт. Повтор его концепта
здесь заводил бы второй источник правды внутри одного документа: META-20
требует повторять концепт там, где соседнего файла может не быть, а базовый
слой отсутствовать не может. Остальные слои темы попадают в копию по
манифесту, и такой гарантии у них нет — отсюда узость разрешения. Записано
оно явно, потому что META-20 читают строже, чем он есть, и без этой строки
базу дублируют без нужды.
### META-5. Расхождение кода с правилом — отступление, а не повод переписать правило
**ДОЛЖЕН.** Правило правится, только когда неверно по существу: содержит
фактическую ошибку, внутреннее противоречие или условие применимости,
которое не даёт ответа.
**ПОЧЕМУ.** Правило, подогнанное под текущий код, перестаёт что-либо
требовать — оно описывает то, что и так происходит, и первое же расхождение
переписывает его снова. Направление «конвенция → код» держится ровно тем,
что факт не считается аргументом.
### META-6. Высшая модальность требует воспроизводимого вердикта
**ДОЛЖЕН.** Правило со ступенью ДОЛЖЕН или НЕ ДОЛЖЕН формулируется так, что
двое проверяющих по одному его тексту выносят один и тот же вердикт.
**ПОЧЕМУ.** Проверяют конвенцию в первую очередь агент и человек — они читают
текст правила и по нему смотрят код. Проверка, стало быть, есть у каждого
правила с первого дня, и её инструмент — формулировка, а не скрипт. Отсюда
цена невоспроизводимой нормы: вердикт зависит от того, кто читал, нарушения
всплывают выборочно, а отступление нечем записать — неизвестно, нарушено ли.
Для СЛЕДУЕТ это честно, там суждение и есть содержание правила; ДОЛЖЕН в
таком виде обещает то, чего не делает, и через несколько случаев обесценивает
остальные ДОЛЖЕН в файле.
Отсюда следствие: правило, вердикт которого зависит от суждения по построению
(вкус формулировки, выбор границы, уместность в конкретном месте), не может
быть ДОЛЖЕН — его модальность СЛЕДУЕТ по природе нормы, а не по слабости.
### META-25. Высшая модальность выбирается, только когда назван вред
**СЛЕДУЕТ.** Правило получает ДОЛЖЕН или НЕ ДОЛЖЕН, если в обосновании
сказано, что́ ломается при нарушении.
**ПОЧЕМУ.** Воспроизводимость вердикта — условие необходимое (META-6), но не
достаточное: воспроизводимо проверяемых мелочей больше, чем важных вещей, и
без второго условия единственным фильтром остаётся удобство проверки. Шкала
наполняется опрятностью, читатель перестаёт отличать «уронит прод» от
«неаккуратно» — и обесцениваются все ДОЛЖЕН в файле, ровно то, от чего META-6
защищает с другой стороны. Собственная ступень этого правила — СЛЕДУЕТ:
форма обоснования ничем не ограничена, поэтому «вред назван» вердикта не
даёт — один читатель увидит названный вред там, где другой увидит объяснение
мотива.
### META-27. Механизация правила желательна, но ступени не задаёт
**СЛЕДУЕТ.** Правило со ступенью ДОЛЖЕН получает машинную проверку, когда
такую проверку можно написать.
**ПОЧЕМУ.** Линтер не забывает, ничего не стоит на каждом прогоне и краснеет
до ревью, а не на нём: там, где проверка пишется, она дешевле самого
внимательного чтения, и путь «находка → конвенция → проверка» кончается ею.
Норму она при этом не заменяет и не отменяет (META-8). Условием ступени
механизация не является:
проверяющий по умолчанию — читатель правила (META-6), а если требовать
скрипт, весь канон стоит в СЛЕДУЕТ до того дня, когда скрипты появятся.
Ступень говорит о важности нормы, а не о состоянии инструментов.
### META-7. Факт механизации фиксируется в копии со ссылкой на правило
**ДОЛЖЕН.** Запись о механизации называет идентификатор правила и
конкретную проверку.
**ПОЧЕМУ.** Механизация — состояние конкретного репозитория, канон о ней не
знает, а без записи следующий автор либо заведёт вторую проверку того же,
либо будет вычитывать глазами уже проверенное машиной. Без идентификатора
читатель догадывается сам, к какому утверждению относится проверка, — и
догадывается по-разному.
### META-8. Норма из канона не удаляется, чем бы она ни проверялась
**НЕ ДОЛЖЕН.** Формулировка нормы остаётся в правиле независимо от того, кто и
чем её проверяет.
**ПОЧЕМУ.** Проверяющий по умолчанию — читатель правила (META-6), и удаление
нормы забирает у него ровно то, чем он проверяет: линтер сообщает, что
нарушено, но не сообщает, что требуется. Условие «механизировано у всех»
спасти не может: оно измеряется в день удаления, а подписчики появляются
после. Репозиторий, подключившийся через год, получил бы правило без нормы и
без проверки — заголовок с обоснованием и никакого способа узнать, что́ именно
предписано, кроме git-истории канона, до которой он не дойдёт. Списка
подписчиков у канона к тому же нет по построению, так что «у всех» ему всё
равно не проверить.
### META-10. Обоснование не удаляется никогда
**НЕ ДОЛЖЕН.** Блок ПОЧЕМУ остаётся и после того, как правило стало
проверяться линтером.
**ПОЧЕМУ.** Линтер сообщает, что нарушено, но не сообщает, зачем правило
существует. Без обоснования не видно, когда причина отпала, — проверка
продолжает работать по инерции, и возразить ей нечем, кроме как отключив.
### META-11. У трудноизменяемого слоя область действия пишется явно
**ДОЛЖЕН.** Конвенция о схеме БД, формате хранения или раскладке директорий
называет, к чему применяется: к новым таблицам и миграциям, а не к
состоянию схемы.
**ПОЧЕМУ.** Здесь не работает привычное «новое пишем правильно, старое
переезжает по мере касания»: таблица не переезжает от того, что её
потрогали. Без явной рамки правило читается как требование к текущему
состоянию, и оба исхода плохи — миграция живых данных ради опрятности либо
молчаливый вывод, что конвенция не соблюдается совсем.
### META-12. Механизируется граница изменения, а не состояние
**ДОЛЖЕН.** Проверка запрещает нарушение в новых миграциях, а не в уже
существующей схеме.
**ПОЧЕМУ.** Проверка состояния краснеет на легаси с первого дня: её
отключают или обвешивают вечным списком исключений — и она перестаёт ловить
новое, ради чего заводилась. Проверка границы оставляет старое в покое и
делает новую ошибку невозможной.
### META-13. Список отступлений трудноизменяемого слоя — постоянный
**ДОЛЖЕН.** Перечисленные старые таблицы и раскладки живут как есть, а не
как задачи на дочистку.
**ПОЧЕМУ.** Список, записанный долгом, требует либо мигрировать живые данные
без выгоды, либо год за годом объяснять невыполненный план. Второе кончается
тем, что список перестают вести, — и пропадает единственное место, где видно,
где именно правило не действует.
### META-14. Отступления перечисляются поимённо, со ссылкой на правила
**ДОЛЖЕН.** В локальной части копии перечислены отступления, которые уже
есть в коде, с идентификатором правила и причиной.
**ПОЧЕМУ.** Иначе репозиторий выглядит соблюдающим конвенцию, а проверить
это можно только чтением всего кода. Со ссылками отступления счётны: видно,
сколько правил конвенции репозиторий реально не соблюдает. Пустой список при
этом почти всегда означает не отсутствие отступлений, а то, что их не искали.
### META-15. Запись об отступлении разбирается по масштабу
**ДОЛЖЕН.** Судьба записи зависит от того, что в ней сказано:
| № | Что записано | Куда идёт |
|---|---|---|
| META-15.1 | правилу не следуем в перечисленных местах, причина названа | остаётся отступлением |
| META-15.2 | правило не применяется в репозитории целиком | чинится условие применимости — в каноне |
| META-15.3 | конвенция репозиторию не нужна | копия удаляется, подписки нет |
**ПОЧЕМУ.** Отступление описывает исключение, и по нему видно, какая часть
правила нарушена. Запись «мы это правило вообще не применяем» такой
информации не несёт и маскирует одну из двух чинимых причин: неверную рамку
правила в каноне, которую чинят один раз для всех, или лишнюю подписку,
где файл просто не нужен. Оставленная отступлением, она прячет обе.
### META-17. Ссылки на код репозитория стоят в локальной части, а не в «Связано»
**ДОЛЖЕН.** Раздел «Связано» канона содержит только ссылки, верные у всех
потребителей; ссылки на ADR, код и файлы конкретного репозитория — в
локальной части копии.
**ПОЧЕМУ.** Текст канона приезжает ко всем потребителям, и ссылка на чужой
файл у них битая с первого дня. Ниже маркера та же ссылка никого не
задевает и переживает обновление, потому что обновление её не трогает.
### META-22. Репозиторное в копии пишется ниже маркера локальной части
**ДОЛЖЕН.** Правки репозитория вносятся ниже маркера, а не в текст,
пришедший из канона.
**ПОЧЕМУ.** Обновление перезаписывает всё, что выше маркера, поэтому правка
там живёт до первого `pull`. Заметить пропажу можно, только вычитав
`git diff` целиком — а он в этот момент и без того полон изменений канона,
и своя строка теряется среди чужих.
### META-23. Документ, переставший быть копией, не носит `origin:`
**НЕ ДОЛЖЕН.** Файл, который развели с каноном намеренно, шапку `origin:`
не сохраняет.
**ПОЧЕМУ.** По `origin:` решается, какие файлы пересобирать из канона. Форк,
оставивший шапку, при первом же обновлении теряет ровно то, ради чего его
заводили. Происхождение такого документа остаётся в истории коммита, где оно
никого не вводит в заблуждение.
### META-18. README директории перечисляет конвенции с однострочным описанием
**СЛЕДУЕТ.** Одна плоская таблица: файл и строка о том, про что он.
**ПОЧЕМУ.** Подписка — это набор лежащих файлов, и без описаний вопрос
«какая из них про мой случай» решается открыванием каждой. Ценой в десяток
файлов это означает, что не открывают ни одной.
### META-19. Короткие инварианты дублируются в точку входа агента
**ДОЛЖЕН.** В `AGENTS.md` / `CLAUDE.md` едет одна строка на правило с его
идентификатором; детали остаются в конвенции.
**ПОЧЕМУ.** Сама по себе конвенция агенту не видна: он дойдёт до неё, только
если его туда отправили, — а безусловно он читает точку входа. Строка с
идентификатором служит и напоминанием, и адресом, по которому за
подробностями идут; перенос деталей туда же вернул бы задачу поддержки двух
текстов.
## Снятые правила
Снятое правило остаётся здесь заглушкой: номер занят навсегда, ссылка на него
ведёт к объяснению, а нумерация в файле остаётся сплошной (META-31).
### META-9. Общая механизация разрешала удалить норму из канона
**СНЯТО 2026-07-26.** Удаление нормы оставляло подписчика, пришедшего позже,
без текста и без проверки, а условие «механизировано у всех» набору не
проверить: списка подписчиков у него нет. Взамен — META-8, запрет удалять
норму вообще.
### META-16. Имя файла — kebab-case
**СНЯТО 2026-07-26.** Вреда от нарушения нет, а значит нет и высшей
модальности (META-25): сборка идёт по имени темы из шапки, а не по имени
файла. Осталось прозой в разделе «Оформление».
### META-26. Запрет слов обязательства в обосновании
**СНЯТО 2026-07-26.** Правило о заглавных уже делает строчное «обязан»
ненормативным, поэтому запрет ничего не добавлял, а форму обоснования рамками
не ограничивают.