- вопрос 3 закрыт: модель записана в README и GUIDE, отмечены три места, где итог разошёлся с прежними заготовками — нет лока, нет маркеров секций, локальные префиксы не объявляются, а резервируются буквой `X` - вопрос 4 переформулирован: регионы не переносятся в единую секцию, а удаляются из канона — наполнять их в каноне нечем - вопрос 7 заменён разбором: транспорт переизобретался, оси и сборка аналога не имеют, Vale отклонён; в 1, 9 и 10 добавлены следствия
21 KiB
К обсуждению
Черновик для следующего разговора: вопросы и варианты, а не принятые решения.
1. Ссылка на LANGUAGE.md не переживает сборку
Все двенадцать конвенций во вводной прозе пишут «Форма записи —
LANGUAGE.md». Обвязка в репозиторий не едет (conv синхронизирует только
conventions/), поэтому в собранной копии эта ссылка указывает в никуда.
Это тот же класс дефекта, который вчера закрыло META-21 для ссылок между темами: путь, верный в каноне, молча умирает при сборке. Разница в том, что META-21 предлагает заменить путь на имя темы — а здесь заменять не на что, целевого документа в репозитории просто нет.
Варианты, которые видно сейчас:
- Убрать упоминание из тел конвенций. Язык записи — забота того, кто пишет канон, а не того, кто читает конвенцию в своём репозитории. Читателю достаточно самого текста: модальные слова и «Почему» самоописательны. Дешевле всего, но копия теряет указание, по каким правилам её править.
- Возить обвязку вместе с конвенциями. Тогда
LANGUAGE.mdи, возможно,GUIDE.mdпоявляются вdocs/conventions/как ещё одни синхронизируемые файлы. Честно, но противоречит нынешнему разделению «канон — конвенции, корень — обвязка» и добавляет в репозиторий текст, который агенту при чтении конвенции не нужен. - Вкладывать короткую преамбулу в собранный файл. Сборщик пишет в шапку три-четыре строки: что такое модальное слово, что «Почему» обязательно, где лежит полный документ. Самодостаточно и не тащит весь язык, но преамбула дублируется в каждом файле темы.
Появился четвёртый вариант, и он выглядит лучше трёх: boilerplate-строка как в RFC 8174. Каждая конвенция несёт одну фразу — «ключевые слова … толкуются как описано в „Языке конвенций“ версии 1 — тогда и только тогда, когда написаны заглавными». Пути нет, документа рядом нет, а норму исполнить можно: строка сама несёт и словарь, и правило капса. Разбирается в заходе про язык записи, вместе с версией — она же цепляет вопрос 9.
Сопутствующее: GUIDE.md в телах конвенций не упоминается ни разу —
проверено, так что вопрос только про LANGUAGE.md.
2. Тулинг: две разные задачи в одном conv
Сейчас в conv смешаны две категории работы, и они расходятся по всему —
по частоте запуска, по тому, кто запускает, и по тому, что считается
провалом.
Целостность канона. Префиксы уникальны и не переиспользованы, шапка совпадает с реестром, номера без дыр вниз, у каждого правила модальность и «Почему», ссылки разрешаются, чужой префикс не лезет в норму (META-20), путей канона в тексте нет (META-21). Запускается в каноне, при каждой правке, провал — это ошибка. Логика уже написана и много раз прогнана руками, но живёт в скретчпаде, а не в репозитории.
Установка в проект. Манифест .conventions.toml, сборка файла темы из
секций (arch → языки → стеки → local), сохранение локальной секции при
пересборке, отчёт «канон ушёл вперёд», предупреждение о висячих ссылках на
неподписанные темы. Запускается в репозитории-потребителе, изредка, провал —
это чаще «посмотри глазами», чем «ошибка».
Что обсудить:
- Разделять ли на два исполняемых файла, или хватит подкоманд с честной границей внутри.
- Валидацию канона стоит ли отдать агенту скиллом вместо (или вдобавок к) скрипту: часть проверок формулируется как «прочитай и скажи, самодостаточна ли норма» — механически это не берётся, а агентом берётся.
- Куда в этой раскладке ложится запаркованное предупреждение о висячих ссылках: это установка, а не целостность, но список подписок ему нужен из манифеста.
3. Модель сборки — записана, закрыто
Записана в README.md (разделы «Копия в репозитории» и «Манифест») и в
GUIDE.md (META-22, META-23). Плоская раскладка, файл на тему, один маркер
<!-- conv:local -->, манифест из источника и списка тем, направление
строго одностороннее.
Против прежних заготовок разошлось в трёх местах:
- лока нет — «что было в прошлый раз» знает git, копии закоммичены, и
автоматического обновления не существует; заодно из шапки копии ушли
origin_hashиsynced, осталось одноorigin:; - маркеров секций нет — раз обновление перезаписывает всё выше локального маркера, разметка слоёв тулингу не нужна; слои идут обычными заголовками;
- локальные префиксы не объявляются в манифесте — за репозиториями
зарезервирована буква
X, столкновение невозможно по построению.
Остаётся переписать conv: сейчас в нём зеркальное дерево, именованные
регионы, origin_hash и команды status/diff/push. Это вопрос 2.
4. Именованные регионы — удалить из канона
Решение принято и записано: регионов нет, есть один маркер
<!-- conv:local -->, который ставит сборщик в копии. Значит регионы не
переносятся в единую секцию, а удаляются: в каноне их нечем наполнять,
локальное принадлежит копии.
Остаётся механическая работа — 31 регион в 12 файлах:
7 связано 7 отступления 7 механизировано
1 эталон / эталоны / словарь / секреты / секретные-поля
1 проверки / поля / модель-владельца / маппинг / границы
Вопрос про связано снят: 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. Не переизобретено ли это — разобрано
Проверка перед вложением в тулинг сделана. По слоям:
- Язык записи — велосипед, но собранный из проверенных деталей: словарь совпадает с RFC 2119/8174 вплоть до правила «нормативен только капс», обязательное «Почему» — дисциплина из requirements engineering (ISO/IEC/IEEE 29148), стабильные идентификаторы — из semgrep/ESLint. Менять архитектуру нечего, остались шесть точечных дельт — отдельным заходом.
- Оси и сборка — аналога не нашлось. Ближайшие соседи (каскад
extendsв ESLint, слои стилей Vale) дают праву слоя отменять базу; наш запрет строже, и это содержательная часть. Вкладываться сюда. - Транспорт — переизобретался, но задача у нас другая, чем у copier и
cruft. У них трёхсторонний merge потому, что шаблон порождает код, который
правят везде: расхождение неограниченно. У нас расхождение ограничено и
живёт под маркером, поэтому исключение из перезаписи лучше merge —
детерминированно и без конфликтных маркеров. Из vendir/cruft взят разбор
«манифест против лока», из ansible
blockinfile— идея размечать управляемый кусок, а не локальный. Лок при этом не взят: его роль играет git. - Раздача агентам — не наша задача, остаёмся на
AGENTS.md/CLAUDE.mdплюс скиллы.
Vale отклонён. Из восьми проверок в LANGUAGE.md он честно закрывает
две-три (модальные слова вне правил, запрещённые формулировки); остальные
пять структурные — «у каждого ### ПРЕФИКС-N есть модальность и Почему»,
«номера без дыр вниз», «префикс совпадает с реестром». Это разбор документа,
а не проверка токенов в области. Ради двух-трёх проверок тянуть ещё один
бинарь и директорию стилей при одном пользователе не стоит.
Что стоит посмотреть перед переписыванием conv (вопрос 2): дистрибуцию
пакетов Vale (.vale.ini → vale sync → styles/) как готовый прототип
манифеста, и vendir.yml — как пример того, где проходит граница между
«чего хочу» и «что получил».
8. Мультиязычность ключевых слов
Модальные слова сейчас русские, и это осознанно: разный словарь держит границу «конвенция — не спецификация» бесплатно. Вопрос — нужен ли английский набор параллельно.
За: канон может однажды понадобиться на английском; агенты натренированы на MUST/SHOULD плотнее, чем на ДОЛЖЕН/СЛЕДУЕТ. Против: два набора — это два способа записать одно, и проверка «модальные слова не встречаются вне правил» усложняется вдвое.
Если делать, то таблица ключевых слов должна принадлежать описанию языка, а не каждой конвенции — то есть вопрос завязан на следующий.
9. Описание языка отдельно от набора конвенций
LANGUAGE.md и GUIDE.md описывают, как пишутся конвенции;
conventions/ — один конкретный набор. Сейчас они склеены в одном
репозитории, и из одного описания нельзя собрать второй набор (рабочий,
доменный, чужой).
Что это даёт, если разнести:
- канон объявляет, какой версии языка следует, а тулинг валидирует набор против объявленного описания, а не против зашитых в код правил;
- таблица модальных слов (вопрос 8) живёт в описании и одна на все наборы;
- вопрос 1 (
LANGUAGE.mdне переживает сборку) меняет форму: собранный файл ссылается не на путь, а на язык с версией.
Цена — ещё одна сущность и ещё одна синхронизация. Проверить, не выйдет ли лечение хуже болезни при одном пользователе.
Оценка выросла: у выноса появилась вторая, независимая причина. Boilerplate- строка из вопроса 1 обязана назвать язык с версией — иначе она врёт при первом же изменении словаря. Версия предполагает документ, у которого версия бывает, то есть отдельный от набора. Так IETF и решил ровно эту задачу: RFC 2119 — самостоятельный документ, на который спецификации ссылаются номером, а не путём.
10. Тулинг на Go, живущий независимо
Сейчас conv — питоновский скрипт внутри канона, то есть тулинг и данные в
одном репозитории и правятся одним движением. Мысль: вынести в отдельный
Go-бинарь со своим релизным циклом, ставить через eget (механизм уже есть
в pet-project-server).
Что за этим стоит помимо вкуса: независимый бинарь физически не даёт править инструмент «заодно» с правкой конвенции, работает против любого канона и любого потребителя — что прямо требуется вопросом 9, — и снимает питон из зависимостей репозиториев-потребителей.
Связано с вопросом 2: если тулинг всё равно переписывается, разделение «целостность канона / установка в проект» дешевле заложить сразу, чем отпиливать потом.
Порядок при этом обратный написанному: пока вопрос 9 не сделан, инструмент всё равно работает против одного конкретного канона, и независимый релизный цикл ему нечего обслуживать. Сначала 9, потом 10.
11. Ссылки на родительский слой своей темы
Из lang/ и stack/ ссылаться на идентификаторы своего же арх-слоя
безопасно: при сборке они оказываются секциями одного файла, и ссылка
никуда не ведёт — правило рядом. Ограничение META-20 писалось именно про
чужую тему, так что формально это уже разрешено.
Но стоит проговорить явно, потому что сейчас читается уже как запрет:
- в
LANGUAGE.mdпроверка сформулирована как «чужой префикс не встречается в абзаце с модальностью» — по букве это ловит иGTIM→TIME-3, то есть ложно срабатывает на ровно том случае, который разрешён. Должно быть «префикс чужой темы»; - обсудить, не добавить ли в META-20 явную строку ДОПУСКАЕТСЯ про родительский слой: правило, которое читают как более строгое, чем оно есть, заставляет авторов дублировать текст без нужды.
Из вчерашнего, не закрыто
- Вынос арх-ядра из
errorsиlogging: закроет две хрупкие ссылки изweb-ui(стек) в go-слой — единственные ссылки стек → язык в каноне. conv checkдолжен уметь отличать ссылку на удалённое правило от упоминания дыры: сейчасMETA-16в прозе «Оформления» даёт ложное срабатывание.