# К обсуждению Черновик для следующего разговора: вопросы и варианты, а не принятые решения. Закрытый вопрос отсюда удаляется — принятое решение живёт в `README.md`, `GUIDE.md` или `LANGUAGE.md`, а не в этом файле. ## 1. Тулинг: две разные задачи в одном `conv` Сейчас в `conv` смешаны две категории работы, и они расходятся по всему — по частоте запуска, по тому, кто запускает, и по тому, что считается провалом. **Целостность канона.** Префиксы уникальны и не переиспользованы, шапка совпадает с реестром, номера без дыр вниз, у каждого правила модальность и «Почему», ссылки разрешаются, префикс чужой темы не лезет в норму (META-20), путей канона в тексте нет (META-21), строка о версии языка на месте. Запускается в каноне, при каждой правке, провал — это ошибка. Логика уже написана и много раз прогнана руками, но живёт в скретчпаде, а не в репозитории. **Установка в проект.** Манифест `.conventions.toml`, сборка файла темы из слоёв (`arch` → язык → стек), сохранение при пересборке всего, что ниже маркера, предупреждение о висячих ссылках на неподписанные темы. Запускается в репозитории-потребителе, изредка, провал — это чаще «посмотри глазами», чем «ошибка». Отчёта «канон ушёл вперёд» здесь нет: его делает `git diff` после пересборки. Что обсудить: - Разделять ли на два исполняемых файла, или хватит подкоманд с честной границей внутри. - Валидацию канона стоит ли отдать агенту скиллом вместо (или вдобавок к) скрипту: часть проверок формулируется как «прочитай и скажи, самодостаточна ли норма» — механически это не берётся, а агентом берётся. - Куда в этой раскладке ложится запаркованное предупреждение о висячих ссылках: это установка, а не целостность, но список подписок ему нужен из манифеста. Перед тем как переписывать, стоит посмотреть на два готовых прототипа: дистрибуцию пакетов Vale (`.vale.ini` → `vale sync` → `styles/`) как образец манифеста и `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. Одиннадцать таблиц не прочитаны на взаимоисключительность `LANGUAGE.md` объявил, что строки таблицы решений взаимоисключающи по умолчанию, а иной порядок объявляется явно. Объявление не делает таблицы такими: нумерованные строки есть в одиннадцати файлах канона, и ни одна таблица под новое требование не прочитана. Конкретный подозреваемый — SLOG-11: «по реальному действию или изменению» против «повторяющаяся служебная, по таймеру или поллингу». Периодическая операция, которая всё-таки меняет данные, подходит под обе строки, и уровень из таблицы не выводится однозначно. Работа читательская, машине не даётся; в список проверок она уже записана в разделе «Чтением, потому что машине не даётся». ## 7. Пересказ нормы в «Почему» — вычитать под META-26 Исходный вопрос («где факт записан модальным словом») закрыт по существу: канон просмотрен, и такой ошибки в нём практически нет. Тринадцать строчных «нельзя» оказались корректными — это утверждения о невозможности, ISO-евская возможность в прозе, ровно как задумано. Единственный настоящий случай, SLOG-12, починен: факт про `slog` уехал в «Почему», норма повторяет свой заголовок. Зато нашёлся обратный класс, под который заведён META-26: норма пересказана словами обязательства внутри «Почему». Греп даёт десять совпадений, из них семь — кандидаты на правку, вердикт за чтением: ``` arch/db-identifiers.md:61 «Нормализация регистра (KEYS-4) … обязаны» arch/time.md:43 «текстовому полю обязан давать порядок событий» arch/time.md:91 «Формат, зона (TIME-1) и ширина (TIME-2) обязаны» lang/go/db-schema.md:88 «именно там он обязан действительно обращать up» lang/go/logging.md:61 «по TIME-2 так и должно быть» lang/go/logging.md:85 «совпадать они обязаны» lang/go/logging.md:295 «выборка … не должна» ``` Лечение в большинстве случаев — заменить пересказ ссылкой на идентификатор, который в тех же фразах уже стоит рядом. Остальные три совпадения отброшены как омонимы: «за попыткой следует повтор» (`logging.md:400`), «становится обязанностью каждого вызывающего» (`db- identifiers.md:42`), «заметить можно, только зная, что они должны были быть» (`logging.md:186`) — все три описывают ход событий, а не требуют. Это и есть причина, по которой META-26 — рекомендация: греп находит слово, а не нарушение. ## Мелкое, не закрыто - `conv check` должен уметь отличать ссылку на удалённое правило от упоминания дыры: сейчас `META-16` в прозе «Оформления» даёт ложное срабатывание.