--- 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.** Правило о заглавных уже делает строчное «обязан» ненормативным, поэтому запрет ничего не добавлял, а форму обоснования рамками не ограничивают.