язык: примеры переведены на вымышленные X-правила

- живые идентификаторы KEYS-5, SLOG-8.1, SLOG-27, MIGR-2/4/6 в примерах
  заменены на XKEY, XMIG, XLOG: номера канона означали не то, что в примере,
  и расходились дальше при каждой перенумерации
- сказано явно, что описание языка ни на один набор конвенций не опирается;
  ссылка на обоснования канона в разделе про ПОЧЕМУ заменена на внешние
  практики
This commit is contained in:
av
2026-07-26 15:15:30 +03:00
parent df8c58671f
commit d5118336cb
2 changed files with 41 additions and 52 deletions
+19 -13
View File
@@ -12,6 +12,12 @@ version: 1
пополниться, и текст, написанный по предыдущей версии, должен читаться по пополниться, и текст, написанный по предыдущей версии, должен читаться по
той, по которой написан. той, по которой написан.
Описание языка ни на один набор конвенций не опирается, поэтому все примеры
здесь — вымышленные правила с префиксами на `X` (`XKEY`, `XMIG`, `XLOG`).
Такие префиксы канон не занимает никогда, реестру они не принадлежат — значит
пример не спутать с настоящим правилом, а перенумерация конвенций описание
языка не задевает.
## Опора на стандарты ## Опора на стандарты
Язык не выводится из вкуса автора. Каждое решение о форме взято из Язык не выводится из вкуса автора. Каждое решение о форме взято из
@@ -56,7 +62,7 @@ version: 1
Адресуемое правило — не украшение формы, а условие работы трёх механизмов: Адресуемое правило — не украшение формы, а условие работы трёх механизмов:
- **Механизация.** Запись о ней должна говорить «правило `MIGR-4` проверяет - **Механизация.** Запись о ней должна говорить «правило `XMIG-4` проверяет
`archrules`», а не «`AUTOINCREMENT` в новых миграциях — `archrules`»: во `archrules`», а не «`AUTOINCREMENT` в новых миграциях — `archrules`»: во
втором случае читатель сам догадывается, к какому утверждению это втором случае читатель сам догадывается, к какому утверждению это
относится, и догадывается по-разному. относится, и догадывается по-разному.
@@ -72,7 +78,7 @@ version: 1
## Единица — правило ## Единица — правило
```markdown ```markdown
### KEYS-5. Разбор внешнего идентификатора на границе ### XKEY-5. Разбор внешнего идентификатора на границе
**ДОЛЖЕН.** Идентификатор, пришедший снаружи, проходит разбор до запроса **ДОЛЖЕН.** Идентификатор, пришедший снаружи, проходит разбор до запроса
к базе. к базе.
@@ -153,9 +159,9 @@ version: 1
Форма обоснования при этом ничем не ограничена: рамки здесь только Форма обоснования при этом ничем не ограничена: рамки здесь только
смысловые. Абзац может быть длинным, вести рассуждение, приводить пример, смысловые. Абзац может быть длинным, вести рассуждение, приводить пример,
ссылаться на внешние практики, стандарты и чужие проекты — канон это уже ссылаться на стандарты, внешние практики и чужие проекты — на устройство
делает («адаптация OpenTelemetry», «как по умолчанию в zap и zerolog», OpenTelemetry, на умолчания библиотек логирования, на процедуру миграции из
двенадцатишаговая процедура SQLite). Запрещённых слов и обязательной документации СУБД. Запрещённых слов и обязательной
структуры у обоснования нет, и заводить их не нужно: обязательность несёт структуры у обоснования нет, и заводить их не нужно: обязательность несёт
норма, а обоснование её объясняет — путаницу между этими двумя ролями норма, а обоснование её объясняет — путаницу между этими двумя ролями
исключает правило о заглавных. исключает правило о заглавных.
@@ -306,7 +312,7 @@ Directives, Part 2, по одной форме записи на ступень,
удаляется, а модальность и обоснование остаются: удаляется, а модальность и обоснование остаются:
```markdown ```markdown
### MIGR-6. Дефолтов времени в схеме БД нет ### XMIG-6. Дефолтов времени в схеме БД нет
**ДОЛЖЕН. МЕХАНИЗИРОВАНО.** Проверяется общим правилом линтера; **ДОЛЖЕН. МЕХАНИЗИРОВАНО.** Проверяется общим правилом линтера;
формулировка удалена, потому что дублировала работающую проверку. формулировка удалена, потому что дублировала работающую проверку.
@@ -331,7 +337,7 @@ Directives, Part 2, по одной форме записи на ступень,
Часть правил **классифицирует ситуации**: какой уровень лога, какая Часть правил **классифицирует ситуации**: какой уровень лога, какая
категория директории, что делать с невалидным вводом в зависимости от его категория директории, что делать с невалидным вводом в зависимости от его
источника. Каноническая форма для них — таблица «ситуация → вердикт», строки источника. Каноническая форма для них — таблица «ситуация → вердикт», строки
которой нумеруются как подпункты правила (`SLOG-8.1`). которой нумеруются как подпункты правила (`XLOG-8.1`).
Таблица плотнее прозы и не даёт пропустить ветку: пустая клетка видна, а Таблица плотнее прозы и не даёт пропустить ветку: пустая клетка видна, а
неупомянутый случай в абзаце — нет. Два свойства такой таблицы взяты из DMN, неупомянутый случай в абзаце — нет. Два свойства такой таблицы взяты из DMN,
@@ -379,12 +385,12 @@ Directives, Part 2, по одной форме записи на ступень,
## Идентификаторы ## Идентификаторы
- Формат — `<ПРЕФИКС>-<номер>`: `KEYS-5`, `SLOG-27`. Префикс принадлежит - Формат — `<ПРЕФИКС>-<номер>`: `XKEY-5`, `XLOG-27`. Префикс принадлежит
файлу, нумерация внутри файла сквозная и начинается с единицы. файлу, нумерация внутри файла сквозная и начинается с единицы.
- Строка таблицы, если на неё нужно ссылаться отдельно, — `KEYS-5.1`, - Строка таблицы, если на неё нужно ссылаться отдельно, — `XKEY-5.1`,
`KEYS-5.2`. `XKEY-5.2`.
- **Идентификатор глобален.** Префикс уникален по всему канону, поэтому - **Идентификатор глобален.** Префикс уникален по всему канону, поэтому
путь файла в ссылке не нужен: `KEYS-5` адресует правило одинаково изнутри путь файла в ссылке не нужен: `XKEY-5` адресует правило одинаково изнутри
файла, из соседней конвенции и из чужого репозитория. В собранной копии файла, из соседней конвенции и из чужого репозитория. В собранной копии
слои разных осей лежат в одном документе, так что ссылка на базовый слой слои разных осей лежат в одном документе, так что ссылка на базовый слой
из языкового вообще никуда не ведёт — правило рядом. из языкового вообще никуда не ведёт — правило рядом.
@@ -428,10 +434,10 @@ Directives, Part 2, по одной форме записи на ступень,
```markdown ```markdown
<!-- conv:local --> <!-- conv:local -->
MIGR-2, MIGR-4 механизированы — `internal/archrules` (проверяются в новых XMIG-2, XMIG-4 механизированы — `internal/archrules` (проверяются в новых
миграциях). миграциях).
MIGR-6 не соблюдается в легаси-таблицах `show_history`, `queue`: составные XMIG-6 не соблюдается в легаси-таблицах `show_history`, `queue`: составные
ключи там появились до конвенции, переписывание требует миграции данных. ключи там появились до конвенции, переписывание требует миграции данных.
``` ```
+22 -39
View File
@@ -4,31 +4,12 @@
решения. Закрытый вопрос отсюда удаляется — принятое решение живёт в решения. Закрытый вопрос отсюда удаляется — принятое решение живёт в
`README.md`, `GUIDE.md` или `LANGUAGE.md`, а не в этом файле. `README.md`, `GUIDE.md` или `LANGUAGE.md`, а не в этом файле.
Две секции: сначала язык и подход, потом канон с тулингом. Пункты 1–7 Две секции: сначала язык и подход, потом канон с тулингом. Пункты 1–6
пришли из внешнего ревью описания языка и проверены по файлам на месте. пришли из внешнего ревью описания языка и проверены по файлам на месте.
# Язык и подход # Язык и подход
## 1. Примеры в LANGUAGE.md сидят на живых идентификаторах ## 1. «Тема» — несущий идентификатор без определения и реестра
Учебные примеры используют настоящие префиксы канона с номерами, которые в
каноне означают другое:
| В примере `LANGUAGE.md` | В каноне на самом деле |
|---|---|
| `MIGR-4` проверяет `AUTOINCREMENT` в новых миграциях | MIGR-4 — «В деплое схема движется только вперёд»; про AUTOINCREMENT — MIGR-12 |
| «MIGR-6. Дефолтов времени в схеме БД нет» | MIGR-6 — «ER-схема обновляется в том же изменении»; дефолты — MIGR-9 |
| «KEYS-5. Разбор внешнего идентификатора на границе» | KEYS-5 — «Внешний идентификатор разбирается до обращения к базе», с другим текстом нормы |
Язык держится на том, что идентификатор адресует ровно одно утверждение, и
документ, определяющий язык, это нарушает. Ни одна проверка не поймает —
идентификаторы существуют. Дрейф вдобавок гарантирован: канон
перенумеровывался, примеры не двигались.
Лечится дёшево: примеры берут префиксы на `X`, зарезервированные как раз под
то, что каноном не занято.
## 2. «Тема» — несущий идентификатор без определения и реестра
META-21 велит ссылаться на соседнюю конвенцию именем темы, манифест META-21 велит ссылаться на соседнюю конвенцию именем темы, манифест
подписывается `topics = ["time", …]`, сборка собирает файл темы из слоёв — подписывается `topics = ["time", …]`, сборка собирает файл темы из слоёв —
@@ -41,13 +22,13 @@ META-21 велит ссылаться на соседнюю конвенцию
файла темы тихо осиротит все текстовые ссылки во всех копиях. файла темы тихо осиротит все текстовые ссылки во всех копиях.
Вопрос уже не гипотетический: пара `arch/db-identifiers.md` против Вопрос уже не гипотетический: пара `arch/db-identifiers.md` против
`lang/go/db-schema.md` (см. вопрос 11) показывает, что имена слоёв одной `lang/go/db-schema.md` (см. вопрос 10) показывает, что имена слоёв одной
темы могут не совпадать. Смежно: `extends: arch/time.md` у SLOG ломает темы могут не совпадать. Смежно: `extends: arch/time.md` у SLOG ломает
гарантию META-24 («базовый слой отсутствовать не может») — она верна только гарантию META-24 («базовый слой отсутствовать не может») — она верна только
для базы своей темы, а машинной проверке негде узнать тему, кроме имени для базы своей темы, а машинной проверке негде узнать тему, кроме имени
файла. файла.
## 3. GUIDE выведен из-под проверок ложным основанием ## 2. GUIDE выведен из-под проверок ложным основанием
`LANGUAGE.md` исключает обвязку из проверок формулировкой «она ключевые слова `LANGUAGE.md` исключает обвязку из проверок формулировкой «она ключевые слова
цитирует, а не употребляет». Для `GUIDE.md` это неверно: META-правила цитирует, а не употребляет». Для `GUIDE.md` это неверно: META-правила
@@ -63,7 +44,7 @@ META-21 велит ссылаться на соседнюю конвенцию
Честнее развести: `GUIDE.md` язык **употребляет** и проверяется как Честнее развести: `GUIDE.md` язык **употребляет** и проверяется как
конвенция, `LANGUAGE.md` и `README.md` — цитируют. конвенция, `LANGUAGE.md` и `README.md` — цитируют.
## 4. МЕХАНИЗИРОВАНО не переживает нового подписчика ## 3. МЕХАНИЗИРОВАНО не переживает нового подписчика
META-8 запрещает удалять норму, пока механизирована не у всех, и защищает META-8 запрещает удалять норму, пока механизирована не у всех, и защищает
тем самым потребителей, существующих **на момент удаления**. Будущих не тем самым потребителей, существующих **на момент удаления**. Будущих не
@@ -81,7 +62,7 @@ META-8 запрещает удалять норму, пока механизир
в тексте канона, то есть ровно то, что запрещает META-4. Либо это законное в тексте канона, то есть ровно то, что запрещает META-4. Либо это законное
исключение, и тогда его надо назвать, либо конфликт. исключение, и тогда его надо назвать, либо конфликт.
## 5. Семантика ключевых слов в копию не едет ## 4. Семантика ключевых слов в копию не едет
Строка о версии языка перечисляет слова, но не их значения, а всё Строка о версии языка перечисляет слова, но не их значения, а всё
нетривиальное в шкале живёт только в `LANGUAGE.md`, который в репозиторий не нетривиальное в шкале живёт только в `LANGUAGE.md`, который в репозиторий не
@@ -97,7 +78,7 @@ META-8 запрещает удалять норму, пока механизир
копиями короткую выжимку семантики; расширить строку о версии до копиями короткую выжимку семантики; расширить строку о версии до
двух-трёх предложений; или признать ограничение и записать его явно. двух-трёх предложений; или признать ограничение и записать его явно.
## 6. Две «механические» проверки без источника данных ## 5. Две «механические» проверки без источника данных
В списке «разбором текста» стоят два пункта, которые без дополнительного В списке «разбором текста» стоят два пункта, которые без дополнительного
реестра нерешаемы: реестра нерешаемы:
@@ -113,7 +94,7 @@ META-8 запрещает удалять норму, пока механизир
реестр снятых номеров не объявлен частью языка, оба пункта принадлежат реестр снятых номеров не объявлен частью языка, оба пункта принадлежат
списку «чтением». списку «чтением».
## 7. Натяжки в опоре на стандарты ## 6. Натяжки в опоре на стандарты
Три места, где источнику приписано чуть больше, чем в нём есть: Три места, где источнику приписано чуть больше, чем в нём есть:
@@ -132,7 +113,7 @@ META-8 запрещает удалять норму, пока механизир
Остальное в таблице проверку выдержало, включая вторую половину `MAY` из Остальное в таблице проверку выдержало, включая вторую половину `MAY` из
BCP 14 и списки эквивалентных словесных форм ISO Directives. BCP 14 и списки эквивалентных словесных форм ISO Directives.
## 8. Одиннадцать таблиц не прочитаны на взаимоисключительность ## 7. Одиннадцать таблиц не прочитаны на взаимоисключительность
`LANGUAGE.md` объявил, что строки таблицы решений взаимоисключающи по `LANGUAGE.md` объявил, что строки таблицы решений взаимоисключающи по
умолчанию, а иной порядок объявляется явно. Объявление не делает таблицы умолчанию, а иной порядок объявляется явно. Объявление не делает таблицы
@@ -147,7 +128,7 @@ BCP 14 и списки эквивалентных словесных форм IS
Работа читательская, машине не даётся; в список проверок она уже записана в Работа читательская, машине не даётся; в список проверок она уже записана в
разделе «Чтением, потому что машине не даётся». разделе «Чтением, потому что машине не даётся».
## 9. Описание языка отдельно от набора конвенций ## 8. Описание языка отдельно от набора конвенций
`LANGUAGE.md` и `GUIDE.md` описывают, **как** пишутся конвенции; `LANGUAGE.md` и `GUIDE.md` описывают, **как** пишутся конвенции;
`conventions/`**один конкретный** набор. Сейчас они склеены в одном `conventions/`**один конкретный** набор. Сейчас они склеены в одном
@@ -156,7 +137,9 @@ BCP 14 и списки эквивалентных словесных форм IS
Срочности нет: версия языка объявлена в самом `LANGUAGE.md` (ключ Срочности нет: версия языка объявлена в самом `LANGUAGE.md` (ключ
`version:`), и конвенции ссылаются на неё номером, а не путём, — то есть `version:`), и конвенции ссылаются на неё номером, а не путём, — то есть
самодостаточность копии выноса не требует. самодостаточность копии выноса не требует. Примеры в `LANGUAGE.md` вдобавок
переведены на вымышленные `X`-правила, так что на конкретный набор описание
языка больше не ссылается вовсе.
Что осталось поводом: Что осталось поводом:
@@ -170,7 +153,7 @@ BCP 14 и списки эквивалентных словесных форм IS
# Канон, тулинг, подключение # Канон, тулинг, подключение
## 10. Тулинг: две разные задачи в одном `conv` ## 9. Тулинг: две разные задачи в одном `conv`
Сейчас в `conv` смешаны две категории работы, и они расходятся по всему — Сейчас в `conv` смешаны две категории работы, и они расходятся по всему —
по частоте запуска, по тому, кто запускает, и по тому, что считается по частоте запуска, по тому, кто запускает, и по тому, что считается
@@ -201,7 +184,7 @@ BCP 14 и списки эквивалентных словесных форм IS
ссылках: это установка, а не целостность, но список подписок ему нужен из ссылках: это установка, а не целостность, но список подписок ему нужен из
манифеста. манифеста.
Часть проверок из этого списка сейчас нереализуема по причине из вопроса 6, Часть проверок из этого списка сейчас нереализуема по причине из вопроса 5,
так что порядок такой: сначала язык, потом чекер. так что порядок такой: сначала язык, потом чекер.
Перед тем как переписывать, стоит посмотреть на два готовых прототипа: Перед тем как переписывать, стоит посмотреть на два готовых прототипа:
@@ -209,14 +192,14 @@ BCP 14 и списки эквивалентных словесных форм IS
манифеста и `vendir.yml` — как пример того, где проходит граница между «чего манифеста и `vendir.yml` — как пример того, где проходит граница между «чего
хочу» и «что получил». хочу» и «что получил».
## 11. Пары слоёв и темы без базы ## 10. Пары слоёв и темы без базы
Отложено сознательно, но список стоит держать перед глазами: Отложено сознательно, но список стоит держать перед глазами:
- `SLOG` объявляет `extends: arch/time.md` — расширение **чужой** темы. - `SLOG` объявляет `extends: arch/time.md` — расширение **чужой** темы.
Сборщик темы `logging` на это наткнётся: базового слоя с темой `logging` Сборщик темы `logging` на это наткнётся: базового слоя с темой `logging`
нет, а `arch/time.md` он тянуть не должен. Чинится переводом в обычную нет, а `arch/time.md` он тянуть не должен. Чинится переводом в обычную
ссылку «связано». Вдобавок это ломает гарантию META-24 — см. вопрос 2. ссылку «связано». Вдобавок это ломает гарантию META-24 — см. вопрос 1.
- Темы без арх-слоя: `db-schema`, `errors`, `web-ui`. Собираются в файл с - Темы без арх-слоя: `db-schema`, `errors`, `web-ui`. Собираются в файл с
одной секцией — само по себе не ломается, но это и есть тот невыделенный одной секцией — само по себе не ломается, но это и есть тот невыделенный
арх-слой из известного долга. арх-слой из известного долга.
@@ -228,7 +211,7 @@ BCP 14 и списки эквивалентных словесных форм IS
- Вынос арх-ядра из `errors` и `logging` закроет две хрупкие ссылки из - Вынос арх-ядра из `errors` и `logging` закроет две хрупкие ссылки из
`web-ui` (стек) в go-слой — единственные ссылки стек → язык в каноне. `web-ui` (стек) в go-слой — единственные ссылки стек → язык в каноне.
## 12. Подключение к репозиториям ## 11. Подключение к репозиториям
Ничего ещё не подключено. Кандидаты — jellybit и pet-project-server. Ничего ещё не подключено. Кандидаты — jellybit и pet-project-server.
Понадобится: заполнить локальную часть копий тем, что сейчас в этих Понадобится: заполнить локальную часть копий тем, что сейчас в этих
@@ -237,7 +220,7 @@ BCP 14 и списки эквивалентных словесных форм IS
строка в `AGENTS.md` каждого потребителя про то, что файлы в строка в `AGENTS.md` каждого потребителя про то, что файлы в
`docs/conventions/` — копии. `docs/conventions/` — копии.
## 13. Тулинг на Go, живущий независимо ## 12. Тулинг на Go, живущий независимо
Сейчас `conv` — питоновский скрипт внутри канона, то есть тулинг и данные в Сейчас `conv` — питоновский скрипт внутри канона, то есть тулинг и данные в
одном репозитории и правятся одним движением. Мысль: вынести в отдельный одном репозитории и правятся одним движением. Мысль: вынести в отдельный
@@ -246,10 +229,10 @@ Go-бинарь со своим релизным циклом, ставить ч
Что за этим стоит помимо вкуса: независимый бинарь физически не даёт править Что за этим стоит помимо вкуса: независимый бинарь физически не даёт править
инструмент «заодно» с правкой конвенции, работает против **любого** канона и инструмент «заодно» с правкой конвенции, работает против **любого** канона и
любого потребителя — что прямо требуется вопросом 9, — и снимает питон из любого потребителя — что прямо требуется вопросом 8, — и снимает питон из
зависимостей репозиториев-потребителей. зависимостей репозиториев-потребителей.
Порядок обратный ожидаемому: пока вопрос 9 не сделан, инструмент всё равно Порядок обратный ожидаемому: пока вопрос 8 не сделан, инструмент всё равно
работает против одного конкретного канона, и независимый релизный цикл ему работает против одного конкретного канона, и независимый релизный цикл ему
нечего обслуживать. Сначала 9, потом 13. Разделение из вопроса 10 при этом нечего обслуживать. Сначала 8, потом 12. Разделение из вопроса 9 при этом
дешевле заложить сразу, чем отпиливать потом. дешевле заложить сразу, чем отпиливать потом.