Files
dev-conventions/TODO.md
T
av 4de6e0f896 черновик «К обсуждению» закоммичен
- одиннадцать открытых вопросов по сборке, тулингу и разделению языка и
  набора конвенций: в переписке они теряются, а часть уже противоречит
  README, и это противоречие видно только рядом с текстом
- снята строка «Не коммитится» и поправлено то же утверждение в CLAUDE.md
2026-07-26 09:06:38 +03:00

241 lines
19 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# К обсуждению
Черновик для следующего разговора: вопросы и варианты, а не принятые
решения.
## 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` в прозе «Оформления» даёт ложное
срабатывание.