diff --git a/TODO.md b/TODO.md index ab08a39..a1de3a0 100644 --- a/TODO.md +++ b/TODO.md @@ -4,72 +4,196 @@ решения. Закрытый вопрос отсюда удаляется — принятое решение живёт в `README.md`, `GUIDE.md` или `LANGUAGE.md`, а не в этом файле. -## 1. Тулинг: две разные задачи в одном `conv` +Две секции: сначала язык и подход, потом канон с тулингом. Пункты 1–9 +пришли из внешнего ревью описания языка и проверены по файлам на месте. -Сейчас в `conv` смешаны две категории работы, и они расходятся по всему — -по частоте запуска, по тому, кто запускает, и по тому, что считается -провалом. +# Язык и подход -**Целостность канона.** Префиксы уникальны и не переиспользованы, шапка -совпадает с реестром, номера без дыр вниз, у каждого правила модальность и -«Почему», ссылки разрешаются, префикс чужой темы не лезет в норму (META-20), -путей канона в тексте нет (META-21), строка о версии языка на месте. -Запускается в каноне, при каждой правке, провал — это ошибка. Логика уже -написана и много раз прогнана руками, но живёт в скретчпаде, а не в -репозитории. +## 1. Два определения второго условия ДОЛЖЕН, и META-6 не соблюдается -**Установка в проект.** Манифест `.conventions.toml`, сборка файла темы из -слоёв (`arch` → язык → стек), сохранение при пересборке всего, что ниже -маркера, предупреждение о висячих ссылках на неподписанные темы. Запускается -в репозитории-потребителе, изредка, провал — это чаще «посмотри глазами», -чем «ошибка». Отчёта «канон ушёл вперёд» здесь нет: его делает `git diff` -после пересборки. +Противоречие двойное, и это самое серьёзное из найденного. -Что обсудить: +**Расхождение формулировок.** `LANGUAGE.md` требует, чтобы норма была +«проверяема машиной» — то есть проверяема в принципе. META-6 требует, чтобы +она «получала машинную проверку» — то есть фактически. Ни одной проверки не +реализовано, поэтому по первому чтению канон в порядке, по второму — весь в +нарушении. Автору нового правила нечем ответить на вопрос «можно ли ДОЛЖЕН +до того, как написан линтер, и как долго». -- Разделять ли на два исполняемых файла, или хватит подкоманд с честной - границей внутри. -- Валидацию канона стоит ли отдать агенту скиллом вместо (или вдобавок к) - скрипту: часть проверок формулируется как «прочитай и скажи, самодостаточна - ли норма» — механически это не берётся, а агентом берётся. -- Куда в этой раскладке ложится запаркованное предупреждение о висячих - ссылках: это установка, а не целостность, но список подписок ему нужен из - манифеста. +**Следствие META-6 массово не соблюдается.** «Правило, непроверяемое машиной +в принципе, — СЛЕДУЕТ по построению», а ДОЛЖЕН стоит у META-1 («ровно один +повторяющийся выбор» — суждение), META-5 («неверно по существу» — суждение), +META-13, META-15, SLOG-8 («уровень выбирается по адресату»), CONF-9 +(«комментарий, из которого ясно»). META-25 при этом демонстративно понижает +**себя** до СЛЕДУЕТ по этой же логике: критерий известен и применяется +выборочно. -Перед тем как переписывать, стоит посмотреть на два готовых прототипа: -дистрибуцию пакетов Vale (`.vale.ini` → `vale sync` → `styles/`) как образец -манифеста и `vendir.yml` — как пример того, где проходит граница между «чего -хочу» и «что получил». +Развилка: либо следствие META-6 слишком сильное и его надо ослабить явно — +например, различив «проверяемо машиной» и «проверяемо воспроизводимо, в том +числе чтением», — либо половина ДОЛЖЕН канона стоит не на своей ступени. +Пока непонятно, что из двух, невозможно ни писать новые правила, ни +реализовать проверку META-6: она либо промолчит всегда, либо покраснеет на +всём каноне, и её отключат — ровно сценарий из обоснования META-12. -## 2. Пары слоёв и темы без базы +## 2. Граница правила не определена -Отложено сознательно, но список стоит держать перед глазами: +Форма объявляет четыре части, но почти каждое крупное правило несёт абзацы +**после** блока ПОЧЕМУ: KEYS-5, SLOG-25, MIGR-11, GERR-26. Язык не говорит, +чем эти абзацы являются — частью правила, продолжением обоснования или +вводной прозой, где заглавные модальные слова запрещены. -- `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. -- Вынос арх-ядра из `errors` и `logging` закроет две хрупкие ссылки из - `web-ui` (стек) в go-слой — единственные ссылки стек → язык в каноне. +В хвостах прячутся настоящие нормы без модальности и без адреса: у SLOG-25 — +«логируется `ERROR` с признаком непокрытой», у GERR-26 — «Продолжать, не +исключив упавший элемент, нельзя». Это ровно тот неадресуемый текст, против +которого язык построен: сослаться нельзя, отступление записать нельзя. -## 3. Подключение к репозиториям +Побочно это блокирует главную машинную проверку. «Заглавные модальные слова +не встречаются вне правил» нереализуема, пока не сказано, где правило +кончается: парсер «от `###` до следующего заголовка» включит хвосты, парсер +«две метки и всё» объявит хвосты прозой и покраснеет на законных пояснениях. -Ничего ещё не подключено. Кандидаты — jellybit и pet-project-server. -Понадобится: заполнить локальную часть копий тем, что сейчас в этих -репозиториях записано по факту; обёртка в раннере (`inv conventions` / -`task conventions`, единый интерфейс команд у трёх ansible-репозиториев); -строка в `AGENTS.md` каждого потребителя про то, что файлы в -`docs/conventions/` — копии. +Решить надо две вещи: где кончается правило и что делать с нормами, которые +уже сидят в хвостах. -## 4. Описание языка отдельно от набора конвенций +## 3. Примеры в LANGUAGE.md сидят на живых идентификаторах + +Учебные примеры используют настоящие префиксы канона с номерами, которые в +каноне означают другое: + +| В примере `LANGUAGE.md` | В каноне на самом деле | +|---|---| +| `MIGR-4` проверяет `AUTOINCREMENT` в новых миграциях | MIGR-4 — «В деплое схема движется только вперёд»; про AUTOINCREMENT — MIGR-12 | +| «MIGR-6. Дефолтов времени в схеме БД нет» | MIGR-6 — «ER-схема обновляется в том же изменении»; дефолты — MIGR-9 | +| «KEYS-5. Разбор внешнего идентификатора на границе» | KEYS-5 — «Внешний идентификатор разбирается до обращения к базе», с другим текстом нормы | + +Язык держится на том, что идентификатор адресует ровно одно утверждение, и +документ, определяющий язык, это нарушает. Ни одна проверка не поймает — +идентификаторы существуют. Дрейф вдобавок гарантирован: канон +перенумеровывался, примеры не двигались. + +Лечится дёшево: примеры берут префиксы на `X`, зарезервированные как раз под +то, что каноном не занято. + +## 4. «Тема» — несущий идентификатор без определения и реестра + +META-21 велит ссылаться на соседнюю конвенцию именем темы, манифест +подписывается `topics = ["time", …]`, сборка собирает файл темы из слоёв — +но нигде не сказано, что такое имя темы (имя файла без расширения? +отдельный атрибут в шапке?) и где список тем существует. + +У префиксов есть реестр `prefixes.toml`, запрет переименования и запрет +переиспользования. У тем нет ничего: ссылка `KEYS-5` валидируется, ссылка +«конвенция `logging`» — нет, и в списке проверок её тоже нет. Переименование +файла темы тихо осиротит все текстовые ссылки во всех копиях. + +Вопрос уже не гипотетический: пара `arch/db-identifiers.md` против +`lang/go/db-schema.md` (см. вопрос 13) показывает, что имена слоёв одной +темы могут не совпадать. Смежно: `extends: arch/time.md` у SLOG ломает +гарантию META-24 («базовый слой отсутствовать не может») — она верна только +для базы своей темы, а машинной проверке негде узнать тему, кроме имени +файла. + +## 5. GUIDE выведен из-под проверок ложным основанием + +`LANGUAGE.md` исключает обвязку из проверок формулировкой «она ключевые слова +цитирует, а не употребляет». Для `GUIDE.md` это неверно: META-правила +употребляют ДОЛЖЕН нормативно, а префикс META зарегистрирован в `[live]`, где +прямо сказано, что правила записаны тем же языком. + +Три следствия. META-правила не попадают ни под одну проверку формы. В +`GUIDE.md` нет строки о версии языка, то есть у META-правил формально нет +ключа к толкованию. И нарушение уже есть: раздел «Оформление» содержит +заглавное СЛЕДУЕТ во вводной прозе — в файле конвенции это было бы +нарушением, а исключение обвязки его прячет. + +Честнее развести: `GUIDE.md` язык **употребляет** и проверяется как +конвенция, `LANGUAGE.md` и `README.md` — цитируют. + +## 6. МЕХАНИЗИРОВАНО не переживает нового подписчика + +META-8 запрещает удалять норму, пока механизирована не у всех, и защищает +тем самым потребителей, существующих **на момент удаления**. Будущих не +защищает никто. + +Сценарий: норма удалена, потому что у всех трёх тогдашних потребителей был +линтер. Через год подключается четвёртый репозиторий, подписывается на тему — +и получает правило без формулировки и без проверки: ни текста, ни линтера, +восстановление только через git-историю канона. + +Смежное: «общий конфиг линтера или общая роль» из META-9 — сущность, которой +в модели распространения (манифест, темы, слои) не существует, и непонятно, +как она доезжает до потребителя. И отдельно: запись «проверяется общим +правилом линтера» — это утверждение о состоянии инфраструктуры потребителей +в тексте канона, то есть ровно то, что запрещает META-4. Либо это законное +исключение, и тогда его надо назвать, либо конфликт. + +## 7. Семантика ключевых слов в копию не едет + +Строка о версии языка перечисляет слова, но не их значения, а всё +нетривиальное в шкале живёт только в `LANGUAGE.md`, который в репозиторий не +едет: что ДОПУСКАЕТСЯ запрещает возражать на ревью, что отступление от +ДОЛЖЕН требует записи, что отступление от СЛЕДУЕТ требует причины. + +Аналогия с BCP 14 ломается именно там, где призвана работать: RFC 2119 +общедоступен и общеизвестен, «язык конвенций версии 1» — нет. Агент в +репозитории-потребителе прочитает ДОПУСКАЕТСЯ как бытовое «можно» и примет +возражение на ревью — ровно та потеря, ради которой слово вводилось. + +Для одного автора терпимо, для агентов — нет. Варианты: возить рядом с +копиями короткую выжимку семантики; расширить строку о версии до +двух-трёх предложений; или признать ограничение и записать его явно. + +## 8. Две «механические» проверки без источника данных + +В списке «разбором текста» стоят два пункта, которые без дополнительного +реестра нерешаемы: + +- **«номера не имеют пропусков вниз»** — дыры в нумерации нормальны по + построению, и статическая проверка не отличит дыру от удалённого правила + от опечатки в номере; +- **«ссылки указывают на правила, которые ещё существуют»** — упоминание + снятого номера в прозе выглядит как висячая ссылка. + +`GUIDE.md` завёл для себя раздел «Освободившиеся номера», но язык не требует +такой таблицы от конвенций, а `prefixes.toml` хранит только префиксы. Пока +реестр снятых номеров не объявлен частью языка, оба пункта принадлежат +списку «чтением». + +## 9. Натяжки в опоре на стандарты + +Три места, где источнику приписано чуть больше, чем в нём есть: + +- **DMN и полнота таблицы.** Политика совпадения — действительно именованное + свойство DMN. Полноту стандарт не требует: индикатор полноты был в DMN 1.0 + и убран в последующих версиях, её проверяют валидаторы инструментов. +- **29148 и обоснование.** Rationale там — рекомендуемый атрибут требования, + а не обязательный «наравне с самим требованием». Обязательный костяк + стандарта — характеристики well-formed requirement, откуда честно взяты + единичность и проверяемость. +- **EARS.** Вывод «выигрыш дала сама обязательность шаблона, а не его + конкретный вид» — экстраполяция, поданная как взятое из источника. Вывод + от этого не становится неверным, но графа «что взято» описывает не + содержимое EARS. + +Остальное в таблице проверку выдержало, включая вторую половину `MAY` из +BCP 14 и списки эквивалентных словесных форм ISO Directives. + +## 10. Одиннадцать таблиц не прочитаны на взаимоисключительность + +`LANGUAGE.md` объявил, что строки таблицы решений взаимоисключающи по +умолчанию, а иной порядок объявляется явно. Объявление не делает таблицы +такими: нумерованные строки есть в одиннадцати файлах канона, и ни одна +таблица под новое требование не прочитана. + +Конкретный подозреваемый — SLOG-11: «по реальному действию или изменению» +против «повторяющаяся служебная, по таймеру или поллингу». Периодическая +операция, которая всё-таки меняет данные, подходит под обе строки, и уровень +из таблицы не выводится однозначно. + +Работа читательская, машине не даётся; в список проверок она уже записана в +разделе «Чтением, потому что машине не даётся». + +## 11. Описание языка отдельно от набора конвенций `LANGUAGE.md` и `GUIDE.md` описывают, **как** пишутся конвенции; `conventions/` — **один конкретный** набор. Сейчас они склеены в одном @@ -90,7 +214,76 @@ сущность и ещё одна синхронизация; при одном наборе лечение выходит хуже болезни. -## 5. Тулинг на Go, живущий независимо +# Канон, тулинг, подключение + +## 12. Тулинг: две разные задачи в одном `conv` + +Сейчас в `conv` смешаны две категории работы, и они расходятся по всему — +по частоте запуска, по тому, кто запускает, и по тому, что считается +провалом. + +**Целостность канона.** Префиксы уникальны и не переиспользованы, шапка +совпадает с реестром, у каждого правила модальность и блок ПОЧЕМУ, ссылки +разрешаются, префикс чужой темы не лезет в норму (META-20), путей канона в +тексте нет (META-21), строка о версии языка на месте. Запускается в каноне, +при каждой правке, провал — это ошибка. Логика уже написана и много раз +прогнана руками, но живёт в скретчпаде, а не в репозитории. + +**Установка в проект.** Манифест `.conventions.toml`, сборка файла темы из +слоёв (`arch` → язык → стек), сохранение при пересборке всего, что ниже +маркера, предупреждение о висячих ссылках на неподписанные темы. Запускается +в репозитории-потребителе, изредка, провал — это чаще «посмотри глазами», +чем «ошибка». Отчёта «канон ушёл вперёд» здесь нет: его делает `git diff` +после пересборки. + +Что обсудить: + +- Разделять ли на два исполняемых файла, или хватит подкоманд с честной + границей внутри. +- Валидацию канона стоит ли отдать агенту скиллом вместо (или вдобавок к) + скрипту: часть проверок формулируется как «прочитай и скажи, самодостаточна + ли норма» — механически это не берётся, а агентом берётся. +- Куда в этой раскладке ложится запаркованное предупреждение о висячих + ссылках: это установка, а не целостность, но список подписок ему нужен из + манифеста. + +Часть проверок из этого списка сейчас нереализуема по причинам из вопросов 2 +и 8, так что порядок такой: сначала язык, потом чекер. + +Перед тем как переписывать, стоит посмотреть на два готовых прототипа: +дистрибуцию пакетов Vale (`.vale.ini` → `vale sync` → `styles/`) как образец +манифеста и `vendir.yml` — как пример того, где проходит граница между «чего +хочу» и «что получил». + +## 13. Пары слоёв и темы без базы + +Отложено сознательно, но список стоит держать перед глазами: + +- `SLOG` объявляет `extends: arch/time.md` — расширение **чужой** темы. + Сборщик темы `logging` на это наткнётся: базового слоя с темой `logging` + нет, а `arch/time.md` он тянуть не должен. Чинится переводом в обычную + ссылку «связано». Вдобавок это ломает гарантию META-24 — см. вопрос 4. +- Темы без арх-слоя: `db-schema`, `errors`, `web-ui`. Собираются в файл с + одной секцией — само по себе не ломается, но это и есть тот невыделенный + арх-слой из известного долга. +- Имена тем в паре не совпадают: `arch/db-identifiers.md` против + `lang/go/db-schema.md`. При сборке по имени темы это две разные темы — + проверить, что так и задумано. +- В `lang/go/db-schema.md` сидит целый пласт `stack/sqlite/` (типы колонок), + тоже из известного долга README. +- Вынос арх-ядра из `errors` и `logging` закроет две хрупкие ссылки из + `web-ui` (стек) в go-слой — единственные ссылки стек → язык в каноне. + +## 14. Подключение к репозиториям + +Ничего ещё не подключено. Кандидаты — jellybit и pet-project-server. +Понадобится: заполнить локальную часть копий тем, что сейчас в этих +репозиториях записано по факту; обёртка в раннере (`inv conventions` / +`task conventions`, единый интерфейс команд у трёх ansible-репозиториев); +строка в `AGENTS.md` каждого потребителя про то, что файлы в +`docs/conventions/` — копии. + +## 15. Тулинг на Go, живущий независимо Сейчас `conv` — питоновский скрипт внутри канона, то есть тулинг и данные в одном репозитории и правятся одним движением. Мысль: вынести в отдельный @@ -99,32 +292,10 @@ Go-бинарь со своим релизным циклом, ставить ч Что за этим стоит помимо вкуса: независимый бинарь физически не даёт править инструмент «заодно» с правкой конвенции, работает против **любого** канона и -любого потребителя — что прямо требуется вопросом 4, — и снимает питон из +любого потребителя — что прямо требуется вопросом 11, — и снимает питон из зависимостей репозиториев-потребителей. -Порядок обратный ожидаемому: пока вопрос 4 не сделан, инструмент всё равно +Порядок обратный ожидаемому: пока вопрос 11 не сделан, инструмент всё равно работает против одного конкретного канона, и независимый релизный цикл ему -нечего обслуживать. Сначала 4, потом 5. Разделение из вопроса 1 при этом +нечего обслуживать. Сначала 11, потом 15. Разделение из вопроса 12 при этом дешевле заложить сразу, чем отпиливать потом. - -## 6. Одиннадцать таблиц не прочитаны на взаимоисключительность - -`LANGUAGE.md` объявил, что строки таблицы решений взаимоисключающи по -умолчанию, а иной порядок объявляется явно. Объявление не делает таблицы -такими: нумерованные строки есть в одиннадцати файлах канона, и ни одна -таблица под новое требование не прочитана. - -Конкретный подозреваемый — SLOG-11: «по реальному действию или изменению» -против «повторяющаяся служебная, по таймеру или поллингу». Периодическая -операция, которая всё-таки меняет данные, подходит под обе строки, и уровень -из таблицы не выводится однозначно. - -Работа читательская, машине не даётся; в список проверок она уже записана в -разделе «Чтением, потому что машине не даётся». - -## Мелкое, не закрыто - -- `conv check` и отличие ссылки на удалённое правило от упоминания дыры: - теперь освободившиеся номера перечислены в `GUIDE.md`, раздел - «Освободившиеся номера», — проверке остаётся читать этот список, а не - угадывать. Реализации по-прежнему нет.