# К обсуждению Черновик для следующего разговора: вопросы и варианты, а не принятые решения. ## 1. Ссылка на `LANGUAGE.md` не переживает сборку Все двенадцать конвенций во вводной прозе пишут «Форма записи — `LANGUAGE.md`». Обвязка в репозиторий не едет (`conv` синхронизирует только `conventions/`), поэтому в собранной копии эта ссылка указывает в никуда. Это тот же класс дефекта, который вчера закрыло META-21 для ссылок между темами: путь, верный в каноне, молча умирает при сборке. Разница в том, что META-21 предлагает заменить путь на имя темы — а здесь заменять не на что, целевого документа в репозитории просто нет. Варианты, которые видно сейчас: - **Убрать упоминание из тел конвенций.** Язык записи — забота того, кто пишет канон, а не того, кто читает конвенцию в своём репозитории. Читателю достаточно самого текста: модальные слова и «Почему» самоописательны. Дешевле всего, но копия теряет указание, по каким правилам её править. - **Возить обвязку вместе с конвенциями.** Тогда `LANGUAGE.md` и, возможно, `GUIDE.md` появляются в `docs/conventions/` как ещё одни синхронизируемые файлы. Честно, но противоречит нынешнему разделению «канон — конвенции, корень — обвязка» и добавляет в репозиторий текст, который агенту при чтении конвенции не нужен. - **Вкладывать короткую преамбулу в собранный файл.** Сборщик пишет в шапку три-четыре строки: что такое модальное слово, что «Почему» обязательно, где лежит полный документ. Самодостаточно и не тащит весь язык, но преамбула дублируется в каждом файле темы. Сопутствующее: `GUIDE.md` в телах конвенций не упоминается ни разу — проверено, так что вопрос только про `LANGUAGE.md`. ## 2. Тулинг: две разные задачи в одном `conv` Сейчас в `conv` смешаны две категории работы, и они расходятся по всему — по частоте запуска, по тому, кто запускает, и по тому, что считается провалом. **Целостность канона.** Префиксы уникальны и не переиспользованы, шапка совпадает с реестром, номера без дыр вниз, у каждого правила модальность и «Почему», ссылки разрешаются, чужой префикс не лезет в норму (META-20), путей канона в тексте нет (META-21). Запускается в каноне, при каждой правке, провал — это ошибка. Логика уже написана и много раз прогнана руками, но живёт в скретчпаде, а не в репозитории. **Установка в проект.** Манифест `.conventions.toml`, сборка файла темы из секций (arch → языки → стеки → local), сохранение локальной секции при пересборке, отчёт «канон ушёл вперёд», предупреждение о висячих ссылках на неподписанные темы. Запускается в репозитории-потребителе, изредка, провал — это чаще «посмотри глазами», чем «ошибка». Что обсудить: - Разделять ли на два исполняемых файла, или хватит подкоманд с честной границей внутри. - Валидацию канона стоит ли отдать агенту скиллом вместо (или вдобавок к) скрипту: часть проверок формулируется как «прочитай и скажи, самодостаточна ли норма» — механически это не берётся, а агентом берётся. - Куда в этой раскладке ложится запаркованное предупреждение о висячих ссылках: это установка, а не целостность, но список подписок ему нужен из манифеста. ## 3. Согласованная модель сборки нигде не записана Самое срочное. Договорённости про плоскую раскладку живут только в переписке, а репозиторий описывает прежнюю модель — и противоречит новой в нескольких местах сразу. Что решено, но не зафиксировано: - копия плоская, файл на тему: `docs/conventions/config.md`, а не дерево `arch/` + `lang/`; - файл темы собирается из секций `arch → языки → стеки → local` с машиночитаемыми маркерами `` и ``; - языки и стеки образуют разреженную матрицу; файл темы собирает её строку, многоязычная тема держит несколько языковых секций в одном файле; - выбор описывается манифестом `.conventions.toml` в корне репозитория-потребителя; путь к канону там **не** хранится; - направление строго одностороннее: канон → код. Правка канона делается руками в каноне, потом пересборка; - локальные префиксы правил репозитория объявляются в манифесте и не пересекаются с реестром канона. Что этому прямо противоречит в репозитории сейчас: - `README.md` → «Раскладка в репозитории» показывает зеркальное дерево `docs/conventions/arch/db-identifiers.md`; - `README.md` → «Команды» и «Контракт с агентом» описывают `conv push` и `conv push --new` как штатный путь; при односторонней модели транспорт назад исчезает, остаётся только детект «копия правлена вне локальной секции»; - `conv` содержит `cmd_push` со всей обвязкой (`--new`, `--force`). ## 4. Именованные регионы → одна локальная секция Решено заменить регионы `` на одну локальную секцию в конце собранного файла: отступление ссылается на идентификатор правила (`DIRS-5`), а не стоит рядом с ним. Это то, что делает сравнение копии с каноном одним хешем и выкидывает из `conv` перенос регионов по именам. Сделать перенос ещё предстоит: в каноне сейчас **31 регион в 12 файлах**. ``` 7 связано 7 отступления 7 механизировано 1 эталон / эталоны / словарь / секреты / секретные-поля 1 проверки / поля / модель-владельца / маппинг / границы ``` Отдельно решить, что делать с `связано`: сейчас это репо-специфичная часть раздела «Связано» (META-17), и при единой локальной секции она переезжает туда же — надо проверить, что 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. Не переизобретено ли это Проверить перед тем, как вкладываться в тулинг. Ближайшие кандидаты, куда смотреть: - **copier / cruft** — шаблон проекта с последующим `update`: ровно та же задача «стянуть обновление апстрима, не затерев локальные правки», с ответом через три-way merge вместо наших регионов. Стоит понять, почему у них merge, а у нас исключение из сравнения. - **vendir** — вендоринг чужого содержимого с лок-файлом; ближе к нашей модели «канон это лавка». - **Vale** — линтер прозы с правилами в файлах: значительная часть проверок целостности канона (модальные слова вне правил, запрещённые формулировки) выражается его языком. - **RFC 2119 / 8174** — канонический источник модальных слов; наш словарь фактически его перевод, полезно сверить границы значений. - **EARS** — шаблоны требований (ubiquitous / event-driven / state-driven); соседняя формализация того же, что мы решили таблицами. - **Наборы правил для агентов** — `AGENTS.md`, cursor rules, скиллы: задачу «раздать читаемые агентом договорённости по репозиториям» сейчас решают несколько продуктов, и там уже могли устояться форматы. ## 8. Мультиязычность ключевых слов Модальные слова сейчас русские, и это осознанно: разный словарь держит границу «конвенция — не спецификация» бесплатно. Вопрос — нужен ли английский набор параллельно. За: канон может однажды понадобиться на английском; агенты натренированы на MUST/SHOULD плотнее, чем на ДОЛЖЕН/СЛЕДУЕТ. Против: два набора — это два способа записать одно, и проверка «модальные слова не встречаются вне правил» усложняется вдвое. Если делать, то таблица ключевых слов должна принадлежать **описанию языка**, а не каждой конвенции — то есть вопрос завязан на следующий. ## 9. Описание языка отдельно от набора конвенций `LANGUAGE.md` и `GUIDE.md` описывают, **как** пишутся конвенции; `conventions/` — **один конкретный** набор. Сейчас они склеены в одном репозитории, и из одного описания нельзя собрать второй набор (рабочий, доменный, чужой). Что это даёт, если разнести: - канон объявляет, какой версии языка следует, а тулинг валидирует набор **против объявленного описания**, а не против зашитых в код правил; - таблица модальных слов (вопрос 8) живёт в описании и одна на все наборы; - вопрос 1 (`LANGUAGE.md` не переживает сборку) меняет форму: собранный файл ссылается не на путь, а на язык с версией. Цена — ещё одна сущность и ещё одна синхронизация. Проверить, не выйдет ли лечение хуже болезни при одном пользователе. ## 10. Тулинг на Go, живущий независимо Сейчас `conv` — питоновский скрипт внутри канона, то есть тулинг и данные в одном репозитории и правятся одним движением. Мысль: вынести в отдельный Go-бинарь со своим релизным циклом, ставить через `eget` (механизм уже есть в pet-project-server). Что за этим стоит помимо вкуса: независимый бинарь физически не даёт править инструмент «заодно» с правкой конвенции, работает против **любого** канона и любого потребителя — что прямо требуется вопросом 9, — и снимает питон из зависимостей репозиториев-потребителей. Связано с вопросом 2: если тулинг всё равно переписывается, разделение «целостность канона / установка в проект» дешевле заложить сразу, чем отпиливать потом. ## 11. Ссылки на родительский слой своей темы Из `lang/` и `stack/` ссылаться на идентификаторы своего же арх-слоя безопасно: при сборке они оказываются секциями одного файла, и ссылка никуда не ведёт — правило рядом. Ограничение META-20 писалось именно про **чужую тему**, так что формально это уже разрешено. Но стоит проговорить явно, потому что сейчас читается уже как запрет: - в `LANGUAGE.md` проверка сформулирована как «**чужой префикс** не встречается в абзаце с модальностью» — по букве это ловит и `GTIM` → `TIME-3`, то есть ложно срабатывает на ровно том случае, который разрешён. Должно быть «префикс **чужой темы**»; - обсудить, не добавить ли в META-20 явную строку **ДОПУСКАЕТСЯ** про родительский слой: правило, которое читают как более строгое, чем оно есть, заставляет авторов дублировать текст без нужды. ## Из вчерашнего, не закрыто - Вынос арх-ядра из `errors` и `logging`: закроет две хрупкие ссылки из `web-ui` (стек) в go-слой — единственные ссылки стек → язык в каноне. - `conv check` должен уметь отличать ссылку на удалённое правило от упоминания дыры: сейчас `META-16` в прозе «Оформления» даёт ложное срабатывание.