черновик «К обсуждению» закоммичен

- одиннадцать открытых вопросов по сборке, тулингу и разделению языка и
  набора конвенций: в переписке они теряются, а часть уже противоречит
  README, и это противоречие видно только рядом с текстом
- снята строка «Не коммитится» и поправлено то же утверждение в CLAUDE.md
This commit is contained in:
av
2026-07-26 09:06:38 +03:00
parent f2aee9e992
commit 4de6e0f896
2 changed files with 243 additions and 3 deletions
+3 -3
View File
@@ -114,6 +114,6 @@ code in this repository.
проверка.
- Ни один репозиторий-потребитель ещё не подключён: копий с шапкой `origin:`
в природе нет, все локальные регионы канона пусты.
- `TODO.md` не коммитится. Это площадка для обсуждения на будущее, а не
принятые решения; при работе над обвязкой его стоит прочесть, но истина о
текущем устройстве — `README.md`.
- `TODO.md` площадка для обсуждения на будущее, а не принятые решения; при
работе над обвязкой его стоит прочесть, но истина о текущем устройстве —
`README.md`.
+240
View File
@@ -0,0 +1,240 @@
# К обсуждению
Черновик для следующего разговора: вопросы и варианты, а не принятые
решения.
## 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` с
машиночитаемыми маркерами `<!-- conv:section … -->` и `<!-- conv:local -->`;
- языки и стеки образуют разреженную матрицу; файл темы собирает её строку,
многоязычная тема держит несколько языковых секций в одном файле;
- выбор описывается манифестом `.conventions.toml` в корне
репозитория-потребителя; путь к канону там **не** хранится;
- направление строго одностороннее: канон → код. Правка канона делается
руками в каноне, потом пересборка;
- локальные префиксы правил репозитория объявляются в манифесте и не
пересекаются с реестром канона.
Что этому прямо противоречит в репозитории сейчас:
- `README.md` → «Раскладка в репозитории» показывает зеркальное дерево
`docs/conventions/arch/db-identifiers.md`;
- `README.md` → «Команды» и «Контракт с агентом» описывают `conv push` и
`conv push --new` как штатный путь; при односторонней модели транспорт
назад исчезает, остаётся только детект «копия правлена вне локальной
секции»;
- `conv` содержит `cmd_push` со всей обвязкой (`--new`, `--force`).
## 4. Именованные регионы → одна локальная секция
Решено заменить регионы `<!-- local:имя -->` на одну локальную секцию в
конце собранного файла: отступление ссылается на идентификатор правила
(`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` в прозе «Оформления» даёт ложное
срабатывание.