diff --git a/TODO.md b/TODO.md index b647c9f..508ec5e 100644 --- a/TODO.md +++ b/TODO.md @@ -1,22 +1,10 @@ # К обсуждению Черновик для следующего разговора: вопросы и варианты, а не принятые -решения. +решения. Закрытый вопрос отсюда удаляется — принятое решение живёт в +`README.md`, `GUIDE.md` или `LANGUAGE.md`, а не в этом файле. -## 1. Ссылка на язык — закрыто - -Заменено boilerplate-строкой по образцу BCP 14: каждая конвенция называет -ключевые слова, версию языка и правило заглавных, но не путь. Строка стоит -отдельным абзацем после вводной прозы во всех двенадцати файлах, «Форма -записи — `LANGUAGE.md`» удалена. Точный текст — в `LANGUAGE.md`, раздел -«Ссылка на язык из конвенции». - -Побочно: строка перечисляет модальные слова заглавными, то есть сама -нарушает проверку «заглавные модальные слова не встречаются вне правил». -Исключение записано в список проверок — так же, как оно устроено в BCP 14, -где boilerplate тоже содержит ключевые слова. - -## 2. Тулинг: две разные задачи в одном `conv` +## 1. Тулинг: две разные задачи в одном `conv` Сейчас в `conv` смешаны две категории работы, и они расходятся по всему — по частоте запуска, по тому, кто запускает, и по тому, что считается @@ -24,16 +12,18 @@ **Целостность канона.** Префиксы уникальны и не переиспользованы, шапка совпадает с реестром, номера без дыр вниз, у каждого правила модальность и -«Почему», ссылки разрешаются, чужой префикс не лезет в норму (META-20), -путей канона в тексте нет (META-21). Запускается в каноне, при каждой -правке, провал — это ошибка. Логика уже написана и много раз прогнана -руками, но живёт в скретчпаде, а не в репозитории. +«Почему», ссылки разрешаются, префикс чужой темы не лезет в норму (META-20), +путей канона в тексте нет (META-21), строка о версии языка на месте. +Запускается в каноне, при каждой правке, провал — это ошибка. Логика уже +написана и много раз прогнана руками, но живёт в скретчпаде, а не в +репозитории. **Установка в проект.** Манифест `.conventions.toml`, сборка файла темы из -секций (arch → языки → стеки → local), сохранение локальной секции при -пересборке, отчёт «канон ушёл вперёд», предупреждение о висячих ссылках на -неподписанные темы. Запускается в репозитории-потребителе, изредка, провал — -это чаще «посмотри глазами», чем «ошибка». +слоёв (`arch` → язык → стек), сохранение при пересборке всего, что ниже +маркера, предупреждение о висячих ссылках на неподписанные темы. Запускается +в репозитории-потребителе, изредка, провал — это чаще «посмотри глазами», +чем «ошибка». Отчёта «канон ушёл вперёд» здесь нет: его делает `git diff` +после пересборки. Что обсудить: @@ -46,28 +36,12 @@ ссылках: это установка, а не целостность, но список подписок ему нужен из манифеста. -## 3. Модель сборки — записана, закрыто +Перед тем как переписывать, стоит посмотреть на два готовых прототипа: +дистрибуцию пакетов Vale (`.vale.ini` → `vale sync` → `styles/`) как образец +манифеста и `vendir.yml` — как пример того, где проходит граница между «чего +хочу» и «что получил». -Записана в `README.md` (разделы «Копия в репозитории» и «Манифест») и в -`GUIDE.md` (META-22, META-23). Плоская раскладка, файл на тему, один маркер -``, манифест из источника и списка тем, направление -строго одностороннее. - -Против прежних заготовок разошлось в трёх местах: - -- **лока нет** — «что было в прошлый раз» знает git, копии закоммичены, и - автоматического обновления не существует; заодно из шапки копии ушли - `origin_hash` и `synced`, осталось одно `origin:`; -- **маркеров секций нет** — раз обновление перезаписывает всё выше - локального маркера, разметка слоёв тулингу не нужна; слои идут обычными - заголовками; -- **локальные префиксы не объявляются в манифесте** — за репозиториями - зарезервирована буква `X`, столкновение невозможно по построению. - -Остаётся переписать `conv`: сейчас в нём зеркальное дерево, именованные -регионы, `origin_hash` и команды `status`/`diff`/`push`. Это вопрос 2. - -## 4. Именованные регионы — удалить из канона +## 2. Именованные регионы — удалить из канона Решение принято и записано: регионов нет, есть один маркер ``, который ставит сборщик в копии. Значит регионы не @@ -82,11 +56,7 @@ 1 проверки / поля / модель-владельца / маппинг / границы ``` -Вопрос про `связано` снят: META-17 переписан, канонический раздел «Связано» -остаётся в тексте и содержит только ссылки, верные у всех, а репо-специфичные -уходят под маркер. - -## 5. Пары слоёв и темы без базы +## 3. Пары слоёв и темы без базы Отложено сознательно, но список стоит держать перед глазами: @@ -102,107 +72,40 @@ проверить, что так и задумано. - В `lang/go/db-schema.md` сидит целый пласт `stack/sqlite/` (типы колонок), тоже из известного долга README. +- Вынос арх-ядра из `errors` и `logging` закроет две хрупкие ссылки из + `web-ui` (стек) в go-слой — единственные ссылки стек → язык в каноне. -## 6. Подключение к репозиториям +## 4. Подключение к репозиториям Ничего ещё не подключено. Кандидаты — jellybit и pet-project-server. -Понадобится: заполнить локальные секции тем, что сейчас в этих репозиториях -записано по факту; обёртка в раннере (`inv conventions` / `task conventions`, -единый интерфейс команд у трёх ansible-репозиториев); строка в `AGENTS.md` -каждого потребителя про то, что файлы в `docs/conventions/` — копии. +Понадобится: заполнить локальную часть копий тем, что сейчас в этих +репозиториях записано по факту; обёртка в раннере (`inv conventions` / +`task conventions`, единый интерфейс команд у трёх ansible-репозиториев); +строка в `AGENTS.md` каждого потребителя про то, что файлы в +`docs/conventions/` — копии. -Открытый кусок с прошлого раза: **как копия ссылается на канон, не ломая -самодостаточность**. Абсолютный путь `~/projects/private/dev-conventions` -в закоммиченном файле не годится — репозиторий перестаёт быть -самодостаточным и получает хардкод путей. Пересекается с вопросом 1. - -## 7. Не переизобретено ли это — разобрано - -Проверка перед вложением в тулинг сделана. По слоям: - -- **Язык записи** — совпал со стандартами почти во всём: шкала и правило - «нормативно только заглавное» — BCP 14, обязательное обоснование и - единичность нормы — ISO/IEC/IEEE 29148, категории — ISO/IEC Directives - Part 2, таблицы решений — DMN, стабильные идентификаторы — semgrep/ESLint. - Шесть точечных дельт применены, опора на источники записана в `LANGUAGE.md` - разделом «Опора на стандарты». -- **Оси и сборка** — аналога не нашлось. Ближайшие соседи (каскад `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. Мультиязычность ключевых слов — закрыто по механике - -Вопрос был поставлен как «нужен ли английский набор параллельно русскому». -Ответ оказался другой формы: словарь — **параметр естественного языка -набора**, а не часть языка конвенций. Шкала из пяти ступеней инвариантна, -слова под неё подбираются: для английского готовый словарь даёт BCP 14, для -любого другого языка слова берут из перевода стандарта или переводят сами. - -Отсюда следствия, снимающие исходный вопрос: - -- **параллельных наборов не бывает.** Словарь один на канон: два словаря - дают две формы записи одного требования и удваивают каждую проверку; -- **версия языка при смене словаря не меняется** — версия принадлежит шкале - и правилам формы, а не буквам. Прежняя оценка «английский набор = версия 2» - неверна; -- **`SHALL` не берётся ни в одном словаре**, потому что занято OpenSpec; для - английского это выбор в пользу `MUST` из BCP 14, а не `shall` из ISO; -- отметка о механизации стандартом не даётся ни в одном языке и подбирается - так же, как остальные слова (`МЕХАНИЗИРОВАНО` / `MECHANIZED`). - -Открытым остаётся только прикладное: понадобится ли этому канону английская -версия вообще. Механика для неё уже описана, заводить заранее нечего. - -## 9. Описание языка отдельно от набора конвенций +## 5. Описание языка отдельно от набора конвенций `LANGUAGE.md` и `GUIDE.md` описывают, **как** пишутся конвенции; `conventions/` — **один конкретный** набор. Сейчас они склеены в одном репозитории, и из одного описания нельзя собрать второй набор (рабочий, доменный, чужой). -Что это даёт, если разнести: +Срочности нет: версия языка объявлена в самом `LANGUAGE.md` (ключ +`version:`), и конвенции ссылаются на неё номером, а не путём, — то есть +самодостаточность копии выноса не требует. -- канон объявляет, какой версии языка следует, а тулинг валидирует набор - **против объявленного описания**, а не против зашитых в код правил; -- таблица модальных слов (вопрос 8) живёт в описании и одна на все наборы; -- вопрос 1 (`LANGUAGE.md` не переживает сборку) меняет форму: собранный файл - ссылается не на путь, а на язык с версией. +Что осталось поводом: -Цена — ещё одна сущность и ещё одна синхронизация. Проверить, не выйдет ли -лечение хуже болезни при одном пользователе. +- из одного описания по-прежнему нельзя собрать второй набор; +- тулинг валидирует правила, зашитые в его код, а не объявленную версию + языка. -Срочность снята: версия появилась у `LANGUAGE.md` (ключ `version:` в шапке), -и boilerplate-строка из вопроса 1 уже ссылается на язык номером, а не путём — -не дожидаясь выноса. Отдельный репозиторий остаётся вопросом второго набора -конвенций, а не вопросом самодостаточности копии. +Оба повода включаются, только когда появится второй набор. Цена — ещё одна +сущность и ещё одна синхронизация; при одном наборе лечение выходит хуже +болезни. -Что осталось поводом: из одного описания по-прежнему нельзя собрать второй -набор, и тулинг валидирует правила, зашитые в код, а не объявленную версию -языка. Оба повода включаются, только когда появится второй набор. - -## 10. Тулинг на Go, живущий независимо +## 6. Тулинг на Go, живущий независимо Сейчас `conv` — питоновский скрипт внутри канона, то есть тулинг и данные в одном репозитории и правятся одним движением. Мысль: вынести в отдельный @@ -211,28 +114,21 @@ Go-бинарь со своим релизным циклом, ставить ч Что за этим стоит помимо вкуса: независимый бинарь физически не даёт править инструмент «заодно» с правкой конвенции, работает против **любого** канона и -любого потребителя — что прямо требуется вопросом 9, — и снимает питон из +любого потребителя — что прямо требуется вопросом 5, — и снимает питон из зависимостей репозиториев-потребителей. -Связано с вопросом 2: если тулинг всё равно переписывается, разделение -«целостность канона / установка в проект» дешевле заложить сразу, чем -отпиливать потом. +Порядок обратный ожидаемому: пока вопрос 5 не сделан, инструмент всё равно +работает против одного конкретного канона, и независимый релизный цикл ему +нечего обслуживать. Сначала 5, потом 6. Разделение из вопроса 1 при этом +дешевле заложить сразу, чем отпиливать потом. -Порядок при этом обратный написанному: пока вопрос 9 не сделан, инструмент -всё равно работает против одного конкретного канона, и независимый релизный -цикл ему нечего обслуживать. Сначала 9, потом 10. - -## 11. Ссылки на родительский слой своей темы +## 7. META-20 и родительский слой своей темы Из `lang/` и `stack/` ссылаться на идентификаторы своего же арх-слоя безопасно: при сборке они оказываются секциями одного файла, и ссылка -никуда не ведёт — правило рядом. Ограничение META-20 писалось именно про -**чужую тему**, так что формально это уже разрешено. - -Формулировка проверки исправлена: в `LANGUAGE.md` теперь «префикс **чужой -темы** не встречается в абзаце с модальностью», и там же сказано, что -префикс своего базового слоя допустим. Ложного срабатывания на `GTIM` → -`TIME-3` больше нет. +никуда не ведёт — правило рядом. Ограничение META-20 писалось про **чужую +тему**, так что формально это уже разрешено, и формулировка проверки в +`LANGUAGE.md` под это исправлена. Осталось решить одно: добавлять ли в META-20 явную строку **ДОПУСКАЕТСЯ** про родительский слой. За — правило, которое читают строже, чем оно есть, @@ -240,7 +136,7 @@ Go-бинарь со своим релизным циклом, ставить ч говорит «чужой темы», и второе правило про то же место придётся держать согласованным с первым. -## 12. `WHEN`/`AND` в блоке стыка правил +## 8. `WHEN`/`AND` в блоке стыка правил Блок для стыка двух правил записан английскими словами: @@ -266,7 +162,7 @@ OpenSpec. `WHEN` и `AND` — из того же набора и по той ж подпадают ли `WHEN`/`AND` под проверку «заглавные модальные слова не встречаются вне правил»: сейчас формально нет, потому что в словаре их нет. -## 13. Критерий «названного вреда» никого не обязывает +## 9. Критерий «названного вреда» никого не обязывает `LANGUAGE.md` говорит, что ДОЛЖЕН требует двух условий сразу: нарушение причиняет названный вред (критерий BCP 14) и норма проверяема машиной @@ -280,7 +176,7 @@ OpenSpec. `WHEN` и `AND` — из того же набора и по той ж META-6 её защищает. Против: критерий «вред назван» проверяется чтением, а не машиной, — то есть по META-6 сам он может быть только СЛЕДУЕТ. -## 14. Одиннадцать таблиц не прочитаны на взаимоисключительность +## 10. Одиннадцать таблиц не прочитаны на взаимоисключительность `LANGUAGE.md` объявил, что строки таблицы решений взаимоисключающи по умолчанию, а иной порядок объявляется явно. Объявление не делает таблицы @@ -295,7 +191,7 @@ META-6 её защищает. Против: критерий «вред назв Работа читательская, машине не даётся; в список проверок она уже записана в разделе «Чтением, потому что машине не даётся». -## 15. Возможность, записанная модальным словом +## 11. Возможность, записанная модальным словом Четвёртая категория ISO — возможность и осуществимость — ключевого слова не имеет: такие утверждения пишутся обычной прозой. Значит канон надо просмотреть @@ -306,10 +202,8 @@ META-6 её защищает. Против: критерий «вред назв Смотреть в первую очередь абзацы «Почему»: там факты и стоят, там же соблазн усилить их модальностью выше всего. -## Из вчерашнего, не закрыто +## Мелкое, не закрыто -- Вынос арх-ядра из `errors` и `logging`: закроет две хрупкие ссылки из - `web-ui` (стек) в go-слой — единственные ссылки стек → язык в каноне. - `conv check` должен уметь отличать ссылку на удалённое правило от упоминания дыры: сейчас `META-16` в прозе «Оформления» даёт ложное срабатывание.