темы: определение, объявление в шапке и манифест набора

- тема — набор правил об одном фокусе разработки, имя латиницей (нижний
  kebab-case рекомендуется, годится любой идентификатор, пригодный для имени
  файла); определение в LANGUAGE.md и README.md
- заведены META-28 и META-29: тема объявляется в шапке (`topic:`), стоит в
  манифесте набора и не переиспользуется; `topic:` добавлен во все 12 файлов
- prefixes.toml и topics.toml слиты в manifest.toml — манифест набора против
  манифеста подключения `.conventions.toml`, разделы topics/prefixes с live
  и retired
This commit is contained in:
av
2026-07-26 15:27:55 +03:00
parent d5118336cb
commit c1cb240540
19 changed files with 274 additions and 126 deletions
+21 -13
View File
@@ -9,7 +9,7 @@ code in this repository.
Канон конвенций разработки для личных проектов. Сами конвенции лежат в Канон конвенций разработки для личных проектов. Сами конвенции лежат в
`conventions/{arch,lang/<язык>,stack/<стек>}/`; обвязка канона (`README.md`, `conventions/{arch,lang/<язык>,stack/<стек>}/`; обвязка канона (`README.md`,
`LANGUAGE.md`, `GUIDE.md`, `prefixes.toml`, `conv`) живёт в корне и в `LANGUAGE.md`, `GUIDE.md`, `manifest.toml`, `conv`) живёт в корне и в
репозитории-потребители не едет. репозитории-потребители не едет.
Ниже — короткие инварианты с идентификаторами; детали и обоснования в Ниже — короткие инварианты с идентификаторами; детали и обоснования в
@@ -60,18 +60,27 @@ code in this repository.
действия. действия.
- Модальность принадлежит правилу, а не файлу: `status:` в шапке отменён. - Модальность принадлежит правилу, а не файлу: `status:` в шапке отменён.
## Идентификаторы и префиксы ## Идентификаторы: тема и префикс
- Тема — набор правил об одном фокусе разработки и единица подписки. Имя —
латиницей, рекомендуется нижний kebab-case, годится любой идентификатор,
пригодный для имени файла.
- META-28: тема объявлена в шапке (`topic: time`) и стоит в манифесте набора
(`manifest.toml`, секция `[topics.live]`). Слои одной темы несут одно имя —
по нему собираются в один файл, как бы ни назывались их файлы; имя файла
повторяет тему из удобства.
- META-29: имя темы не переиспользуется, снятое уходит в `[topics.retired]`
с причиной и датой. Оно живёт в `origin:` копий и в подписках манифестов.
- Формат `<ПРЕФИКС>-<номер>`, нумерация сквозная внутри файла. Порядок правил - Формат `<ПРЕФИКС>-<номер>`, нумерация сквозная внутри файла. Порядок правил
в файле — по читаемости: номер это идентификатор, а не позиция. в файле — по читаемости: номер это идентификатор, а не позиция.
- Идентификаторы не переиспользуются. Удалённое правило оставляет дыру, новое - Идентификаторы не переиспользуются. Удалённое правило оставляет дыру, новое
берёт следующий свободный номер, а не первый освободившийся. берёт следующий свободный номер, а не первый освободившийся.
- Новый файл конвенции — новый префикс: четыре заглавные латинские буквы, - Новый файл конвенции — новый префикс: четыре заглавные латинские буквы,
уникальные по всему канону, выбираются под файл, а не выводятся по формуле. уникальные по всему канону, выбираются под файл, а не выводятся по формуле.
Объявляется в шапке (`prefix: KEYS`) и регистрируется в `prefixes.toml`, Объявляется в шапке (`prefix: KEYS`) и регистрируется в манифесте набора,
секция `[live]`, путём от корня репозитория. секция `[prefixes.live]`, путём от корня репозитория.
- Удаление или разделение файла: префикс уходит в `[retired]` с причиной и - Удаление или разделение файла: префикс уходит в `[prefixes.retired]` с
датой, а не освобождается. причиной и датой, а не освобождается.
- Префиксы на букву `X` канон не занимает: они зарезервированы за локальными - Префиксы на букву `X` канон не занимает: они зарезервированы за локальными
правилами репозиториев-потребителей. правилами репозиториев-потребителей.
- Перенос правила в другой файл — смысловое изменение: новый префикс и новый - Перенос правила в другой файл — смысловое изменение: новый префикс и новый
@@ -121,13 +130,12 @@ code in this repository.
## Оформление файла ## Оформление файла
Шапка `prefix:` (плюс `extends:`) → `# Тема` → вводная проза → отдельным Шапка `topic:` и `prefix:` (плюс `extends:`) → `# Тема` → вводная проза →
абзацем строка о версии языка (её точный текст — в `LANGUAGE.md`, раздел отдельным абзацем строка о версии языка (её точный текст — в `LANGUAGE.md`,
«Ссылка на язык из конвенции») → `## Область действия` (обязателен для раздел «Ссылка на язык из конвенции») → `## Область действия` (обязателен для
трудноизменяемых слоёв — META-11) → правила → `## Связано`, если трудноизменяемых слоёв — META-11) → правила → `## Связано`, если канонические
канонические ссылки есть (META-17; пустого раздела не заводят). Имя файла ссылки есть (META-17; пустого раздела не заводят). Имя файла повторяет имя
kebab-case по теме. Проза темы. Проза переносится по ~76 колонок; таблицы и блоки кода не переносятся.
переносится по ~76 колонок; таблицы и блоки кода не переносятся.
## Ревью формы ## Ревью формы
+28 -4
View File
@@ -32,11 +32,11 @@ prefix: META
## Оформление ## Оформление
Имя файла — kebab-case по теме: `app-directories.md`. Правилом это не Имя файла повторяет имя темы: `app-directories.md`. Правилом это не
записано, и это случай META-25: регуляркой имя проверяется тривиально, но записано, и это случай META-25: регуляркой имя проверяется тривиально, но
обоснование сводится к «чтобы имя файла в реестре префиксов писалось одним вреда от нарушения нет — тема объявлена в шапке (META-28), и сборка идёт по
способом» — вреда от нарушения нет, значит и высшей модальности нет, а на объявленному имени, а не по имени файла. Значит, и высшей модальности нет, а
СЛЕДУЕТ такое правило не окупает строчку. на СЛЕДУЕТ такое правило не окупает строчку.
## Канон и копии ## Канон и копии
@@ -68,6 +68,30 @@ prefix: META
дорого: перенос правила в другой файл — это новый префикс и новая дорого: перенос правила в другой файл — это новый префикс и новая
нумерация, поэтому после разреза все внешние ссылки обходят руками. нумерация, поэтому после разреза все внешние ссылки обходят руками.
### META-28. Тема объявляется в шапке файла и стоит в манифесте набора
**ДОЛЖЕН.** Шапка несёт ключ `topic:` с именем темы, и это имя стоит в
манифесте набора.
**ПОЧЕМУ.** Тема — единица подписки и единица сборки: потребитель перечисляет
темы в своём манифесте, а сборщик складывает в один файл все слои темы. Пока
имя выводится из имени файла, у сборщика нет способа узнать, что два слоя,
названные по-разному, — один документ; переименование файла при этом молча
заводит новую тему, подписка перестаёт находить прежнюю, а ссылки «конвенция
`logging`» в копиях остаются висеть. Объявленное имя вдобавок сверяется с
манифестом — выведенное сверять не с чем.
### META-29. Имя темы не переиспользуется
**НЕ ДОЛЖЕН.** Снятое или переименованное имя темы другой теме не выдаётся:
оно уходит в раздел выбывших манифеста с причиной и датой.
**ПОЧЕМУ.** Имя темы живёт в чужих репозиториях — в шапке `origin:` каждой
копии, в подписке потребителя, в тексте ссылок. Выданное второй теме, оно
начинает указывать на другой набор правил, и обнаруживается это не на сборке,
а по содержанию: файл обновится штатно, изменится текст. Та же дисциплина и по
той же причине действует для префиксов правил.
### META-2. Конвенция заводится, когда решение принимается третий раз ### META-2. Конвенция заводится, когда решение принимается третий раз
**СЛЕДУЕТ.** Поводом служит одно и то же решение, принятое третий раз и **СЛЕДУЕТ.** Поводом служит одно и то же решение, принятое третий раз и
+34 -4
View File
@@ -14,7 +14,7 @@ version: 1
Описание языка ни на один набор конвенций не опирается, поэтому все примеры Описание языка ни на один набор конвенций не опирается, поэтому все примеры
здесь — вымышленные правила с префиксами на `X` (`XKEY`, `XMIG`, `XLOG`). здесь — вымышленные правила с префиксами на `X` (`XKEY`, `XMIG`, `XLOG`).
Такие префиксы канон не занимает никогда, реестру они не принадлежат — значит Такие префиксы канон не занимает никогда, в манифесте набора их нет — значит
пример не спутать с настоящим правилом, а перенумерация конвенций описание пример не спутать с настоящим правилом, а перенумерация конвенций описание
языка не задевает. языка не задевает.
@@ -219,7 +219,7 @@ Directives, Part 2, по одной форме записи на ступень,
Модальность живёт на **правиле**, а не на файле. Файловый статус Модальность живёт на **правиле**, а не на файле. Файловый статус
(`status: рекомендуемая` / `обязательная` в шапке) не используется: он (`status: рекомендуемая` / `обязательная` в шапке) не используется: он
неизбежно врёт, потому что один файл смешивает жёсткие требования с неизбежно врёт, потому что один файл смешивает жёсткие требования с
советами. В шапке остаются только `prefix` и `extends`. советами. В шапке остаются только `topic`, `prefix` и `extends`.
## Словарь другого языка ## Словарь другого языка
@@ -385,6 +385,12 @@ Directives, Part 2, по одной форме записи на ступень,
## Идентификаторы ## Идентификаторы
Идентификаторов в языке два: **правило** адресуется префиксом с номером,
**конвенция целиком** — именем темы. Ссылаться путём к файлу нельзя ни на то,
ни на другое.
**Правило.**
- Формат — `<ПРЕФИКС>-<номер>`: `XKEY-5`, `XLOG-27`. Префикс принадлежит - Формат — `<ПРЕФИКС>-<номер>`: `XKEY-5`, `XLOG-27`. Префикс принадлежит
файлу, нумерация внутри файла сквозная и начинается с единицы. файлу, нумерация внутри файла сквозная и начинается с единицы.
- Строка таблицы, если на неё нужно ссылаться отдельно, — `XKEY-5.1`, - Строка таблицы, если на неё нужно ссылаться отдельно, — `XKEY-5.1`,
@@ -397,7 +403,7 @@ Directives, Part 2, по одной форме записи на ступень,
- **Идентификаторы стабильны и не переиспользуются.** Удалённое правило - **Идентификаторы стабильны и не переиспользуются.** Удалённое правило
оставляет дыру в нумерации; занимать её новым нельзя — иначе ссылка из оставляет дыру в нумерации; занимать её новым нельзя — иначе ссылка из
чужого репозитория начнёт указывать на другое утверждение. То же чужого репозитория начнёт указывать на другое утверждение. То же
относится к префиксам: выбывшие хранит `prefixes.toml`. относится к префиксам: выбывшие хранит манифест набора.
- Префикс **выбирается под файл, а не выводится по формуле**: он нужен, - Префикс **выбирается под файл, а не выводится по формуле**: он нужен,
чтобы по нему искать, а не чтобы его разбирать. Выводимый префикс вдобавок чтобы по нему искать, а не чтобы его разбирать. Выводимый префикс вдобавок
привязал бы идентификатор к таксономии, которую канон перестраивает, и привязал бы идентификатор к таксономии, которую канон перестраивает, и
@@ -411,6 +417,25 @@ Directives, Part 2, по одной форме записи на ступень,
Порядок правил в файле выбирается по читаемости, не по номерам: номер — это Порядок правил в файле выбирается по читаемости, не по номерам: номер — это
идентификатор, а не позиция. идентификатор, а не позиция.
**Тема.**
- **Тема — набор правил об одном фокусе разработки:** время, конфигурация,
схема БД. Она же — единица подписки: потребитель берёт тему целиком, а не
отдельные правила.
- Имя темы записывается латиницей. Рекомендуется нижний kebab-case
(`db-identifiers`), но годится любой идентификатор, пригодный для имени
файла: имя попадает и в файловую систему потребителя, и в его манифест.
- **Тему объявляет файл, а не файловая система.** Имя стоит в шапке
(`topic:`) и зарегистрировано в манифесте набора. Слои одной темы несут
одно и то же имя — по нему они и собираются в один документ, как бы ни
назывались их файлы.
- **Имя темы не переиспользуется** — как и префикс: оно живёт в шапке
`origin:` каждой копии, в подписке манифеста и в тексте ссылок, поэтому
снятое имя уходит в раздел выбывших манифеста, а не достаётся другой теме.
- Ссылка на конвенцию — имя темы (конвенция `logging`), ссылка на правило —
идентификатор (`XLOG-27`). Путь файла не употребляется ни там, ни там: в
собранной копии путей канона не существует.
## Что правилом не является ## Что правилом не является
Заглавные модальные слова в этих частях **не употребляются** — иначе Заглавные модальные слова в этих частях **не употребляются** — иначе
@@ -454,8 +479,13 @@ XMIG-6 не соблюдается в легаси-таблицах `show_histor
- модальные и служебные слова принадлежат объявленному словарю канона, а не - модальные и служебные слова принадлежат объявленному словарю канона, а не
смеси словарей; смеси словарей;
- префикс в шапке файла совпадает с реестром, состоит из четырёх заглавных - префикс в шапке файла совпадает с манифестом набора, состоит из четырёх
заглавных
латинских букв, не начинается на `X` и не значится в списке выбывших; латинских букв, не начинается на `X` и не значится в списке выбывших;
- шапка файла несёт имя темы, и это имя стоит в манифесте набора — среди
живых, а не среди выбывших;
- имя темы, названное в ссылке или в подписке потребителя, тоже разрешается по
манифесту: ссылка на снятую тему не проходит молча;
- заголовки правил файла используют только его собственный префикс; - заголовки правил файла используют только его собственный префикс;
- номера уникальны внутри файла и не имеют пропусков вниз (новое правило - номера уникальны внутри файла и не имеют пропусков вниз (новое правило
берёт следующий свободный, а не первый освободившийся); берёт следующий свободный, а не первый освободившийся);
+54 -16
View File
@@ -12,7 +12,7 @@
| `README.md` | устройство канона, оси, сборка копий, жизненный цикл | | `README.md` | устройство канона, оси, сборка копий, жизненный цикл |
| [LANGUAGE.md](LANGUAGE.md) | язык записи правил: идентификаторы, модальность, обоснование | | [LANGUAGE.md](LANGUAGE.md) | язык записи правил: идентификаторы, модальность, обоснование |
| [GUIDE.md](GUIDE.md) | как ведут конвенции: когда заводить, механизация, отступления | | [GUIDE.md](GUIDE.md) | как ведут конвенции: когда заводить, механизация, отступления |
| `prefixes.toml` | реестр префиксов правил | | [manifest.toml](manifest.toml) | манифест набора: темы и префиксы правил |
| `conv` | сборка копий | | `conv` | сборка копий |
Обвязка живёт только в каноне и в репозитории не оказывается — в копию едет Обвязка живёт только в каноне и в репозитории не оказывается — в копию едет
@@ -55,8 +55,9 @@ conventions/
тему. Пути файлов даются относительно `conventions/` тему. Пути файлов даются относительно `conventions/`
(`arch/db-identifiers.md`) и адресуют исходник канона, а не место в копии. (`arch/db-identifiers.md`) и адресуют исходник канона, а не место в копии.
На **правила** ссылаются идентификатором без пути: `KEYS-5`. Префикс На **правила** ссылаются идентификатором без пути: `KEYS-5`. Префикс
уникален по всему канону (реестр — `prefixes.toml`), поэтому идентификатор уникален по всему канону (он перечислен в манифесте набора), поэтому
не зависит ни от оси, ни от того, как собран файл у потребителя. идентификатор не зависит ни от оси, ни от того, как собран файл у
потребителя.
Тест — по тому, замена чего убивает правило: Тест — по тому, замена чего убивает правило:
@@ -81,6 +82,31 @@ conventions/
пласт `stack/sqlite/` (типы колонок). Это не принцип, а незавершённая пласт `stack/sqlite/` (типы колонок). Это не принцип, а незавершённая
работа. работа.
## Темы
**Тема — набор правил об одном фокусе разработки:** время, конфигурация,
схема БД. Она же единица подписки и единица сборки: потребитель берёт тему
целиком, а сборщик складывает в один файл все её слои.
Имя темы записывается латиницей; рекомендуется нижний kebab-case, но годится
любой идентификатор, пригодный для имени файла — имя попадает и в файловую
систему потребителя, и в его манифест. Файл конвенции объявляет тему в шапке:
```yaml
topic: db-identifiers
prefix: KEYS
```
Слои одной темы несут одно и то же имя — по нему они и собираются в один
документ, как бы ни назывались их файлы. Имя файла повторяет тему из
удобства, но истина — в шапке.
Темы перечислены в манифесте набора — [`manifest.toml`](manifest.toml),
секция `[topics.live]`: имя и однострочное описание. Имя темы не
переиспользуется по той же причине, что и префикс: оно живёт в чужих
репозиториях — в шапке `origin:` каждой копии, в подписке манифеста, в тексте
ссылок, — и выданное второй теме начинает указывать на другой набор правил.
## Префиксы ## Префиксы
Каждый файл канона объявляет в шапке свой префикс правил: Каждый файл канона объявляет в шапке свой префикс правил:
@@ -89,10 +115,11 @@ conventions/
prefix: KEYS prefix: KEYS
``` ```
Четыре заглавные латинские буквы, уникальные по всему канону; реестр — Четыре заглавные латинские буквы, уникальные по всему канону; перечислены в
[`prefixes.toml`](prefixes.toml). Префикс выбирается под файл, а не выводится манифесте набора, секция `[prefixes.live]`. Префикс выбирается под файл, а не
по формуле, и не переиспользуется никогда. Правила адресуются идентификатором выводится по формуле, и не переиспользуется никогда. Правила адресуются
`KEYS-5` — без пути к файлу. Подробности формы — `LANGUAGE.md`. идентификатором `KEYS-5` — без пути к файлу. Подробности формы —
`LANGUAGE.md`.
Буква `X` в начале префикса зарезервирована за репозиториями: канон её не Буква `X` в начале префикса зарезервирована за репозиториями: канон её не
занимает никогда, а локальные правила потребителя берут префиксы только на занимает никогда, а локальные правила потребителя берут префиксы только на
@@ -140,10 +167,11 @@ origin: time
--- ---
``` ```
Больше в шапке ничего нет. Отпечатка канона и даты синхронизации в ней не В `origin:` стоит имя темы — то же, что в манифесте набора и в шапках
хранится: обновление перезаписывает файл в рабочем дереве, и что именно `topic:` слоёв, из которых файл собран. Больше в шапке ничего нет: отпечатка
изменилось, показывает `git diff` до коммита. Второй механизм сравнения канона и даты синхронизации в ней не хранится, потому что обновление
рядом с git не нужен. перезаписывает файл в рабочем дереве, и что именно изменилось, показывает
`git diff` до коммита. Второй механизм сравнения рядом с git не нужен.
**Маркер локальной части** — единственная машинно значимая разметка внутри **Маркер локальной части** — единственная машинно значимая разметка внутри
файла: файла:
@@ -170,10 +198,18 @@ MIGR-6 не соблюдается в `show_history`, `queue`: составны
репозитория. Файл, оставивший шапку, при следующем обновлении потеряет репозитория. Файл, оставивший шапку, при следующем обновлении потеряет
всё, что выше маркера. всё, что выше маркера.
## Манифест ## Два манифеста
Откуда взяты копии и где брать обновления — `.conventions.toml` в корне Манифестов в модели два, и они отвечают на разные вопросы:
репозитория-потребителя:
| Файл | Где лежит | Что описывает |
|---|---|---|
| `manifest.toml` | в наборе | сам набор: темы и префиксы правил |
| `.conventions.toml` | в проекте | подключение: откуда копии, какие темы, язык, стек |
Манифест набора — единственное место, где перечислены оба идентификатора
канона; правила у них общие, поэтому и файл один. Манифест подключения
отвечает, откуда взяты копии и где брать обновления:
```toml ```toml
source = "ssh://git@git.vakhrushev.me:2222/av/dev-conventions.git" source = "ssh://git@git.vakhrushev.me:2222/av/dev-conventions.git"
@@ -185,8 +221,10 @@ topics = ["time", "config", "db-identifiers"]
``` ```
`lang` и `stack` выбирают строку разреженной матрицы: файл темы собирает `lang` и `stack` выбирают строку разреженной матрицы: файл темы собирает
только те слои, которые репозиторию подходят. `topics` — подписка; списка только те слои, которые репозиторию подходят. `topics` — подписка, именами из
подписчиков у канона по-прежнему нет, список тем есть только у потребителя. манифеста набора; списка подписчиков у канона по-прежнему нет, список подписок
есть
только у потребителя.
Как именно инструмент добирается до канона — путь на диске, git, HTTP — Как именно инструмент добирается до канона — путь на диске, git, HTTP —
дело инструмента, а не модели. Манифест отвечает на два вопроса: откуда это дело инструмента, а не модели. Манифест отвечает на два вопроса: откуда это
+24 -40
View File
@@ -4,36 +4,17 @@
решения. Закрытый вопрос отсюда удаляется — принятое решение живёт в решения. Закрытый вопрос отсюда удаляется — принятое решение живёт в
`README.md`, `GUIDE.md` или `LANGUAGE.md`, а не в этом файле. `README.md`, `GUIDE.md` или `LANGUAGE.md`, а не в этом файле.
Две секции: сначала язык и подход, потом канон с тулингом. Пункты 1–6 Две секции: сначала язык и подход, потом канон с тулингом. Пункты 1–5
пришли из внешнего ревью описания языка и проверены по файлам на месте. пришли из внешнего ревью описания языка и проверены по файлам на месте.
# Язык и подход # Язык и подход
## 1. «Тема» — несущий идентификатор без определения и реестра ## 1. GUIDE выведен из-под проверок ложным основанием
META-21 велит ссылаться на соседнюю конвенцию именем темы, манифест
подписывается `topics = ["time", …]`, сборка собирает файл темы из слоёв —
но нигде не сказано, что такое имя темы (имя файла без расширения?
отдельный атрибут в шапке?) и где список тем существует.
У префиксов есть реестр `prefixes.toml`, запрет переименования и запрет
переиспользования. У тем нет ничего: ссылка `KEYS-5` валидируется, ссылка
«конвенция `logging`» — нет, и в списке проверок её тоже нет. Переименование
файла темы тихо осиротит все текстовые ссылки во всех копиях.
Вопрос уже не гипотетический: пара `arch/db-identifiers.md` против
`lang/go/db-schema.md` (см. вопрос 10) показывает, что имена слоёв одной
темы могут не совпадать. Смежно: `extends: arch/time.md` у SLOG ломает
гарантию META-24 («базовый слой отсутствовать не может») — она верна только
для базы своей темы, а машинной проверке негде узнать тему, кроме имени
файла.
## 2. GUIDE выведен из-под проверок ложным основанием
`LANGUAGE.md` исключает обвязку из проверок формулировкой «она ключевые слова `LANGUAGE.md` исключает обвязку из проверок формулировкой «она ключевые слова
цитирует, а не употребляет». Для `GUIDE.md` это неверно: META-правила цитирует, а не употребляет». Для `GUIDE.md` это неверно: META-правила
употребляют ДОЛЖЕН нормативно, а префикс META зарегистрирован в `[live]`, где употребляют ДОЛЖЕН нормативно, а префикс META стоит в `[prefixes.live]`
прямо сказано, что правила записаны тем же языком. манифеста набора, где прямо сказано, что правила записаны тем же языком.
Три следствия. META-правила не попадают ни под одну проверку формы. В Три следствия. META-правила не попадают ни под одну проверку формы. В
`GUIDE.md` нет строки о версии языка, то есть у META-правил формально нет `GUIDE.md` нет строки о версии языка, то есть у META-правил формально нет
@@ -44,7 +25,7 @@ META-21 велит ссылаться на соседнюю конвенцию
Честнее развести: `GUIDE.md` язык **употребляет** и проверяется как Честнее развести: `GUIDE.md` язык **употребляет** и проверяется как
конвенция, `LANGUAGE.md` и `README.md` — цитируют. конвенция, `LANGUAGE.md` и `README.md` — цитируют.
## 3. МЕХАНИЗИРОВАНО не переживает нового подписчика ## 2. МЕХАНИЗИРОВАНО не переживает нового подписчика
META-8 запрещает удалять норму, пока механизирована не у всех, и защищает META-8 запрещает удалять норму, пока механизирована не у всех, и защищает
тем самым потребителей, существующих **на момент удаления**. Будущих не тем самым потребителей, существующих **на момент удаления**. Будущих не
@@ -62,7 +43,7 @@ META-8 запрещает удалять норму, пока механизир
в тексте канона, то есть ровно то, что запрещает META-4. Либо это законное в тексте канона, то есть ровно то, что запрещает META-4. Либо это законное
исключение, и тогда его надо назвать, либо конфликт. исключение, и тогда его надо назвать, либо конфликт.
## 4. Семантика ключевых слов в копию не едет ## 3. Семантика ключевых слов в копию не едет
Строка о версии языка перечисляет слова, но не их значения, а всё Строка о версии языка перечисляет слова, но не их значения, а всё
нетривиальное в шкале живёт только в `LANGUAGE.md`, который в репозиторий не нетривиальное в шкале живёт только в `LANGUAGE.md`, который в репозиторий не
@@ -78,7 +59,7 @@ META-8 запрещает удалять норму, пока механизир
копиями короткую выжимку семантики; расширить строку о версии до копиями короткую выжимку семантики; расширить строку о версии до
двух-трёх предложений; или признать ограничение и записать его явно. двух-трёх предложений; или признать ограничение и записать его явно.
## 5. Две «механические» проверки без источника данных ## 4. Две «механические» проверки без источника данных
В списке «разбором текста» стоят два пункта, которые без дополнительного В списке «разбором текста» стоят два пункта, которые без дополнительного
реестра нерешаемы: реестра нерешаемы:
@@ -90,11 +71,12 @@ META-8 запрещает удалять норму, пока механизир
снятого номера в прозе выглядит как висячая ссылка. снятого номера в прозе выглядит как висячая ссылка.
`GUIDE.md` завёл для себя раздел «Освободившиеся номера», но язык не требует `GUIDE.md` завёл для себя раздел «Освободившиеся номера», но язык не требует
такой таблицы от конвенций, а `prefixes.toml` хранит только префиксы. Пока такой таблицы от конвенций, а манифест набора хранит только темы и префиксы.
Пока
реестр снятых номеров не объявлен частью языка, оба пункта принадлежат реестр снятых номеров не объявлен частью языка, оба пункта принадлежат
списку «чтением». списку «чтением».
## 6. Натяжки в опоре на стандарты ## 5. Натяжки в опоре на стандарты
Три места, где источнику приписано чуть больше, чем в нём есть: Три места, где источнику приписано чуть больше, чем в нём есть:
@@ -113,7 +95,7 @@ META-8 запрещает удалять норму, пока механизир
Остальное в таблице проверку выдержало, включая вторую половину `MAY` из Остальное в таблице проверку выдержало, включая вторую половину `MAY` из
BCP 14 и списки эквивалентных словесных форм ISO Directives. BCP 14 и списки эквивалентных словесных форм ISO Directives.
## 7. Одиннадцать таблиц не прочитаны на взаимоисключительность ## 6. Одиннадцать таблиц не прочитаны на взаимоисключительность
`LANGUAGE.md` объявил, что строки таблицы решений взаимоисключающи по `LANGUAGE.md` объявил, что строки таблицы решений взаимоисключающи по
умолчанию, а иной порядок объявляется явно. Объявление не делает таблицы умолчанию, а иной порядок объявляется явно. Объявление не делает таблицы
@@ -128,7 +110,7 @@ BCP 14 и списки эквивалентных словесных форм IS
Работа читательская, машине не даётся; в список проверок она уже записана в Работа читательская, машине не даётся; в список проверок она уже записана в
разделе «Чтением, потому что машине не даётся». разделе «Чтением, потому что машине не даётся».
## 8. Описание языка отдельно от набора конвенций ## 7. Описание языка отдельно от набора конвенций
`LANGUAGE.md` и `GUIDE.md` описывают, **как** пишутся конвенции; `LANGUAGE.md` и `GUIDE.md` описывают, **как** пишутся конвенции;
`conventions/`**один конкретный** набор. Сейчас они склеены в одном `conventions/`**один конкретный** набор. Сейчас они склеены в одном
@@ -153,14 +135,14 @@ BCP 14 и списки эквивалентных словесных форм IS
# Канон, тулинг, подключение # Канон, тулинг, подключение
## 9. Тулинг: две разные задачи в одном `conv` ## 8. Тулинг: две разные задачи в одном `conv`
Сейчас в `conv` смешаны две категории работы, и они расходятся по всему — Сейчас в `conv` смешаны две категории работы, и они расходятся по всему —
по частоте запуска, по тому, кто запускает, и по тому, что считается по частоте запуска, по тому, кто запускает, и по тому, что считается
провалом. провалом.
**Целостность канона.** Префиксы уникальны и не переиспользованы, шапка **Целостность канона.** Префиксы уникальны и не переиспользованы, шапка
совпадает с реестром, у каждого правила модальность и блок ПОЧЕМУ, ссылки совпадает с манифестом, у каждого правила модальность и блок ПОЧЕМУ, ссылки
разрешаются, префикс чужой темы не лезет в норму (META-20), путей канона в разрешаются, префикс чужой темы не лезет в норму (META-20), путей канона в
тексте нет (META-21), строка о версии языка на месте. Запускается в каноне, тексте нет (META-21), строка о версии языка на месте. Запускается в каноне,
при каждой правке, провал — это ошибка. Логика уже написана и много раз при каждой правке, провал — это ошибка. Логика уже написана и много раз
@@ -184,7 +166,7 @@ BCP 14 и списки эквивалентных словесных форм IS
ссылках: это установка, а не целостность, но список подписок ему нужен из ссылках: это установка, а не целостность, но список подписок ему нужен из
манифеста. манифеста.
Часть проверок из этого списка сейчас нереализуема по причине из вопроса 5, Часть проверок из этого списка сейчас нереализуема по причине из вопроса 4,
так что порядок такой: сначала язык, потом чекер. так что порядок такой: сначала язык, потом чекер.
Перед тем как переписывать, стоит посмотреть на два готовых прототипа: Перед тем как переписывать, стоит посмотреть на два готовых прототипа:
@@ -192,14 +174,16 @@ BCP 14 и списки эквивалентных словесных форм IS
манифеста и `vendir.yml` — как пример того, где проходит граница между «чего манифеста и `vendir.yml` — как пример того, где проходит граница между «чего
хочу» и «что получил». хочу» и «что получил».
## 10. Пары слоёв и темы без базы ## 9. Пары слоёв и темы без базы
Отложено сознательно, но список стоит держать перед глазами: Отложено сознательно, но список стоит держать перед глазами:
- `SLOG` объявляет `extends: arch/time.md` — расширение **чужой** темы. - `SLOG` объявляет `extends: arch/time.md` — расширение **чужой** темы.
Сборщик темы `logging` на это наткнётся: базового слоя с темой `logging` Сборщик темы `logging` на это наткнётся: базового слоя с темой `logging`
нет, а `arch/time.md` он тянуть не должен. Чинится переводом в обычную нет, а `arch/time.md` он тянуть не должен. Чинится переводом в обычную
ссылку «связано». Вдобавок это ломает гарантию META-24 — см. вопрос 1. ссылку «связано». Вдобавок это ломает гарантию META-24: она верна только
для базы своей темы, а `arch/time.md` объявляет тему `time`, не `logging`.
С объявленной темой расхождение стало проверяемым машинно.
- Темы без арх-слоя: `db-schema`, `errors`, `web-ui`. Собираются в файл с - Темы без арх-слоя: `db-schema`, `errors`, `web-ui`. Собираются в файл с
одной секцией — само по себе не ломается, но это и есть тот невыделенный одной секцией — само по себе не ломается, но это и есть тот невыделенный
арх-слой из известного долга. арх-слой из известного долга.
@@ -211,7 +195,7 @@ BCP 14 и списки эквивалентных словесных форм IS
- Вынос арх-ядра из `errors` и `logging` закроет две хрупкие ссылки из - Вынос арх-ядра из `errors` и `logging` закроет две хрупкие ссылки из
`web-ui` (стек) в go-слой — единственные ссылки стек → язык в каноне. `web-ui` (стек) в go-слой — единственные ссылки стек → язык в каноне.
## 11. Подключение к репозиториям ## 10. Подключение к репозиториям
Ничего ещё не подключено. Кандидаты — jellybit и pet-project-server. Ничего ещё не подключено. Кандидаты — jellybit и pet-project-server.
Понадобится: заполнить локальную часть копий тем, что сейчас в этих Понадобится: заполнить локальную часть копий тем, что сейчас в этих
@@ -220,7 +204,7 @@ BCP 14 и списки эквивалентных словесных форм IS
строка в `AGENTS.md` каждого потребителя про то, что файлы в строка в `AGENTS.md` каждого потребителя про то, что файлы в
`docs/conventions/` — копии. `docs/conventions/` — копии.
## 12. Тулинг на Go, живущий независимо ## 11. Тулинг на Go, живущий независимо
Сейчас `conv` — питоновский скрипт внутри канона, то есть тулинг и данные в Сейчас `conv` — питоновский скрипт внутри канона, то есть тулинг и данные в
одном репозитории и правятся одним движением. Мысль: вынести в отдельный одном репозитории и правятся одним движением. Мысль: вынести в отдельный
@@ -229,10 +213,10 @@ Go-бинарь со своим релизным циклом, ставить ч
Что за этим стоит помимо вкуса: независимый бинарь физически не даёт править Что за этим стоит помимо вкуса: независимый бинарь физически не даёт править
инструмент «заодно» с правкой конвенции, работает против **любого** канона и инструмент «заодно» с правкой конвенции, работает против **любого** канона и
любого потребителя — что прямо требуется вопросом 8, — и снимает питон из любого потребителя — что прямо требуется вопросом 7, — и снимает питон из
зависимостей репозиториев-потребителей. зависимостей репозиториев-потребителей.
Порядок обратный ожидаемому: пока вопрос 8 не сделан, инструмент всё равно Порядок обратный ожидаемому: пока вопрос 7 не сделан, инструмент всё равно
работает против одного конкретного канона, и независимый релизный цикл ему работает против одного конкретного канона, и независимый релизный цикл ему
нечего обслуживать. Сначала 8, потом 12. Разделение из вопроса 9 при этом нечего обслуживать. Сначала 7, потом 11. Разделение из вопроса 8 при этом
дешевле заложить сразу, чем отпиливать потом. дешевле заложить сразу, чем отпиливать потом.
+1
View File
@@ -1,4 +1,5 @@
--- ---
topic: app-directories
prefix: DIRS prefix: DIRS
--- ---
+1
View File
@@ -1,4 +1,5 @@
--- ---
topic: config
prefix: CONF prefix: CONF
--- ---
+1
View File
@@ -1,4 +1,5 @@
--- ---
topic: db-identifiers
prefix: KEYS prefix: KEYS
--- ---
+1
View File
@@ -1,4 +1,5 @@
--- ---
topic: time
prefix: TIME prefix: TIME
--- ---
+1
View File
@@ -1,4 +1,5 @@
--- ---
topic: config
prefix: GCFG prefix: GCFG
extends: arch/config.md extends: arch/config.md
--- ---
+1
View File
@@ -1,4 +1,5 @@
--- ---
topic: db-identifiers
prefix: GKEY prefix: GKEY
extends: arch/db-identifiers.md extends: arch/db-identifiers.md
--- ---
+1
View File
@@ -1,4 +1,5 @@
--- ---
topic: db-schema
prefix: MIGR prefix: MIGR
--- ---
+1
View File
@@ -1,4 +1,5 @@
--- ---
topic: errors
prefix: GERR prefix: GERR
--- ---
+1
View File
@@ -1,4 +1,5 @@
--- ---
topic: logging
prefix: SLOG prefix: SLOG
extends: arch/time.md extends: arch/time.md
--- ---
+1
View File
@@ -1,4 +1,5 @@
--- ---
topic: time
prefix: GTIM prefix: GTIM
extends: arch/time.md extends: arch/time.md
--- ---
@@ -1,4 +1,5 @@
--- ---
topic: app-directories
prefix: ANSD prefix: ANSD
extends: arch/app-directories.md extends: arch/app-directories.md
--- ---
+1
View File
@@ -1,4 +1,5 @@
--- ---
topic: web-ui
prefix: HTMX prefix: HTMX
--- ---
+101
View File
@@ -0,0 +1,101 @@
# Манифест набора конвенций.
#
# Манифестов в модели два, и они отвечают на разные вопросы:
#
# - этот, в наборе, описывает сам набор: какие в нём темы и какие префиксы
# правил заняты;
# - `.conventions.toml` в репозитории-потребителе описывает подключение:
# откуда взяты копии, какие темы выбраны, какие язык и стек.
#
# Оба идентификатора набора — тема и префикс — живут здесь, потому что
# правила у них общие: объявляются в шапке файла, сверяются с манифестом,
# не переиспользуются никогда, а снятые уходят в свой раздел `retired`
# вместе с причиной и датой.
# ─── Темы ───────────────────────────────────────────────────────────────────
#
# Тема — набор правил об одном фокусе разработки: время, конфигурация, схема
# БД. Имя записывается латиницей; рекомендуется нижний kebab-case, но годится
# любой идентификатор, пригодный для имени файла.
#
# Тема — единица подписки и единица сборки: потребитель перечисляет темы в
# своём манифесте, а сборщик складывает в один файл все слои темы в порядке
# arch → язык → стек. Слои узнают друг друга по объявленному имени, а не по
# имени файла: файл конвенции несёт тему в шапке (`topic: time`).
#
# Имя темы не переименовывается и не переиспользуется: на тему ссылаются
# словом — из текста конвенций («конвенция `logging`»), из подписки в
# манифесте потребителя, из шапки `origin:` каждой копии, — и такая ссылка
# обязана продолжать указывать на тот же набор правил. Тема живёт, пока в
# `conventions/` есть хотя бы один её слой.
#
# Описание — одна строка о том, про что тема: из него собирается таблица в
# README директории конвенций у потребителя (META-18).
[topics.live]
app-directories = "категории директорий приложения и что в каждой лежит"
config = "конфигурация: файл, валидация, секреты"
db-identifiers = "идентификаторы сущностей: вид ключа, генерация, границы"
db-schema = "схема БД и миграции: типы колонок, форма изменения"
errors = "ошибки: обёртки, границы трансляции, паники"
logging = "логирование: уровни, структура записи, что не логируем"
time = "время: хранение, зоны, форматы, календарные границы"
web-ui = "веб-UI: партиалы, свопы, поллинг"
[topics.retired]
# Пусто. Сюда попадают имена снятых и переименованных тем вместе с причиной
# и датой, чтобы их нельзя было выдать другой теме.
# ─── Префиксы правил ────────────────────────────────────────────────────────
#
# Префикс — четыре заглавные латинские буквы, уникальные по всему набору. Он
# выбирается под файл, а не выводится по формуле: префикс нужен, чтобы по нему
# искать, а не чтобы его разбирать. Поэтому подходящее слово лучше
# закономерности.
#
# Правила:
#
# - префикс не переименовывается и не переиспользуется никогда — ссылка
# из чужого репозитория обязана продолжать указывать на то же место;
# - при удалении или разделении файла префикс уходит в retired, а не
# освобождается;
# - переезд файла между осями префикс не меняет: идентификатор правила
# не зависит от таксономии;
# - вынос части правил в новый файл — это новый префикс и новая нумерация:
# перенос правила между документами есть смысловое изменение, а не
# переименование;
# - тот же префикс продублирован в шапке файла (`prefix:`), conv сверяет.
#
# Префикс принадлежит файлу, тема — набору файлов: у слоёв одной темы
# префиксы разные, а имя темы одно.
#
# Пути даются от корня репозитория, а не от `conventions/`: манифест покрывает
# и обвязку тоже.
#
# Буква `X` в начале префикса зарезервирована за репозиториями-потребителями:
# набор её не занимает никогда, локальные правила берут префиксы только на
# неё (XTIM, XLOG). Согласовывать их с манифестом не нужно — столкновение
# невозможно по построению.
[prefixes.live]
DIRS = "conventions/arch/app-directories.md"
CONF = "conventions/arch/config.md"
KEYS = "conventions/arch/db-identifiers.md"
TIME = "conventions/arch/time.md"
GCFG = "conventions/lang/go/config.md"
GKEY = "conventions/lang/go/db-identifiers.md"
MIGR = "conventions/lang/go/db-schema.md"
GERR = "conventions/lang/go/errors.md"
SLOG = "conventions/lang/go/logging.md"
GTIM = "conventions/lang/go/time.md"
ANSD = "conventions/stack/ansible/app-directories.md"
HTMX = "conventions/stack/htmx/web-ui.md"
# Обвязка набора: не синхронизируется в репозитории, но правила записаны тем
# же языком и цитируются по номерам, поэтому префикс нужен. Темы у неё нет —
# подписаться на обвязку нельзя, она не едет к потребителю.
META = "GUIDE.md"
[prefixes.retired]
# Пусто. Сюда попадают префиксы удалённых и разделённых файлов вместе с
# причиной и датой, чтобы их нельзя было выдать повторно.
-49
View File
@@ -1,49 +0,0 @@
# Реестр префиксов правил.
#
# Префикс — четыре заглавные латинские буквы, уникальные по всему канону.
# Он выбирается под файл, а не выводится по формуле: префикс нужен, чтобы
# по нему искать, а не чтобы его разбирать. Поэтому подходящее слово лучше
# закономерности.
#
# Правила реестра:
#
# - префикс не переименовывается и не переиспользуется никогда — ссылка
# из чужого репозитория обязана продолжать указывать на то же место;
# - при удалении или разделении файла префикс уходит в [retired], а не
# освобождается;
# - переезд файла между осями префикс не меняет: идентификатор правила
# не зависит от таксономии;
# - вынос части правил в новый файл — это новый префикс и новая
# нумерация: перенос правила между документами есть смысловое
# изменение, а не переименование;
# - тот же префикс продублирован в шапке файла (`prefix:`), conv сверяет.
#
# Пути даются от корня репозитория, а не от `conventions/`: реестр покрывает
# и обвязку тоже.
#
# Буква `X` в начале префикса зарезервирована за репозиториями-потребителями:
# канон её не занимает никогда, локальные правила берут префиксы только на
# неё (XTIM, XLOG). Согласовывать их с этим реестром не нужно — столкновение
# невозможно по построению.
[live]
DIRS = "conventions/arch/app-directories.md"
CONF = "conventions/arch/config.md"
KEYS = "conventions/arch/db-identifiers.md"
TIME = "conventions/arch/time.md"
GCFG = "conventions/lang/go/config.md"
GKEY = "conventions/lang/go/db-identifiers.md"
MIGR = "conventions/lang/go/db-schema.md"
GERR = "conventions/lang/go/errors.md"
SLOG = "conventions/lang/go/logging.md"
GTIM = "conventions/lang/go/time.md"
ANSD = "conventions/stack/ansible/app-directories.md"
HTMX = "conventions/stack/htmx/web-ui.md"
# Обвязка канона: не синхронизируется в репозитории, но правила
# записаны тем же языком и цитируются по номерам, поэтому префикс нужен.
META = "GUIDE.md"
[retired]
# Пусто. Сюда попадают префиксы удалённых и разделённых файлов вместе с
# причиной и датой, чтобы их нельзя было выдать повторно.