Files
dev-conventions/TODO.md
T
av 67d51db212 механизация больше не разрешает удалять норму
- META-9 снят: удаление оставляло подписчика, пришедшего после, без нормы и
  без проверки, а «механизировано у всех» канону не проверить — списка
  подписчиков у него нет по построению
- META-8 переписан в запрет: норма остаётся в правиле, чем бы её ни
  проверяли; линтер сообщает, что нарушено, но не что требуется (META-6)
- МЕХАНИЗИРОВАНО объявлена свойством репозитория: в тексте конвенции отметки
  нет, её место — запись о механизации ниже маркера (META-7)
2026-07-26 15:41:52 +03:00

15 KiB
Raw Blame History

К обсуждению

Черновик для следующего разговора: вопросы и варианты, а не принятые решения. Закрытый вопрос отсюда удаляется — принятое решение живёт в README.md, GUIDE.md или LANGUAGE.md, а не в этом файле.

Две секции: сначала язык и подход, потом канон с тулингом. Пункты 1–3 пришли из внешнего ревью описания языка и проверены по файлам на месте.

Язык и подход

1. Семантика ключевых слов в копию не едет

Строка о версии языка перечисляет слова, но не их значения, а всё нетривиальное в шкале живёт только в LANGUAGE.md, который в репозиторий не едет: что ДОПУСКАЕТСЯ запрещает возражать на ревью, что отступление от ДОЛЖЕН требует записи, что отступление от СЛЕДУЕТ требует причины.

Аналогия с BCP 14 ломается именно там, где призвана работать: RFC 2119 общедоступен и общеизвестен, «язык конвенций версии 1» — нет. Агент в репозитории-потребителе прочитает ДОПУСКАЕТСЯ как бытовое «можно» и примет возражение на ревью — ровно та потеря, ради которой слово вводилось.

Для одного автора терпимо, для агентов — нет. Варианты: возить рядом с копиями короткую выжимку семантики; расширить строку о версии до двух-трёх предложений; или признать ограничение и записать его явно.

2. Две «механические» проверки без источника данных

В списке «разбором текста» стоят два пункта, которые без дополнительного реестра нерешаемы:

  • «номера не имеют пропусков вниз» — дыры в нумерации нормальны по построению, и статическая проверка не отличит дыру от удалённого правила от опечатки в номере;
  • «ссылки указывают на правила, которые ещё существуют» — упоминание снятого номера в прозе выглядит как висячая ссылка.

GUIDE.md завёл для себя раздел «Освободившиеся номера» — и, поскольку он теперь проверяется как конвенция, это единственный живой пример такого реестра. Языком он всё равно не объявлен: от конвенций такой таблицы не требуют, а манифест набора хранит только темы и префиксы. Пока реестр снятых номеров не объявлен частью языка, оба пункта принадлежат списку «чтением».

3. Натяжки в опоре на стандарты

Три места, где источнику приписано чуть больше, чем в нём есть:

  • DMN и полнота таблицы. Политика совпадения — действительно именованное свойство DMN. Полноту стандарт не требует: индикатор полноты был в DMN 1.0 и убран в последующих версиях, её проверяют валидаторы инструментов.
  • 29148 и обоснование. Rationale там — рекомендуемый атрибут требования, а не обязательный «наравне с самим требованием». Обязательный костяк стандарта — характеристики well-formed requirement, откуда честно взяты единичность и проверяемость.
  • EARS. Вывод «выигрыш дала сама обязательность шаблона, а не его конкретный вид» — экстраполяция, поданная как взятое из источника. Вывод от этого не становится неверным, но графа «что взято» описывает не содержимое EARS.

Остальное в таблице проверку выдержало, включая вторую половину MAY из BCP 14 и списки эквивалентных словесных форм ISO Directives.

4. Одиннадцать таблиц не прочитаны на взаимоисключительность

LANGUAGE.md объявил, что строки таблицы решений взаимоисключающи по умолчанию, а иной порядок объявляется явно. Объявление не делает таблицы такими: нумерованные строки есть в одиннадцати файлах канона, и ни одна таблица под новое требование не прочитана.

Конкретный подозреваемый — SLOG-11: «по реальному действию или изменению» против «повторяющаяся служебная, по таймеру или поллингу». Периодическая операция, которая всё-таки меняет данные, подходит под обе строки, и уровень из таблицы не выводится однозначно.

Работа читательская, машине не даётся; в список проверок она уже записана в разделе «Чтением, потому что машине не даётся».

5. Описание языка отдельно от набора конвенций

LANGUAGE.md и GUIDE.md описывают, как пишутся конвенции; conventions/один конкретный набор. Сейчас они склеены в одном репозитории, и из одного описания нельзя собрать второй набор (рабочий, доменный, чужой).

Срочности нет: версия языка объявлена в самом LANGUAGE.md (ключ version:), и конвенции ссылаются на неё номером, а не путём, — то есть самодостаточность копии выноса не требует. Примеры в LANGUAGE.md вдобавок переведены на вымышленные X-правила, так что на конкретный набор описание языка больше не ссылается вовсе.

Что осталось поводом:

  • из одного описания по-прежнему нельзя собрать второй набор;
  • тулинг валидирует правила, зашитые в его код, а не объявленную версию языка.

Оба повода включаются, только когда появится второй набор. Цена — ещё одна сущность и ещё одна синхронизация; при одном наборе лечение выходит хуже болезни.

Канон, тулинг, подключение

6. Тулинг: две разные задачи в одном conv

Сейчас в conv смешаны две категории работы, и они расходятся по всему — по частоте запуска, по тому, кто запускает, и по тому, что считается провалом.

Целостность канона. Префиксы уникальны и не переиспользованы, шапка совпадает с манифестом, у каждого правила модальность и блок ПОЧЕМУ, ссылки разрешаются, префикс чужой темы не лезет в норму (META-20), путей канона в тексте нет (META-21), строка о версии языка на месте. Запускается в каноне, при каждой правке, провал — это ошибка. Логика уже написана и много раз прогнана руками, но живёт в скретчпаде, а не в репозитории.

Установка в проект. Манифест .conventions.toml, сборка файла темы из слоёв (arch → язык → стек), сохранение при пересборке всего, что ниже маркера, предупреждение о висячих ссылках на неподписанные темы. Запускается в репозитории-потребителе, изредка, провал — это чаще «посмотри глазами», чем «ошибка». Отчёта «канон ушёл вперёд» здесь нет: его делает git diff после пересборки.

Что обсудить:

  • Разделять ли на два исполняемых файла, или хватит подкоманд с честной границей внутри.
  • Валидацию канона стоит ли отдать агенту скиллом вместо (или вдобавок к) скрипту: часть проверок формулируется как «прочитай и скажи, самодостаточна ли норма» — механически это не берётся, а агентом берётся.
  • Куда в этой раскладке ложится запаркованное предупреждение о висячих ссылках: это установка, а не целостность, но список подписок ему нужен из манифеста.

Часть проверок из этого списка сейчас нереализуема по причине из вопроса 2, так что порядок такой: сначала язык, потом чекер.

Перед тем как переписывать, стоит посмотреть на два готовых прототипа: дистрибуцию пакетов Vale (.vale.inivale syncstyles/) как образец манифеста и vendir.yml — как пример того, где проходит граница между «чего хочу» и «что получил».

7. Пары слоёв и темы без базы

Отложено сознательно, но список стоит держать перед глазами:

  • SLOG объявляет extends: arch/time.md — расширение чужой темы. Сборщик темы logging на это наткнётся: базового слоя с темой logging нет, а arch/time.md он тянуть не должен. Чинится переводом в обычную ссылку «связано». Вдобавок это ломает гарантию META-24: она верна только для базы своей темы, а arch/time.md объявляет тему time, не logging. С объявленной темой расхождение стало проверяемым машинно.
  • Темы без арх-слоя: 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-слой — единственные ссылки стек → язык в каноне.

8. Подключение к репозиториям

Ничего ещё не подключено. Кандидаты — jellybit и pet-project-server. Понадобится: заполнить локальную часть копий тем, что сейчас в этих репозиториях записано по факту; обёртка в раннере (inv conventions / task conventions, единый интерфейс команд у трёх ansible-репозиториев); строка в AGENTS.md каждого потребителя про то, что файлы в docs/conventions/ — копии.

9. Тулинг на Go, живущий независимо

Сейчас conv — питоновский скрипт внутри канона, то есть тулинг и данные в одном репозитории и правятся одним движением. Мысль: вынести в отдельный Go-бинарь со своим релизным циклом, ставить через eget (механизм уже есть в pet-project-server).

Что за этим стоит помимо вкуса: независимый бинарь физически не даёт править инструмент «заодно» с правкой конвенции, работает против любого канона и любого потребителя — что прямо требуется вопросом 5, — и снимает питон из зависимостей репозиториев-потребителей.

Порядок обратный ожидаемому: пока вопрос 5 не сделан, инструмент всё равно работает против одного конкретного канона, и независимый релизный цикл ему нечего обслуживать. Сначала 5, потом 9. Разделение из вопроса 6 при этом дешевле заложить сразу, чем отпиливать потом.