- живые идентификаторы KEYS-5, SLOG-8.1, SLOG-27, MIGR-2/4/6 в примерах заменены на XKEY, XMIG, XLOG: номера канона означали не то, что в примере, и расходились дальше при каждой перенумерации - сказано явно, что описание языка ни на один набор конвенций не опирается; ссылка на обоснования канона в разделе про ПОЧЕМУ заменена на внешние практики
239 lines
19 KiB
Markdown
239 lines
19 KiB
Markdown
# К обсуждению
|
||
|
||
Черновик для следующего разговора: вопросы и варианты, а не принятые
|
||
решения. Закрытый вопрос отсюда удаляется — принятое решение живёт в
|
||
`README.md`, `GUIDE.md` или `LANGUAGE.md`, а не в этом файле.
|
||
|
||
Две секции: сначала язык и подход, потом канон с тулингом. Пункты 1–6
|
||
пришли из внешнего ревью описания языка и проверены по файлам на месте.
|
||
|
||
# Язык и подход
|
||
|
||
## 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 выведен из-под проверок ложным основанием
|
||
|
||
`LANGUAGE.md` исключает обвязку из проверок формулировкой «она ключевые слова
|
||
цитирует, а не употребляет». Для `GUIDE.md` это неверно: META-правила
|
||
употребляют ДОЛЖЕН нормативно, а префикс META зарегистрирован в `[live]`, где
|
||
прямо сказано, что правила записаны тем же языком.
|
||
|
||
Три следствия. META-правила не попадают ни под одну проверку формы. В
|
||
`GUIDE.md` нет строки о версии языка, то есть у META-правил формально нет
|
||
ключа к толкованию. И нарушение уже есть: раздел «Оформление» содержит
|
||
заглавное СЛЕДУЕТ во вводной прозе — в файле конвенции это было бы
|
||
нарушением, а исключение обвязки его прячет.
|
||
|
||
Честнее развести: `GUIDE.md` язык **употребляет** и проверяется как
|
||
конвенция, `LANGUAGE.md` и `README.md` — цитируют.
|
||
|
||
## 3. МЕХАНИЗИРОВАНО не переживает нового подписчика
|
||
|
||
META-8 запрещает удалять норму, пока механизирована не у всех, и защищает
|
||
тем самым потребителей, существующих **на момент удаления**. Будущих не
|
||
защищает никто.
|
||
|
||
Сценарий: норма удалена, потому что у всех трёх тогдашних потребителей был
|
||
линтер. Через год подключается четвёртый репозиторий, подписывается на тему —
|
||
и получает правило без формулировки и без проверки: ни текста, ни линтера,
|
||
восстановление только через git-историю канона.
|
||
|
||
Смежное: «общий конфиг линтера или общая роль» из META-9 — сущность, которой
|
||
в модели распространения (манифест, темы, слои) не существует, и непонятно,
|
||
как она доезжает до потребителя. И отдельно: запись «проверяется общим
|
||
правилом линтера» — это утверждение о состоянии инфраструктуры потребителей
|
||
в тексте канона, то есть ровно то, что запрещает META-4. Либо это законное
|
||
исключение, и тогда его надо назвать, либо конфликт.
|
||
|
||
## 4. Семантика ключевых слов в копию не едет
|
||
|
||
Строка о версии языка перечисляет слова, но не их значения, а всё
|
||
нетривиальное в шкале живёт только в `LANGUAGE.md`, который в репозиторий не
|
||
едет: что ДОПУСКАЕТСЯ запрещает возражать на ревью, что отступление от
|
||
ДОЛЖЕН требует записи, что отступление от СЛЕДУЕТ требует причины.
|
||
|
||
Аналогия с BCP 14 ломается именно там, где призвана работать: RFC 2119
|
||
общедоступен и общеизвестен, «язык конвенций версии 1» — нет. Агент в
|
||
репозитории-потребителе прочитает ДОПУСКАЕТСЯ как бытовое «можно» и примет
|
||
возражение на ревью — ровно та потеря, ради которой слово вводилось.
|
||
|
||
Для одного автора терпимо, для агентов — нет. Варианты: возить рядом с
|
||
копиями короткую выжимку семантики; расширить строку о версии до
|
||
двух-трёх предложений; или признать ограничение и записать его явно.
|
||
|
||
## 5. Две «механические» проверки без источника данных
|
||
|
||
В списке «разбором текста» стоят два пункта, которые без дополнительного
|
||
реестра нерешаемы:
|
||
|
||
- **«номера не имеют пропусков вниз»** — дыры в нумерации нормальны по
|
||
построению, и статическая проверка не отличит дыру от удалённого правила
|
||
от опечатки в номере;
|
||
- **«ссылки указывают на правила, которые ещё существуют»** — упоминание
|
||
снятого номера в прозе выглядит как висячая ссылка.
|
||
|
||
`GUIDE.md` завёл для себя раздел «Освободившиеся номера», но язык не требует
|
||
такой таблицы от конвенций, а `prefixes.toml` хранит только префиксы. Пока
|
||
реестр снятых номеров не объявлен частью языка, оба пункта принадлежат
|
||
списку «чтением».
|
||
|
||
## 6. Натяжки в опоре на стандарты
|
||
|
||
Три места, где источнику приписано чуть больше, чем в нём есть:
|
||
|
||
- **DMN и полнота таблицы.** Политика совпадения — действительно именованное
|
||
свойство DMN. Полноту стандарт не требует: индикатор полноты был в DMN 1.0
|
||
и убран в последующих версиях, её проверяют валидаторы инструментов.
|
||
- **29148 и обоснование.** Rationale там — рекомендуемый атрибут требования,
|
||
а не обязательный «наравне с самим требованием». Обязательный костяк
|
||
стандарта — характеристики well-formed requirement, откуда честно взяты
|
||
единичность и проверяемость.
|
||
- **EARS.** Вывод «выигрыш дала сама обязательность шаблона, а не его
|
||
конкретный вид» — экстраполяция, поданная как взятое из источника. Вывод
|
||
от этого не становится неверным, но графа «что взято» описывает не
|
||
содержимое EARS.
|
||
|
||
Остальное в таблице проверку выдержало, включая вторую половину `MAY` из
|
||
BCP 14 и списки эквивалентных словесных форм ISO Directives.
|
||
|
||
## 7. Одиннадцать таблиц не прочитаны на взаимоисключительность
|
||
|
||
`LANGUAGE.md` объявил, что строки таблицы решений взаимоисключающи по
|
||
умолчанию, а иной порядок объявляется явно. Объявление не делает таблицы
|
||
такими: нумерованные строки есть в одиннадцати файлах канона, и ни одна
|
||
таблица под новое требование не прочитана.
|
||
|
||
Конкретный подозреваемый — SLOG-11: «по реальному действию или изменению»
|
||
против «повторяющаяся служебная, по таймеру или поллингу». Периодическая
|
||
операция, которая всё-таки меняет данные, подходит под обе строки, и уровень
|
||
из таблицы не выводится однозначно.
|
||
|
||
Работа читательская, машине не даётся; в список проверок она уже записана в
|
||
разделе «Чтением, потому что машине не даётся».
|
||
|
||
## 8. Описание языка отдельно от набора конвенций
|
||
|
||
`LANGUAGE.md` и `GUIDE.md` описывают, **как** пишутся конвенции;
|
||
`conventions/` — **один конкретный** набор. Сейчас они склеены в одном
|
||
репозитории, и из одного описания нельзя собрать второй набор (рабочий,
|
||
доменный, чужой).
|
||
|
||
Срочности нет: версия языка объявлена в самом `LANGUAGE.md` (ключ
|
||
`version:`), и конвенции ссылаются на неё номером, а не путём, — то есть
|
||
самодостаточность копии выноса не требует. Примеры в `LANGUAGE.md` вдобавок
|
||
переведены на вымышленные `X`-правила, так что на конкретный набор описание
|
||
языка больше не ссылается вовсе.
|
||
|
||
Что осталось поводом:
|
||
|
||
- из одного описания по-прежнему нельзя собрать второй набор;
|
||
- тулинг валидирует правила, зашитые в его код, а не объявленную версию
|
||
языка.
|
||
|
||
Оба повода включаются, только когда появится второй набор. Цена — ещё одна
|
||
сущность и ещё одна синхронизация; при одном наборе лечение выходит хуже
|
||
болезни.
|
||
|
||
# Канон, тулинг, подключение
|
||
|
||
## 9. Тулинг: две разные задачи в одном `conv`
|
||
|
||
Сейчас в `conv` смешаны две категории работы, и они расходятся по всему —
|
||
по частоте запуска, по тому, кто запускает, и по тому, что считается
|
||
провалом.
|
||
|
||
**Целостность канона.** Префиксы уникальны и не переиспользованы, шапка
|
||
совпадает с реестром, у каждого правила модальность и блок ПОЧЕМУ, ссылки
|
||
разрешаются, префикс чужой темы не лезет в норму (META-20), путей канона в
|
||
тексте нет (META-21), строка о версии языка на месте. Запускается в каноне,
|
||
при каждой правке, провал — это ошибка. Логика уже написана и много раз
|
||
прогнана руками, но живёт в скретчпаде, а не в репозитории.
|
||
|
||
**Установка в проект.** Манифест `.conventions.toml`, сборка файла темы из
|
||
слоёв (`arch` → язык → стек), сохранение при пересборке всего, что ниже
|
||
маркера, предупреждение о висячих ссылках на неподписанные темы. Запускается
|
||
в репозитории-потребителе, изредка, провал — это чаще «посмотри глазами»,
|
||
чем «ошибка». Отчёта «канон ушёл вперёд» здесь нет: его делает `git diff`
|
||
после пересборки.
|
||
|
||
Что обсудить:
|
||
|
||
- Разделять ли на два исполняемых файла, или хватит подкоманд с честной
|
||
границей внутри.
|
||
- Валидацию канона стоит ли отдать агенту скиллом вместо (или вдобавок к)
|
||
скрипту: часть проверок формулируется как «прочитай и скажи, самодостаточна
|
||
ли норма» — механически это не берётся, а агентом берётся.
|
||
- Куда в этой раскладке ложится запаркованное предупреждение о висячих
|
||
ссылках: это установка, а не целостность, но список подписок ему нужен из
|
||
манифеста.
|
||
|
||
Часть проверок из этого списка сейчас нереализуема по причине из вопроса 5,
|
||
так что порядок такой: сначала язык, потом чекер.
|
||
|
||
Перед тем как переписывать, стоит посмотреть на два готовых прототипа:
|
||
дистрибуцию пакетов Vale (`.vale.ini` → `vale sync` → `styles/`) как образец
|
||
манифеста и `vendir.yml` — как пример того, где проходит граница между «чего
|
||
хочу» и «что получил».
|
||
|
||
## 10. Пары слоёв и темы без базы
|
||
|
||
Отложено сознательно, но список стоит держать перед глазами:
|
||
|
||
- `SLOG` объявляет `extends: arch/time.md` — расширение **чужой** темы.
|
||
Сборщик темы `logging` на это наткнётся: базового слоя с темой `logging`
|
||
нет, а `arch/time.md` он тянуть не должен. Чинится переводом в обычную
|
||
ссылку «связано». Вдобавок это ломает гарантию META-24 — см. вопрос 1.
|
||
- Темы без арх-слоя: `db-schema`, `errors`, `web-ui`. Собираются в файл с
|
||
одной секцией — само по себе не ломается, но это и есть тот невыделенный
|
||
арх-слой из известного долга.
|
||
- Имена тем в паре не совпадают: `arch/db-identifiers.md` против
|
||
`lang/go/db-schema.md`. При сборке по имени темы это две разные темы —
|
||
проверить, что так и задумано.
|
||
- В `lang/go/db-schema.md` сидит целый пласт `stack/sqlite/` (типы колонок),
|
||
тоже из известного долга README.
|
||
- Вынос арх-ядра из `errors` и `logging` закроет две хрупкие ссылки из
|
||
`web-ui` (стек) в go-слой — единственные ссылки стек → язык в каноне.
|
||
|
||
## 11. Подключение к репозиториям
|
||
|
||
Ничего ещё не подключено. Кандидаты — jellybit и pet-project-server.
|
||
Понадобится: заполнить локальную часть копий тем, что сейчас в этих
|
||
репозиториях записано по факту; обёртка в раннере (`inv conventions` /
|
||
`task conventions`, единый интерфейс команд у трёх ansible-репозиториев);
|
||
строка в `AGENTS.md` каждого потребителя про то, что файлы в
|
||
`docs/conventions/` — копии.
|
||
|
||
## 12. Тулинг на Go, живущий независимо
|
||
|
||
Сейчас `conv` — питоновский скрипт внутри канона, то есть тулинг и данные в
|
||
одном репозитории и правятся одним движением. Мысль: вынести в отдельный
|
||
Go-бинарь со своим релизным циклом, ставить через `eget` (механизм уже есть
|
||
в pet-project-server).
|
||
|
||
Что за этим стоит помимо вкуса: независимый бинарь физически не даёт править
|
||
инструмент «заодно» с правкой конвенции, работает против **любого** канона и
|
||
любого потребителя — что прямо требуется вопросом 8, — и снимает питон из
|
||
зависимостей репозиториев-потребителей.
|
||
|
||
Порядок обратный ожидаемому: пока вопрос 8 не сделан, инструмент всё равно
|
||
работает против одного конкретного канона, и независимый релизный цикл ему
|
||
нечего обслуживать. Сначала 8, потом 12. Разделение из вопроса 9 при этом
|
||
дешевле заложить сразу, чем отпиливать потом.
|