Files
dev-conventions/LANGUAGE.md
T
av 840904d454 реестр префиксов перенесён в корень
- реестр покрывает и обвязку тоже (GUIDE.md), поэтому внутри conventions/
  он упирался в путь `../GUIDE.md`; теперь пути даются от корня репозитория
- README дополнен разделом про префиксы и строкой в таблице обвязки
2026-07-25 20:57:54 +03:00

16 KiB
Raw Blame History

Язык конвенций

Как записываются правила в этом каноне. Документ описывает форму, а не содержание: что такое правило, чем оно отличается от прозы вокруг и как на него сослаться.

Форма подсмотрена у OpenSpec, но взято оттуда не всё — см. «Чего мы не берём».

Зачем формализовать

Не ради строгости. Три конкретные вещи, которые без адресуемых правил не работают:

  • Механизация. Регион механизировано должен говорить «правило MIGR-4 проверяет archrules», а не «AUTOINCREMENT в новых миграциях — archrules»: во втором случае читатель сам догадывается, к какому утверждению это относится, и догадывается по-разному.
  • Отступления. «У нас не так» бесполезно, пока не сказано, что именно «не так». Со ссылкой на правило отступления становятся счётными: видно, сколько правил конвенции репозиторий реально не соблюдает.
  • Промоут находки. Путь «находка → конвенция → правило линтера → удаление прозы» требует ручки, за которую берут конкретное правило.

Общий знаменатель — идентификатор. Модальные слова и таблицы полезны, но вторичны.

Единица — правило

### KEYS-5. Разбор внешнего идентификатора на границе

**ДОЛЖЕН.** Идентификатор, пришедший снаружи, проходит разбор до запроса
к базе.

**Почему.** Разбор валидирует формат и нормализует регистр. Сравнение строк
в базе побайтовое, поэтому без нормализации запрос молча не находит
существующую запись — отладка такого случая стоит дороже, чем сам разбор.

Четыре обязательные части: идентификатор, заголовок, модальность с нормой, почему. Норма — одна фраза; если в неё не влезает, это два правила.

Правило без «почему» не принимается

Это жёсткое требование к форме, а не пожелание. Причины:

  • «Почему» — единственный способ понять, когда правило перестало действовать. Норма стареет молча; обоснование стареет заметно. Когда причина отпала, видно, что правило пора убрать, а не соблюдать по инерции.
  • Правило без обоснования не переживает спор. Через год ни автор, ни агент не восстановят мотив, и правило будет либо отменено первым же возражением, либо соблюдено там, где вредит.
  • Формулировка «почему» — проверка на то, что это вообще правило. Если причина не формулируется, перед нами привычка или вкусовщина; ей место в черновиках, а не в конвенции.

«Почему» отвечает на «что сломается, если сделать иначе», а не пересказывает норму другими словами. «Потому что так принято» — не обоснование.

Модальные слова

Пишутся капсом — это ключевые слова, а не обычный текст.

Слово Значение Отступление
ДОЛЖЕН нарушение считается ошибкой только с записью в регион отступления
НЕ ДОЛЖЕН запрет то же
СЛЕДУЕТ сильная рекомендация; новый код пишем так допустимо, причину записываем
НЕ СЛЕДУЕТ обратное к СЛЕДУЕТ то же
ДОПУСКАЕТСЯ явное разрешение не требуется — правило ничего не запрещает

ДОПУСКАЕТСЯ нужно не для симметрии: оно снимает вопрос «а так можно?» там, где соседнее правило звучит строго и его легко перечитать шире, чем задумано.

Модальность живёт на правиле, а не на файле. Прежний файловый статус (status: рекомендуемая / обязательная в шапке) отменён: он неизбежно врал, потому что один файл смешивает жёсткие требования с советами. В шапке остаются только prefix, extends и служебные ключи копии.

Мы не используем SHALL и прочие английские ключевые слова. Они заняты спецификациями (OpenSpec), и общий словарь стирал бы границу «конвенция — не capability». Разный словарь эту границу держит бесплатно.

Идентификаторы

  • Формат — <ПРЕФИКС>-<номер>: KEYS-5, SLOG-27. Префикс принадлежит файлу, нумерация внутри файла сквозная и начинается с единицы.
  • Строка таблицы, если на неё нужно ссылаться отдельно, — KEYS-5.1, KEYS-5.2.
  • Идентификатор глобален. Префикс уникален по всему канону, поэтому путь файла в ссылке не нужен: KEYS-5 адресует правило одинаково изнутри файла, из соседней конвенции и из чужого репозитория. В собранной копии слои разных осей лежат в одном документе, так что ссылка на базовый слой из языкового вообще никуда не ведёт — правило рядом.
  • Идентификаторы стабильны и не переиспользуются. Удалённое правило оставляет дыру в нумерации; занимать её новым нельзя — иначе ссылка из чужого репозитория начнёт указывать на другое утверждение. То же относится к префиксам: выбывшие хранит prefixes.toml.
  • Префикс выбирается под файл, а не выводится по формуле: он нужен, чтобы по нему искать, а не чтобы его разбирать. Выводимый префикс вдобавок привязал бы идентификатор к таксономии, которую канон перестраивает, и упёрся бы в потолок из числа букв алфавита.
  • Перенос правила в другой файл — смысловое изменение, а не переименование: новый файл означает новый префикс и новую нумерацию. Переезд самого файла между осями идентификаторы не трогает.

Порядок правил в файле выбирается по читаемости, не по номерам: номер — это идентификатор, а не позиция.

Правило, чья норма уехала в линтер

Когда правило механизировано у всех потребителей, его норма из канона удаляется, а обоснование — нет. Остаётся правило без модальности, и чтобы оно не выглядело недописанным, место нормы занимает отметка:

### MIGR-6. Дефолтов времени в схеме БД нет

**МЕХАНИЗИРОВАНО.** Проверяется общим правилом линтера; формулировка
удалена, потому что дублировала работающую проверку.

**Почему.** Дефолт превращает забытую вставку в тихо работающий код…
  • Идентификатор и заголовок сохраняются: ссылки из репозиториев продолжают указывать на то же утверждение.
  • «Почему» остаётся навсегда — линтер сообщает, что нарушено, но не сообщает, зачем правило существует, и без обоснования нельзя понять, когда проверку пора отменять.
  • МЕХАНИЗИРОВАНО — не шестое модальное слово: оно не задаёт обязательность, а сообщает, что обязательность теперь обеспечена машиной. В остальном такое правило равно ДОЛЖЕН.

Факт «механизировано у всех» устанавливается вручную: канон по построению не знает списка подписчиков, и обойти репозитории перед удалением нормы — часть работы, а не то, что можно проверить автоматически.

Таблицы вместо сценариев

Часть правил классифицирует ситуации: какой уровень лога, какая категория директории, что делать с невалидным вводом в зависимости от его источника. Для них каноническая форма — таблица «ситуация → вердикт», строки которой при необходимости нумеруются.

Таблица плотнее прозы и не даёт пропустить ветку: пустая клетка видна, а неупомянутый случай в абзаце — нет.

Чего мы не берём из OpenSpec

GIVEN/WHEN/THEN. У спецификации субъект — система, и её поведение разворачивается во времени: состояние, событие, исход. У конвенции субъект — автор кода, и разворачивать нечего: есть ситуация выбора и вердикт. Это таблица, а не траектория.

SHALL. См. выше про словарь.

Сценарии как общая форма. Прозаический сценарий остаётся точечным инструментом — для стыка правил, когда два правила вместе дают неочевидный результат:

WHEN зависимость недоступна и ретраи вызова исчерпаны → ext-запись ERROR
AND тик фонового цикла упал по той же причине        → доменная запись WARN

Такой блок ставится после обоих правил и ссылается на их номера. Если стыков нет — сценариев в файле нет.

Что правилом не является

Модальные слова в этих частях не употребляются — иначе перестанет быть понятно, что адресуемо, а что нет:

  • Область действия — на что конвенция распространяется во времени («новые таблицы; существующие не переписываются»). Это рамка для всех правил файла, а не правило.
  • Связано — ссылки на смежные конвенции, ADR, код.
  • Локальные регионы — содержимое принадлежит репозиторию.
  • Вводная проза, объясняющая предмет конвенции.

Как на правила ссылаются копии

В репозитории:

<!-- local:механизировано -->
MIGR-2, MIGR-4 — `internal/archrules` (проверяются в новых миграциях).
<!-- /local -->

<!-- local:отступления -->
MIGR-6 — не соблюдается в легаси-таблицах `show_history`, `queue`: составные
ключи там появились до конвенции, переписывание требует миграции данных.
<!-- /local -->

Отсюда видно и то, чего раньше не было видно: конвенция из восьми правил, из которых два механизированы и одно не соблюдается.

Что стоит проверять машиной

Сейчас не реализовано; список — на будущее для conv:

  • префикс в шапке файла совпадает с реестром, состоит из четырёх заглавных латинских букв и не значится в списке выбывших;
  • заголовки правил файла используют только его собственный префикс;
  • номера уникальны внутри файла и не имеют пропусков вниз (новое правило берёт следующий свободный, а не первый освободившийся);
  • у каждого ### <ПРЕФИКС>-<n> есть модальное слово (или отметка МЕХАНИЗИРОВАНО) и блок «Почему»;
  • ссылки вида <ПРЕФИКС>-<n> — хоть в тексте канона, хоть в локальных регионах копии — указывают на правила, которые ещё существуют;
  • модальные слова не встречаются вне правил.

Порядок перевода

Все конвенции канона записаны на этом языке. Новая конвенция пишется на нём сразу; смешение форм в каноне больше не предполагается.