Files
dev-conventions/TODO.md
T
av 9318087248 язык записи опёрт на стандарты, словарь стал параметром
- шкала обязательности объявлена инвариантом, а набор ключевых слов —
  параметром естественного языка набора: для английского готовый словарь
  даёт BCP 14, для прочих берут перевод стандарта или делают свой; отклонены
  синонимы ступеней и `SHALL`, занятый OpenSpec
- применены шесть дельт: нормативно только заглавное написание (RFC 8174),
  ДОЛЖЕН требует названного вреда и машинной проверки сразу, ДОПУСКАЕТСЯ
  адресовано рецензенту, МЕХАНИЗИРОВАНО выведено из шкалы в отметку рядом с
  модальностью (ISO/IEC/IEEE 29148), у таблиц объявлены политика совпадения
  и полнота (DMN)
- «Форма записи — LANGUAGE.md» в двенадцати конвенциях заменена строкой о
  версии языка по образцу boilerplate BCP 14: пути канона в копии не
  существует, а словарь и правило заглавных строка несёт сама
2026-07-26 13:42:10 +03:00

250 lines
20 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# К обсуждению
Черновик для следующего разговора: вопросы и варианты, а не принятые
решения.
## 1. Ссылка на язык — закрыто
Заменено boilerplate-строкой по образцу BCP 14: каждая конвенция называет
ключевые слова, версию языка и правило заглавных, но не путь. Строка стоит
отдельным абзацем после вводной прозы во всех двенадцати файлах, «Форма
записи — `LANGUAGE.md`» удалена. Точный текст — в `LANGUAGE.md`, раздел
«Ссылка на язык из конвенции».
Побочно: строка перечисляет модальные слова заглавными, то есть сама
нарушает проверку «заглавные модальные слова не встречаются вне правил».
Исключение записано в список проверок — так же, как оно устроено в BCP 14,
где boilerplate тоже содержит ключевые слова.
## 2. Тулинг: две разные задачи в одном `conv`
Сейчас в `conv` смешаны две категории работы, и они расходятся по всему —
по частоте запуска, по тому, кто запускает, и по тому, что считается
провалом.
**Целостность канона.** Префиксы уникальны и не переиспользованы, шапка
совпадает с реестром, номера без дыр вниз, у каждого правила модальность и
«Почему», ссылки разрешаются, чужой префикс не лезет в норму (META-20),
путей канона в тексте нет (META-21). Запускается в каноне, при каждой
правке, провал — это ошибка. Логика уже написана и много раз прогнана
руками, но живёт в скретчпаде, а не в репозитории.
**Установка в проект.** Манифест `.conventions.toml`, сборка файла темы из
секций (arch → языки → стеки → local), сохранение локальной секции при
пересборке, отчёт «канон ушёл вперёд», предупреждение о висячих ссылках на
неподписанные темы. Запускается в репозитории-потребителе, изредка, провал —
это чаще «посмотри глазами», чем «ошибка».
Что обсудить:
- Разделять ли на два исполняемых файла, или хватит подкоманд с честной
границей внутри.
- Валидацию канона стоит ли отдать агенту скиллом вместо (или вдобавок к)
скрипту: часть проверок формулируется как «прочитай и скажи, самодостаточна
ли норма» — механически это не берётся, а агентом берётся.
- Куда в этой раскладке ложится запаркованное предупреждение о висячих
ссылках: это установка, а не целостность, но список подписок ему нужен из
манифеста.
## 3. Модель сборки — записана, закрыто
Записана в `README.md` (разделы «Копия в репозитории» и «Манифест») и в
`GUIDE.md` (META-22, META-23). Плоская раскладка, файл на тему, один маркер
`<!-- conv:local -->`, манифест из источника и списка тем, направление
строго одностороннее.
Против прежних заготовок разошлось в трёх местах:
- **лока нет** — «что было в прошлый раз» знает git, копии закоммичены, и
автоматического обновления не существует; заодно из шапки копии ушли
`origin_hash` и `synced`, осталось одно `origin:`;
- **маркеров секций нет** — раз обновление перезаписывает всё выше
локального маркера, разметка слоёв тулингу не нужна; слои идут обычными
заголовками;
- **локальные префиксы не объявляются в манифесте** — за репозиториями
зарезервирована буква `X`, столкновение невозможно по построению.
Остаётся переписать `conv`: сейчас в нём зеркальное дерево, именованные
регионы, `origin_hash` и команды `status`/`diff`/`push`. Это вопрос 2.
## 4. Именованные регионы — удалить из канона
Решение принято и записано: регионов нет, есть один маркер
`<!-- conv:local -->`, который ставит сборщик в копии. Значит регионы не
переносятся в единую секцию, а **удаляются**: в каноне их нечем наполнять,
локальное принадлежит копии.
Остаётся механическая работа — **31 регион в 12 файлах**:
```
7 связано 7 отступления 7 механизировано
1 эталон / эталоны / словарь / секреты / секретные-поля
1 проверки / поля / модель-владельца / маппинг / границы
```
Вопрос про `связано` снят: META-17 переписан, канонический раздел «Связано»
остаётся в тексте и содержит только ссылки, верные у всех, а репо-специфичные
уходят под маркер.
## 5. Пары слоёв и темы без базы
Отложено сознательно, но список стоит держать перед глазами:
- `SLOG` объявляет `extends: arch/time.md` — расширение **чужой** темы.
Сборщик темы `logging` на это наткнётся: базового слоя с темой `logging`
нет, а `arch/time.md` он тянуть не должен. Чинится переводом в обычную
ссылку «связано».
- Темы без арх-слоя: `db-schema`, `errors`, `web-ui`. Собираются в файл с
одной секцией — само по себе не ломается, но это и есть тот невыделенный
арх-слой из известного долга.
- Имена тем в паре не совпадают: `arch/db-identifiers.md` против
`lang/go/db-schema.md`. При сборке по имени темы это две разные темы —
проверить, что так и задумано.
- В `lang/go/db-schema.md` сидит целый пласт `stack/sqlite/` (типы колонок),
тоже из известного долга README.
## 6. Подключение к репозиториям
Ничего ещё не подключено. Кандидаты — jellybit и pet-project-server.
Понадобится: заполнить локальные секции тем, что сейчас в этих репозиториях
записано по факту; обёртка в раннере (`inv conventions` / `task conventions`,
единый интерфейс команд у трёх ansible-репозиториев); строка в `AGENTS.md`
каждого потребителя про то, что файлы в `docs/conventions/` — копии.
Открытый кусок с прошлого раза: **как копия ссылается на канон, не ломая
самодостаточность**. Абсолютный путь `~/projects/private/dev-conventions`
в закоммиченном файле не годится — репозиторий перестаёт быть
самодостаточным и получает хардкод путей. Пересекается с вопросом 1.
## 7. Не переизобретено ли это — разобрано
Проверка перед вложением в тулинг сделана. По слоям:
- **Язык записи** — совпал со стандартами почти во всём: шкала и правило
«нормативно только заглавное» — BCP 14, обязательное обоснование и
единичность нормы — ISO/IEC/IEEE 29148, категории — ISO/IEC Directives
Part 2, таблицы решений — DMN, стабильные идентификаторы — semgrep/ESLint.
Шесть точечных дельт применены, опора на источники записана в `LANGUAGE.md`
разделом «Опора на стандарты».
- **Оси и сборка** — аналога не нашлось. Ближайшие соседи (каскад `extends`
в ESLint, слои стилей Vale) дают праву слоя **отменять** базу; наш запрет
строже, и это содержательная часть. Вкладываться сюда.
- **Транспорт** — переизобретался, но задача у нас другая, чем у copier и
cruft. У них трёхсторонний merge потому, что шаблон порождает код, который
правят везде: расхождение неограниченно. У нас расхождение ограничено и
живёт под маркером, поэтому исключение из перезаписи лучше merge —
детерминированно и без конфликтных маркеров. Из vendir/cruft взят разбор
«манифест против лока», из ansible `blockinfile` — идея размечать
управляемый кусок, а не локальный. Лок при этом не взят: его роль играет
git.
- **Раздача агентам** — не наша задача, остаёмся на `AGENTS.md`/`CLAUDE.md`
плюс скиллы.
**Vale отклонён.** Из восьми проверок в `LANGUAGE.md` он честно закрывает
две-три (модальные слова вне правил, запрещённые формулировки); остальные
пять структурные — «у каждого `### ПРЕФИКС-N` есть модальность и Почему»,
«номера без дыр вниз», «префикс совпадает с реестром». Это разбор документа,
а не проверка токенов в области. Ради двух-трёх проверок тянуть ещё один
бинарь и директорию стилей при одном пользователе не стоит.
**Что стоит посмотреть перед переписыванием `conv`** (вопрос 2): дистрибуцию
пакетов Vale (`.vale.ini``vale sync``styles/`) как готовый прототип
манифеста, и `vendir.yml` — как пример того, где проходит граница между
«чего хочу» и «что получил».
## 8. Мультиязычность ключевых слов — закрыто по механике
Вопрос был поставлен как «нужен ли английский набор параллельно русскому».
Ответ оказался другой формы: словарь — **параметр естественного языка
набора**, а не часть языка конвенций. Шкала из пяти ступеней инвариантна,
слова под неё подбираются: для английского готовый словарь даёт BCP 14, для
любого другого языка слова берут из перевода стандарта или переводят сами.
Отсюда следствия, снимающие исходный вопрос:
- **параллельных наборов не бывает.** Словарь один на канон: два словаря
дают две формы записи одного требования и удваивают каждую проверку;
- **версия языка при смене словаря не меняется** — версия принадлежит шкале
и правилам формы, а не буквам. Прежняя оценка «английский набор = версия 2»
неверна;
- **`SHALL` не берётся ни в одном словаре**, потому что занято OpenSpec; для
английского это выбор в пользу `MUST` из BCP 14, а не `shall` из ISO;
- отметка о механизации стандартом не даётся ни в одном языке и подбирается
так же, как остальные слова (`МЕХАНИЗИРОВАНО` / `MECHANIZED`).
Открытым остаётся только прикладное: понадобится ли этому канону английская
версия вообще. Механика для неё уже описана, заводить заранее нечего.
## 9. Описание языка отдельно от набора конвенций
`LANGUAGE.md` и `GUIDE.md` описывают, **как** пишутся конвенции;
`conventions/`**один конкретный** набор. Сейчас они склеены в одном
репозитории, и из одного описания нельзя собрать второй набор (рабочий,
доменный, чужой).
Что это даёт, если разнести:
- канон объявляет, какой версии языка следует, а тулинг валидирует набор
**против объявленного описания**, а не против зашитых в код правил;
- таблица модальных слов (вопрос 8) живёт в описании и одна на все наборы;
- вопрос 1 (`LANGUAGE.md` не переживает сборку) меняет форму: собранный файл
ссылается не на путь, а на язык с версией.
Цена — ещё одна сущность и ещё одна синхронизация. Проверить, не выйдет ли
лечение хуже болезни при одном пользователе.
Срочность снята: версия появилась у `LANGUAGE.md` (ключ `version:` в шапке),
и boilerplate-строка из вопроса 1 уже ссылается на язык номером, а не путём —
не дожидаясь выноса. Отдельный репозиторий остаётся вопросом второго набора
конвенций, а не вопросом самодостаточности копии.
Что осталось поводом: из одного описания по-прежнему нельзя собрать второй
набор, и тулинг валидирует правила, зашитые в код, а не объявленную версию
языка. Оба повода включаются, только когда появится второй набор.
## 10. Тулинг на Go, живущий независимо
Сейчас `conv` — питоновский скрипт внутри канона, то есть тулинг и данные в
одном репозитории и правятся одним движением. Мысль: вынести в отдельный
Go-бинарь со своим релизным циклом, ставить через `eget` (механизм уже есть
в pet-project-server).
Что за этим стоит помимо вкуса: независимый бинарь физически не даёт править
инструмент «заодно» с правкой конвенции, работает против **любого** канона и
любого потребителя — что прямо требуется вопросом 9, — и снимает питон из
зависимостей репозиториев-потребителей.
Связано с вопросом 2: если тулинг всё равно переписывается, разделение
«целостность канона / установка в проект» дешевле заложить сразу, чем
отпиливать потом.
Порядок при этом обратный написанному: пока вопрос 9 не сделан, инструмент
всё равно работает против одного конкретного канона, и независимый релизный
цикл ему нечего обслуживать. Сначала 9, потом 10.
## 11. Ссылки на родительский слой своей темы
Из `lang/` и `stack/` ссылаться на идентификаторы своего же арх-слоя
безопасно: при сборке они оказываются секциями одного файла, и ссылка
никуда не ведёт — правило рядом. Ограничение META-20 писалось именно про
**чужую тему**, так что формально это уже разрешено.
Формулировка проверки исправлена: в `LANGUAGE.md` теперь «префикс **чужой
темы** не встречается в абзаце с модальностью», и там же сказано, что
префикс своего базового слоя допустим. Ложного срабатывания на `GTIM`
`TIME-3` больше нет.
Осталось решить одно: добавлять ли в META-20 явную строку **ДОПУСКАЕТСЯ**
про родительский слой. За — правило, которое читают строже, чем оно есть,
заставляет авторов дублировать текст без нужды. Против — норма META-20 уже
говорит «чужой темы», и второе правило про то же место придётся держать
согласованным с первым.
## Из вчерашнего, не закрыто
- Вынос арх-ядра из `errors` и `logging`: закроет две хрупкие ссылки из
`web-ui` (стек) в go-слой — единственные ссылки стек → язык в каноне.
- `conv check` должен уметь отличать ссылку на удалённое правило от
упоминания дыры: сейчас `META-16` в прозе «Оформления» даёт ложное
срабатывание.