From c1cb240540e1b1e5bfd87a1ba0f893e0dc24d2c5 Mon Sep 17 00:00:00 2001 From: Anton Vakhrushev Date: Sun, 26 Jul 2026 15:27:55 +0300 Subject: [PATCH] =?UTF-8?q?=D1=82=D0=B5=D0=BC=D1=8B:=20=D0=BE=D0=BF=D1=80?= =?UTF-8?q?=D0=B5=D0=B4=D0=B5=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5,=20=D0=BE?= =?UTF-8?q?=D0=B1=D1=8A=D1=8F=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=B2?= =?UTF-8?q?=20=D1=88=D0=B0=D0=BF=D0=BA=D0=B5=20=D0=B8=20=D0=BC=D0=B0=D0=BD?= =?UTF-8?q?=D0=B8=D1=84=D0=B5=D1=81=D1=82=20=D0=BD=D0=B0=D0=B1=D0=BE=D1=80?= =?UTF-8?q?=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - тема — набор правил об одном фокусе разработки, имя латиницей (нижний 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 --- CLAUDE.md | 34 ++++--- GUIDE.md | 32 +++++- LANGUAGE.md | 38 ++++++- README.md | 70 ++++++++++--- TODO.md | 64 +++++------- conventions/arch/app-directories.md | 1 + conventions/arch/config.md | 1 + conventions/arch/db-identifiers.md | 1 + conventions/arch/time.md | 1 + conventions/lang/go/config.md | 1 + conventions/lang/go/db-identifiers.md | 1 + conventions/lang/go/db-schema.md | 1 + conventions/lang/go/errors.md | 1 + conventions/lang/go/logging.md | 1 + conventions/lang/go/time.md | 1 + conventions/stack/ansible/app-directories.md | 1 + conventions/stack/htmx/web-ui.md | 1 + manifest.toml | 101 +++++++++++++++++++ prefixes.toml | 49 --------- 19 files changed, 274 insertions(+), 126 deletions(-) create mode 100644 manifest.toml delete mode 100644 prefixes.toml diff --git a/CLAUDE.md b/CLAUDE.md index 3a178d1..a0c6b84 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -9,7 +9,7 @@ code in this repository. Канон конвенций разработки для личных проектов. Сами конвенции лежат в `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:` в шапке отменён. -## Идентификаторы и префиксы +## Идентификаторы: тема и префикс +- Тема — набор правил об одном фокусе разработки и единица подписки. Имя — + латиницей, рекомендуется нижний kebab-case, годится любой идентификатор, + пригодный для имени файла. +- META-28: тема объявлена в шапке (`topic: time`) и стоит в манифесте набора + (`manifest.toml`, секция `[topics.live]`). Слои одной темы несут одно имя — + по нему собираются в один файл, как бы ни назывались их файлы; имя файла + повторяет тему из удобства. +- META-29: имя темы не переиспользуется, снятое уходит в `[topics.retired]` + с причиной и датой. Оно живёт в `origin:` копий и в подписках манифестов. - Формат `<ПРЕФИКС>-<номер>`, нумерация сквозная внутри файла. Порядок правил в файле — по читаемости: номер это идентификатор, а не позиция. - Идентификаторы не переиспользуются. Удалённое правило оставляет дыру, новое берёт следующий свободный номер, а не первый освободившийся. - Новый файл конвенции — новый префикс: четыре заглавные латинские буквы, уникальные по всему канону, выбираются под файл, а не выводятся по формуле. - Объявляется в шапке (`prefix: KEYS`) и регистрируется в `prefixes.toml`, - секция `[live]`, путём от корня репозитория. -- Удаление или разделение файла: префикс уходит в `[retired]` с причиной и - датой, а не освобождается. + Объявляется в шапке (`prefix: KEYS`) и регистрируется в манифесте набора, + секция `[prefixes.live]`, путём от корня репозитория. +- Удаление или разделение файла: префикс уходит в `[prefixes.retired]` с + причиной и датой, а не освобождается. - Префиксы на букву `X` канон не занимает: они зарезервированы за локальными правилами репозиториев-потребителей. - Перенос правила в другой файл — смысловое изменение: новый префикс и новый @@ -121,13 +130,12 @@ code in this repository. ## Оформление файла -Шапка `prefix:` (плюс `extends:`) → `# Тема` → вводная проза → отдельным -абзацем строка о версии языка (её точный текст — в `LANGUAGE.md`, раздел -«Ссылка на язык из конвенции») → `## Область действия` (обязателен для -трудноизменяемых слоёв — META-11) → правила → `## Связано`, если -канонические ссылки есть (META-17; пустого раздела не заводят). Имя файла — -kebab-case по теме. Проза -переносится по ~76 колонок; таблицы и блоки кода не переносятся. +Шапка `topic:` и `prefix:` (плюс `extends:`) → `# Тема` → вводная проза → +отдельным абзацем строка о версии языка (её точный текст — в `LANGUAGE.md`, +раздел «Ссылка на язык из конвенции») → `## Область действия` (обязателен для +трудноизменяемых слоёв — META-11) → правила → `## Связано`, если канонические +ссылки есть (META-17; пустого раздела не заводят). Имя файла повторяет имя +темы. Проза переносится по ~76 колонок; таблицы и блоки кода не переносятся. ## Ревью формы diff --git a/GUIDE.md b/GUIDE.md index 036fd1c..e1374fc 100644 --- a/GUIDE.md +++ b/GUIDE.md @@ -32,11 +32,11 @@ prefix: META ## Оформление -Имя файла — kebab-case по теме: `app-directories.md`. Правилом это не +Имя файла повторяет имя темы: `app-directories.md`. Правилом это не записано, и это случай META-25: регуляркой имя проверяется тривиально, но -обоснование сводится к «чтобы имя файла в реестре префиксов писалось одним -способом» — вреда от нарушения нет, значит и высшей модальности нет, а на -СЛЕДУЕТ такое правило не окупает строчку. +вреда от нарушения нет — тема объявлена в шапке (META-28), и сборка идёт по +объявленному имени, а не по имени файла. Значит, и высшей модальности нет, а +на СЛЕДУЕТ такое правило не окупает строчку. ## Канон и копии @@ -68,6 +68,30 @@ prefix: META дорого: перенос правила в другой файл — это новый префикс и новая нумерация, поэтому после разреза все внешние ссылки обходят руками. +### META-28. Тема объявляется в шапке файла и стоит в манифесте набора + +**ДОЛЖЕН.** Шапка несёт ключ `topic:` с именем темы, и это имя стоит в +манифесте набора. + +**ПОЧЕМУ.** Тема — единица подписки и единица сборки: потребитель перечисляет +темы в своём манифесте, а сборщик складывает в один файл все слои темы. Пока +имя выводится из имени файла, у сборщика нет способа узнать, что два слоя, +названные по-разному, — один документ; переименование файла при этом молча +заводит новую тему, подписка перестаёт находить прежнюю, а ссылки «конвенция +`logging`» в копиях остаются висеть. Объявленное имя вдобавок сверяется с +манифестом — выведенное сверять не с чем. + +### META-29. Имя темы не переиспользуется + +**НЕ ДОЛЖЕН.** Снятое или переименованное имя темы другой теме не выдаётся: +оно уходит в раздел выбывших манифеста с причиной и датой. + +**ПОЧЕМУ.** Имя темы живёт в чужих репозиториях — в шапке `origin:` каждой +копии, в подписке потребителя, в тексте ссылок. Выданное второй теме, оно +начинает указывать на другой набор правил, и обнаруживается это не на сборке, +а по содержанию: файл обновится штатно, изменится текст. Та же дисциплина и по +той же причине действует для префиксов правил. + ### META-2. Конвенция заводится, когда решение принимается третий раз **СЛЕДУЕТ.** Поводом служит одно и то же решение, принятое третий раз и diff --git a/LANGUAGE.md b/LANGUAGE.md index 1a74dcb..cf87a60 100644 --- a/LANGUAGE.md +++ b/LANGUAGE.md @@ -14,7 +14,7 @@ version: 1 Описание языка ни на один набор конвенций не опирается, поэтому все примеры здесь — вымышленные правила с префиксами на `X` (`XKEY`, `XMIG`, `XLOG`). -Такие префиксы канон не занимает никогда, реестру они не принадлежат — значит +Такие префиксы канон не занимает никогда, в манифесте набора их нет — значит пример не спутать с настоящим правилом, а перенумерация конвенций описание языка не задевает. @@ -219,7 +219,7 @@ Directives, Part 2, по одной форме записи на ступень, Модальность живёт на **правиле**, а не на файле. Файловый статус (`status: рекомендуемая` / `обязательная` в шапке) не используется: он неизбежно врёт, потому что один файл смешивает жёсткие требования с -советами. В шапке остаются только `prefix` и `extends`. +советами. В шапке остаются только `topic`, `prefix` и `extends`. ## Словарь другого языка @@ -385,6 +385,12 @@ Directives, Part 2, по одной форме записи на ступень, ## Идентификаторы +Идентификаторов в языке два: **правило** адресуется префиксом с номером, +**конвенция целиком** — именем темы. Ссылаться путём к файлу нельзя ни на то, +ни на другое. + +**Правило.** + - Формат — `<ПРЕФИКС>-<номер>`: `XKEY-5`, `XLOG-27`. Префикс принадлежит файлу, нумерация внутри файла сквозная и начинается с единицы. - Строка таблицы, если на неё нужно ссылаться отдельно, — `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` и не значится в списке выбывших; +- шапка файла несёт имя темы, и это имя стоит в манифесте набора — среди + живых, а не среди выбывших; +- имя темы, названное в ссылке или в подписке потребителя, тоже разрешается по + манифесту: ссылка на снятую тему не проходит молча; - заголовки правил файла используют только его собственный префикс; - номера уникальны внутри файла и не имеют пропусков вниз (новое правило берёт следующий свободный, а не первый освободившийся); diff --git a/README.md b/README.md index b7e8ab0..6f347d2 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ | `README.md` | устройство канона, оси, сборка копий, жизненный цикл | | [LANGUAGE.md](LANGUAGE.md) | язык записи правил: идентификаторы, модальность, обоснование | | [GUIDE.md](GUIDE.md) | как ведут конвенции: когда заводить, механизация, отступления | -| `prefixes.toml` | реестр префиксов правил | +| [manifest.toml](manifest.toml) | манифест набора: темы и префиксы правил | | `conv` | сборка копий | Обвязка живёт только в каноне и в репозитории не оказывается — в копию едет @@ -55,8 +55,9 @@ conventions/ тему. Пути файлов даются относительно `conventions/` (`arch/db-identifiers.md`) и адресуют исходник канона, а не место в копии. На **правила** ссылаются идентификатором без пути: `KEYS-5`. Префикс -уникален по всему канону (реестр — `prefixes.toml`), поэтому идентификатор -не зависит ни от оси, ни от того, как собран файл у потребителя. +уникален по всему канону (он перечислен в манифесте набора), поэтому +идентификатор не зависит ни от оси, ни от того, как собран файл у +потребителя. Тест — по тому, замена чего убивает правило: @@ -81,6 +82,31 @@ conventions/ пласт `stack/sqlite/` (типы колонок). Это не принцип, а незавершённая работа. +## Темы + +**Тема — набор правил об одном фокусе разработки:** время, конфигурация, +схема БД. Она же единица подписки и единица сборки: потребитель берёт тему +целиком, а сборщик складывает в один файл все её слои. + +Имя темы записывается латиницей; рекомендуется нижний kebab-case, но годится +любой идентификатор, пригодный для имени файла — имя попадает и в файловую +систему потребителя, и в его манифест. Файл конвенции объявляет тему в шапке: + +```yaml +topic: db-identifiers +prefix: KEYS +``` + +Слои одной темы несут одно и то же имя — по нему они и собираются в один +документ, как бы ни назывались их файлы. Имя файла повторяет тему из +удобства, но истина — в шапке. + +Темы перечислены в манифесте набора — [`manifest.toml`](manifest.toml), +секция `[topics.live]`: имя и однострочное описание. Имя темы не +переиспользуется по той же причине, что и префикс: оно живёт в чужих +репозиториях — в шапке `origin:` каждой копии, в подписке манифеста, в тексте +ссылок, — и выданное второй теме начинает указывать на другой набор правил. + ## Префиксы Каждый файл канона объявляет в шапке свой префикс правил: @@ -89,10 +115,11 @@ conventions/ prefix: KEYS ``` -Четыре заглавные латинские буквы, уникальные по всему канону; реестр — -[`prefixes.toml`](prefixes.toml). Префикс выбирается под файл, а не выводится -по формуле, и не переиспользуется никогда. Правила адресуются идентификатором -`KEYS-5` — без пути к файлу. Подробности формы — `LANGUAGE.md`. +Четыре заглавные латинские буквы, уникальные по всему канону; перечислены в +манифесте набора, секция `[prefixes.live]`. Префикс выбирается под файл, а не +выводится по формуле, и не переиспользуется никогда. Правила адресуются +идентификатором `KEYS-5` — без пути к файлу. Подробности формы — +`LANGUAGE.md`. Буква `X` в начале префикса зарезервирована за репозиториями: канон её не занимает никогда, а локальные правила потребителя берут префиксы только на @@ -140,10 +167,11 @@ origin: time --- ``` -Больше в шапке ничего нет. Отпечатка канона и даты синхронизации в ней не -хранится: обновление перезаписывает файл в рабочем дереве, и что именно -изменилось, показывает `git diff` до коммита. Второй механизм сравнения -рядом с git не нужен. +В `origin:` стоит имя темы — то же, что в манифесте набора и в шапках +`topic:` слоёв, из которых файл собран. Больше в шапке ничего нет: отпечатка +канона и даты синхронизации в ней не хранится, потому что обновление +перезаписывает файл в рабочем дереве, и что именно изменилось, показывает +`git diff` до коммита. Второй механизм сравнения рядом с git не нужен. **Маркер локальной части** — единственная машинно значимая разметка внутри файла: @@ -170,10 +198,18 @@ MIGR-6 не соблюдается в `show_history`, `queue`: составны репозитория. Файл, оставивший шапку, при следующем обновлении потеряет всё, что выше маркера. -## Манифест +## Два манифеста -Откуда взяты копии и где брать обновления — `.conventions.toml` в корне -репозитория-потребителя: +Манифестов в модели два, и они отвечают на разные вопросы: + +| Файл | Где лежит | Что описывает | +|---|---|---| +| `manifest.toml` | в наборе | сам набор: темы и префиксы правил | +| `.conventions.toml` | в проекте | подключение: откуда копии, какие темы, язык, стек | + +Манифест набора — единственное место, где перечислены оба идентификатора +канона; правила у них общие, поэтому и файл один. Манифест подключения +отвечает, откуда взяты копии и где брать обновления: ```toml source = "ssh://git@git.vakhrushev.me:2222/av/dev-conventions.git" @@ -185,8 +221,10 @@ topics = ["time", "config", "db-identifiers"] ``` `lang` и `stack` выбирают строку разреженной матрицы: файл темы собирает -только те слои, которые репозиторию подходят. `topics` — подписка; списка -подписчиков у канона по-прежнему нет, список тем есть только у потребителя. +только те слои, которые репозиторию подходят. `topics` — подписка, именами из +манифеста набора; списка подписчиков у канона по-прежнему нет, список подписок +есть +только у потребителя. Как именно инструмент добирается до канона — путь на диске, git, HTTP — дело инструмента, а не модели. Манифест отвечает на два вопроса: откуда это diff --git a/TODO.md b/TODO.md index a390ed9..412a005 100644 --- a/TODO.md +++ b/TODO.md @@ -4,36 +4,17 @@ решения. Закрытый вопрос отсюда удаляется — принятое решение живёт в `README.md`, `GUIDE.md` или `LANGUAGE.md`, а не в этом файле. -Две секции: сначала язык и подход, потом канон с тулингом. Пункты 1–6 +Две секции: сначала язык и подход, потом канон с тулингом. Пункты 1–5 пришли из внешнего ревью описания языка и проверены по файлам на месте. # Язык и подход -## 1. «Тема» — несущий идентификатор без определения и реестра - -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 выведен из-под проверок ложным основанием +## 1. GUIDE выведен из-под проверок ложным основанием `LANGUAGE.md` исключает обвязку из проверок формулировкой «она ключевые слова цитирует, а не употребляет». Для `GUIDE.md` это неверно: META-правила -употребляют ДОЛЖЕН нормативно, а префикс META зарегистрирован в `[live]`, где -прямо сказано, что правила записаны тем же языком. +употребляют ДОЛЖЕН нормативно, а префикс META стоит в `[prefixes.live]` +манифеста набора, где прямо сказано, что правила записаны тем же языком. Три следствия. META-правила не попадают ни под одну проверку формы. В `GUIDE.md` нет строки о версии языка, то есть у META-правил формально нет @@ -44,7 +25,7 @@ META-21 велит ссылаться на соседнюю конвенцию Честнее развести: `GUIDE.md` язык **употребляет** и проверяется как конвенция, `LANGUAGE.md` и `README.md` — цитируют. -## 3. МЕХАНИЗИРОВАНО не переживает нового подписчика +## 2. МЕХАНИЗИРОВАНО не переживает нового подписчика META-8 запрещает удалять норму, пока механизирована не у всех, и защищает тем самым потребителей, существующих **на момент удаления**. Будущих не @@ -62,7 +43,7 @@ META-8 запрещает удалять норму, пока механизир в тексте канона, то есть ровно то, что запрещает META-4. Либо это законное исключение, и тогда его надо назвать, либо конфликт. -## 4. Семантика ключевых слов в копию не едет +## 3. Семантика ключевых слов в копию не едет Строка о версии языка перечисляет слова, но не их значения, а всё нетривиальное в шкале живёт только в `LANGUAGE.md`, который в репозиторий не @@ -78,7 +59,7 @@ META-8 запрещает удалять норму, пока механизир копиями короткую выжимку семантики; расширить строку о версии до двух-трёх предложений; или признать ограничение и записать его явно. -## 5. Две «механические» проверки без источника данных +## 4. Две «механические» проверки без источника данных В списке «разбором текста» стоят два пункта, которые без дополнительного реестра нерешаемы: @@ -90,11 +71,12 @@ META-8 запрещает удалять норму, пока механизир снятого номера в прозе выглядит как висячая ссылка. `GUIDE.md` завёл для себя раздел «Освободившиеся номера», но язык не требует -такой таблицы от конвенций, а `prefixes.toml` хранит только префиксы. Пока +такой таблицы от конвенций, а манифест набора хранит только темы и префиксы. +Пока реестр снятых номеров не объявлен частью языка, оба пункта принадлежат списку «чтением». -## 6. Натяжки в опоре на стандарты +## 5. Натяжки в опоре на стандарты Три места, где источнику приписано чуть больше, чем в нём есть: @@ -113,7 +95,7 @@ META-8 запрещает удалять норму, пока механизир Остальное в таблице проверку выдержало, включая вторую половину `MAY` из BCP 14 и списки эквивалентных словесных форм ISO Directives. -## 7. Одиннадцать таблиц не прочитаны на взаимоисключительность +## 6. Одиннадцать таблиц не прочитаны на взаимоисключительность `LANGUAGE.md` объявил, что строки таблицы решений взаимоисключающи по умолчанию, а иной порядок объявляется явно. Объявление не делает таблицы @@ -128,7 +110,7 @@ BCP 14 и списки эквивалентных словесных форм IS Работа читательская, машине не даётся; в список проверок она уже записана в разделе «Чтением, потому что машине не даётся». -## 8. Описание языка отдельно от набора конвенций +## 7. Описание языка отдельно от набора конвенций `LANGUAGE.md` и `GUIDE.md` описывают, **как** пишутся конвенции; `conventions/` — **один конкретный** набор. Сейчас они склеены в одном @@ -153,14 +135,14 @@ BCP 14 и списки эквивалентных словесных форм IS # Канон, тулинг, подключение -## 9. Тулинг: две разные задачи в одном `conv` +## 8. Тулинг: две разные задачи в одном `conv` Сейчас в `conv` смешаны две категории работы, и они расходятся по всему — по частоте запуска, по тому, кто запускает, и по тому, что считается провалом. **Целостность канона.** Префиксы уникальны и не переиспользованы, шапка -совпадает с реестром, у каждого правила модальность и блок ПОЧЕМУ, ссылки +совпадает с манифестом, у каждого правила модальность и блок ПОЧЕМУ, ссылки разрешаются, префикс чужой темы не лезет в норму (META-20), путей канона в тексте нет (META-21), строка о версии языка на месте. Запускается в каноне, при каждой правке, провал — это ошибка. Логика уже написана и много раз @@ -184,7 +166,7 @@ BCP 14 и списки эквивалентных словесных форм IS ссылках: это установка, а не целостность, но список подписок ему нужен из манифеста. -Часть проверок из этого списка сейчас нереализуема по причине из вопроса 5, +Часть проверок из этого списка сейчас нереализуема по причине из вопроса 4, так что порядок такой: сначала язык, потом чекер. Перед тем как переписывать, стоит посмотреть на два готовых прототипа: @@ -192,14 +174,16 @@ BCP 14 и списки эквивалентных словесных форм IS манифеста и `vendir.yml` — как пример того, где проходит граница между «чего хочу» и «что получил». -## 10. Пары слоёв и темы без базы +## 9. Пары слоёв и темы без базы Отложено сознательно, но список стоит держать перед глазами: - `SLOG` объявляет `extends: arch/time.md` — расширение **чужой** темы. Сборщик темы `logging` на это наткнётся: базового слоя с темой `logging` нет, а `arch/time.md` он тянуть не должен. Чинится переводом в обычную - ссылку «связано». Вдобавок это ломает гарантию META-24 — см. вопрос 1. + ссылку «связано». Вдобавок это ломает гарантию META-24: она верна только + для базы своей темы, а `arch/time.md` объявляет тему `time`, не `logging`. + С объявленной темой расхождение стало проверяемым машинно. - Темы без арх-слоя: `db-schema`, `errors`, `web-ui`. Собираются в файл с одной секцией — само по себе не ломается, но это и есть тот невыделенный арх-слой из известного долга. @@ -211,7 +195,7 @@ BCP 14 и списки эквивалентных словесных форм IS - Вынос арх-ядра из `errors` и `logging` закроет две хрупкие ссылки из `web-ui` (стек) в go-слой — единственные ссылки стек → язык в каноне. -## 11. Подключение к репозиториям +## 10. Подключение к репозиториям Ничего ещё не подключено. Кандидаты — jellybit и pet-project-server. Понадобится: заполнить локальную часть копий тем, что сейчас в этих @@ -220,7 +204,7 @@ BCP 14 и списки эквивалентных словесных форм IS строка в `AGENTS.md` каждого потребителя про то, что файлы в `docs/conventions/` — копии. -## 12. Тулинг на Go, живущий независимо +## 11. Тулинг на Go, живущий независимо Сейчас `conv` — питоновский скрипт внутри канона, то есть тулинг и данные в одном репозитории и правятся одним движением. Мысль: вынести в отдельный @@ -229,10 +213,10 @@ Go-бинарь со своим релизным циклом, ставить ч Что за этим стоит помимо вкуса: независимый бинарь физически не даёт править инструмент «заодно» с правкой конвенции, работает против **любого** канона и -любого потребителя — что прямо требуется вопросом 8, — и снимает питон из +любого потребителя — что прямо требуется вопросом 7, — и снимает питон из зависимостей репозиториев-потребителей. -Порядок обратный ожидаемому: пока вопрос 8 не сделан, инструмент всё равно +Порядок обратный ожидаемому: пока вопрос 7 не сделан, инструмент всё равно работает против одного конкретного канона, и независимый релизный цикл ему -нечего обслуживать. Сначала 8, потом 12. Разделение из вопроса 9 при этом +нечего обслуживать. Сначала 7, потом 11. Разделение из вопроса 8 при этом дешевле заложить сразу, чем отпиливать потом. diff --git a/conventions/arch/app-directories.md b/conventions/arch/app-directories.md index 331ff74..e0d71dc 100644 --- a/conventions/arch/app-directories.md +++ b/conventions/arch/app-directories.md @@ -1,4 +1,5 @@ --- +topic: app-directories prefix: DIRS --- diff --git a/conventions/arch/config.md b/conventions/arch/config.md index 2b7181d..edbcf04 100644 --- a/conventions/arch/config.md +++ b/conventions/arch/config.md @@ -1,4 +1,5 @@ --- +topic: config prefix: CONF --- diff --git a/conventions/arch/db-identifiers.md b/conventions/arch/db-identifiers.md index 916a4dc..4b335a2 100644 --- a/conventions/arch/db-identifiers.md +++ b/conventions/arch/db-identifiers.md @@ -1,4 +1,5 @@ --- +topic: db-identifiers prefix: KEYS --- diff --git a/conventions/arch/time.md b/conventions/arch/time.md index aff9c11..ee3fc4a 100644 --- a/conventions/arch/time.md +++ b/conventions/arch/time.md @@ -1,4 +1,5 @@ --- +topic: time prefix: TIME --- diff --git a/conventions/lang/go/config.md b/conventions/lang/go/config.md index 72be5ca..6c7f325 100644 --- a/conventions/lang/go/config.md +++ b/conventions/lang/go/config.md @@ -1,4 +1,5 @@ --- +topic: config prefix: GCFG extends: arch/config.md --- diff --git a/conventions/lang/go/db-identifiers.md b/conventions/lang/go/db-identifiers.md index 75d3a15..6ecd41e 100644 --- a/conventions/lang/go/db-identifiers.md +++ b/conventions/lang/go/db-identifiers.md @@ -1,4 +1,5 @@ --- +topic: db-identifiers prefix: GKEY extends: arch/db-identifiers.md --- diff --git a/conventions/lang/go/db-schema.md b/conventions/lang/go/db-schema.md index 16ae6d2..ead8029 100644 --- a/conventions/lang/go/db-schema.md +++ b/conventions/lang/go/db-schema.md @@ -1,4 +1,5 @@ --- +topic: db-schema prefix: MIGR --- diff --git a/conventions/lang/go/errors.md b/conventions/lang/go/errors.md index db174d0..53c5a00 100644 --- a/conventions/lang/go/errors.md +++ b/conventions/lang/go/errors.md @@ -1,4 +1,5 @@ --- +topic: errors prefix: GERR --- diff --git a/conventions/lang/go/logging.md b/conventions/lang/go/logging.md index e8d04ba..8fed709 100644 --- a/conventions/lang/go/logging.md +++ b/conventions/lang/go/logging.md @@ -1,4 +1,5 @@ --- +topic: logging prefix: SLOG extends: arch/time.md --- diff --git a/conventions/lang/go/time.md b/conventions/lang/go/time.md index b6597a4..f17cf3d 100644 --- a/conventions/lang/go/time.md +++ b/conventions/lang/go/time.md @@ -1,4 +1,5 @@ --- +topic: time prefix: GTIM extends: arch/time.md --- diff --git a/conventions/stack/ansible/app-directories.md b/conventions/stack/ansible/app-directories.md index 1953c52..24825f2 100644 --- a/conventions/stack/ansible/app-directories.md +++ b/conventions/stack/ansible/app-directories.md @@ -1,4 +1,5 @@ --- +topic: app-directories prefix: ANSD extends: arch/app-directories.md --- diff --git a/conventions/stack/htmx/web-ui.md b/conventions/stack/htmx/web-ui.md index ca974f9..a31214a 100644 --- a/conventions/stack/htmx/web-ui.md +++ b/conventions/stack/htmx/web-ui.md @@ -1,4 +1,5 @@ --- +topic: web-ui prefix: HTMX --- diff --git a/manifest.toml b/manifest.toml new file mode 100644 index 0000000..ba18f59 --- /dev/null +++ b/manifest.toml @@ -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] +# Пусто. Сюда попадают префиксы удалённых и разделённых файлов вместе с +# причиной и датой, чтобы их нельзя было выдать повторно. diff --git a/prefixes.toml b/prefixes.toml deleted file mode 100644 index 5d7b10a..0000000 --- a/prefixes.toml +++ /dev/null @@ -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] -# Пусто. Сюда попадают префиксы удалённых и разделённых файлов вместе с -# причиной и датой, чтобы их нельзя было выдать повторно.