Files
dev-conventions/TODO.md
T
av 7fca0e8cb8 из канона удалены пустые локальные регионы
- 31 регион `<!-- local:имя -->` в двенадцати файлах удалён, а не перенесён:
  локальное принадлежит копии и живёт ниже маркера `<!-- conv:local -->`
  (META-22), так что наполнять регионы в каноне нечем
- вместе с ними ушли два опустевших раздела «Связано» — в arch и ansible
  слоях app-directories канонических ссылок нет, а пустой заголовок ничего
  не адресует; CLAUDE.md уточнён: раздел заводят, когда ссылки есть
- форма проверена скриптом: у всех правил модальность и «Почему», префиксы
  сходятся с реестром, дыр в нумерации нет
2026-07-26 13:52:07 +03:00

15 KiB
Raw Blame History

К обсуждению

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

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

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

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

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

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

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

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

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

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

  • 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.
  • Вынос арх-ядра из errors и logging закроет две хрупкие ссылки из web-ui (стек) в go-слой — единственные ссылки стек → язык в каноне.

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

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

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

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

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

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

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

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

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

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

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

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

6. META-20 и родительский слой своей темы

Из lang/ и stack/ ссылаться на идентификаторы своего же арх-слоя безопасно: при сборке они оказываются секциями одного файла, и ссылка никуда не ведёт — правило рядом. Ограничение META-20 писалось про чужую тему, так что формально это уже разрешено, и формулировка проверки в LANGUAGE.md под это исправлена.

Осталось решить одно: добавлять ли в META-20 явную строку ДОПУСКАЕТСЯ про родительский слой. За — правило, которое читают строже, чем оно есть, заставляет авторов дублировать текст без нужды. Против — норма META-20 уже говорит «чужой темы», и второе правило про то же место придётся держать согласованным с первым.

7. WHEN/AND в блоке стыка правил

Блок для стыка двух правил записан английскими словами:

WHEN зависимость недоступна и ретраи вызова исчерпаны → ext-запись ERROR
AND тик фонового цикла упал по той же причине        → доменная запись WARN

Рядом сказано, что SHALL не берётся ни в один словарь, потому что занят OpenSpec. WHEN и AND — из того же набора и по той же причине должны бы не браться, но взяты. Это нестыковка, а не решение.

Варианты:

  • перевести на КОГДА / И: словарь набора один, и служебные слова внутри канона следуют ему же;
  • оставить и объяснить: блок стыка описывает поведение системы во времени, а не выбор автора, — то есть это единственное место, где форма спецификации уместна, и заимствование её синтаксиса намеренно.

Второе честнее по смыслу (субъект там действительно система), но требует явной оговорки в LANGUAGE.md, иначе читается как недосмотр. Заодно решить, подпадают ли WHEN/AND под проверку «заглавные модальные слова не встречаются вне правил»: сейчас формально нет, потому что в словаре их нет.

8. Критерий «названного вреда» никого не обязывает

LANGUAGE.md говорит, что ДОЛЖЕН требует двух условий сразу: нарушение причиняет названный вред (критерий BCP 14) и норма проверяема машиной (META-6). Но правила под первое условие нет: META-6 работает только в одну сторону — «нет машинной проверки, понижай в СЛЕДУЕТ». Обратной, «проверка есть, а вреда нет — не повышай», не существует, и автор ничем не связан.

Решить, заводить ли META-24 под первое условие или оставить его семантикой шкалы в описании языка. За правило: механически проверяемых мелочей больше, чем важных вещей, и без нормы шкала размывается тем же способом, от которого META-6 её защищает. Против: критерий «вред назван» проверяется чтением, а не машиной, — то есть по META-6 сам он может быть только СЛЕДУЕТ.

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

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

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

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

10. Возможность, записанная модальным словом

Четвёртая категория ISO — возможность и осуществимость — ключевого слова не имеет: такие утверждения пишутся обычной прозой. Значит канон надо просмотреть на обратную ошибку: где утверждение о факте («библиотеки по умолчанию отдают именно его», «SQLite сравнивает строки побайтово») записано модальным словом и тем самым превратилось в норму, которую никто не вводил.

Смотреть в первую очередь абзацы «Почему»: там факты и стоят, там же соблазн усилить их модальностью выше всего.

Мелкое, не закрыто

  • conv check должен уметь отличать ссылку на удалённое правило от упоминания дыры: сейчас META-16 в прозе «Оформления» даёт ложное срабатывание.