заведены README.md и CLAUDE.md
- README описывает термины, команды, два режима и вывод проверки; модель не пересказывается — истина остаётся в репозитории набора - CLAUDE.md фиксирует распределение языков, инварианты кода и решения, которые уже приняты и не пересматриваются без просьбы - отдельным разделом перечислены известные остатки, чтобы их не искали заново
This commit is contained in:
@@ -0,0 +1,141 @@
|
||||
# CLAUDE.md
|
||||
|
||||
This file provides guidance to Claude Code (claude.ai/code) when working with
|
||||
code in this repository.
|
||||
|
||||
## Язык
|
||||
|
||||
Общение по репозиторию — на русском. Внутри репозитория язык распределён так, и
|
||||
это распределение проверяется глазами при ревью:
|
||||
|
||||
- **английский** — комментарии в коде, имена, тексты ошибок, вывод CLI,
|
||||
сообщения и имена тестов;
|
||||
- **русский** — `README.md`, `CLAUDE.md`, сообщения коммитов;
|
||||
- **язык проверяемого набора** — содержимое тестовых фикстур и литералы
|
||||
словарей в `internal/lang`. Это данные под проверкой, а не текст инструмента,
|
||||
и переводить их нельзя: сломается то, что они проверяют.
|
||||
|
||||
Слова словаря законно попадают внутрь английских сообщений, потому что
|
||||
подставляются из набора: `rule GTIM-1 has no ПОЧЕМУ block`. Инструмент говорит
|
||||
по-английски и цитирует то, чем записан проверяемый набор.
|
||||
|
||||
## Что это
|
||||
|
||||
CLI для управления конвенциями. Модель здесь не описывается: она живёт в
|
||||
репозитории набора `dev-conventions` — `README.md` (набор и копии),
|
||||
`LANGUAGE.md` (форма правила и список проверок), `GUIDE.md` (ведение набора,
|
||||
префикс META), `TOOL.md` (решения об инструменте). При расхождении истина там,
|
||||
а не в коде и не здесь.
|
||||
|
||||
Пользовательская сторона — в `README.md`. Ниже — то, что нужно знать, правя код.
|
||||
|
||||
## Раскладка
|
||||
|
||||
```
|
||||
internal/lang словарь: реестр «версия языка × естественный язык»
|
||||
internal/manifest suite.toml — чтение и текстовая правка
|
||||
internal/doc разбор документа: шапка, области правил, блоки
|
||||
internal/suite сборка набора в память, отбор слоёв под компонент
|
||||
internal/check проверки: manifest, form, spread, links
|
||||
internal/cli команды, диалог, два режима
|
||||
```
|
||||
|
||||
Зависимость одна — `BurntSushi/toml`. Вторую не заводить: так решено в
|
||||
`TOOL.md`, и `Undecoded()` этого парсера бесплатно ловит опечатки в ключах
|
||||
манифеста.
|
||||
|
||||
## Инварианты кода
|
||||
|
||||
- **В коде нет ни одной темы, ни одного префикса, ни одного пути набора.** Всё
|
||||
это приходит из манифеста. Список проверяемых файлов берётся из
|
||||
`[prefixes.live]`, а не из дерева директорий: это и есть граница «язык
|
||||
употребляет» против «язык цитирует».
|
||||
- **Словарь зашит в бинарь** по паре «версия языка × естественный язык», а не
|
||||
объявляется в манифесте. Когда спецификация языка уедет в отдельный
|
||||
репозиторий и там появятся спеки словарей, источником станут они —
|
||||
подменяется `registry`, тип `Vocabulary` и проверки поверх него не трогаются.
|
||||
- **Что инструмент пишет, инструмент принимает.** Набор, созданный `suite init`,
|
||||
`add` и `rule`, обязан проходить `suite check` без правок. Это проверяет
|
||||
`checkClean` в `internal/cli`; ломать инвариант нельзя.
|
||||
- **Манифест правится текстом, а не энкодером.** В `suite.toml` комментариев
|
||||
больше, чем данных. `manifest.AddEntry` вставляет запись, подстраиваясь под
|
||||
порядок таблицы: отсортированную по алфавиту держит отсортированной,
|
||||
упорядоченную вручную дополняет в конец. Комментарий, отделённый пустой
|
||||
строкой, принадлежит таблице **ниже** себя.
|
||||
- **Разбор опирается на разметку, а не на суждение.** Область правила — от
|
||||
заголовка до следующего заголовка любого уровня. Метка открывает блок только
|
||||
первой в абзаце и полужирным. Огороженные блоки кода исключаются везде;
|
||||
инлайн-код вырезается там, где ищутся ссылки, и не вырезается там, где ищутся
|
||||
пути канона.
|
||||
|
||||
## Решения, которые уже приняты
|
||||
|
||||
Их не пересматривают без явной просьбы — каждое обсуждалось и стоило времени.
|
||||
|
||||
- **Порядок правил в файле — по читаемости, а не по номерам.** Номер стабилен и
|
||||
не переиспользуется, поэтому «порядок по номерам» означал бы «порядок по
|
||||
времени написания» навсегда. Проверяется сплошность нумерации, а не
|
||||
возрастание.
|
||||
- **Ссылка на чужую тему вне нормы разрешена** (META-20): обоснование,
|
||||
потерявшее адресата, деградирует честно. Внутри своей темы ссылаться можно
|
||||
только в базовый слой, и это проверяется во всём документе, а не только в
|
||||
норме: гарантированно присутствует в копии один базовый слой.
|
||||
- **Заголовок правила — объявление, а не ссылка.** При разборе ссылок строки
|
||||
заголовков пропускаются.
|
||||
- **Лок-файла, `push`, отчёта о расхождении и перенумерации не будет.** Модель
|
||||
отвергает каждое явно.
|
||||
|
||||
## Проверки
|
||||
|
||||
Семейства повторяют деление из `LANGUAGE.md`, раздел «Что стоит проверять
|
||||
машиной», и это деление держится в коде: `form` — в любом файле, который язык
|
||||
употребляет; `spread` — только в конвенциях, потому что эти проверки о том, что
|
||||
документ уезжает к потребителю. Третья часть списка (взаимоисключительность
|
||||
строк таблицы, покрытие области действия, отвечает ли обоснование на «что
|
||||
сломается») разбором текста не даётся и в коде отсутствует намеренно.
|
||||
|
||||
Новая проверка заводится вместе с двумя тестами: что она срабатывает и что она
|
||||
**молчит** там, где не должна. Второй важнее: проверка, краснеющая на исправном
|
||||
файле, выключается целиком. Ложные срабатывания собраны в
|
||||
`TestNoFalsePositives`.
|
||||
|
||||
Перед тем как заводить проверку, стоит прогнать её замысел по живому канону
|
||||
(`dev-conventions`): если она покраснеет на исправном наборе, замысел неверен.
|
||||
|
||||
## Известные остатки
|
||||
|
||||
- Набор без документа самоуправления, в котором конвенция потеряла `topic`,
|
||||
проскочит: признаков «этот документ один» и «у него нет ключей слоя» не
|
||||
хватает. Закрывается маркером в манифесте — правка формата, не сделана.
|
||||
- Проверка пути канона считает путём любой токен `*.md`, который резолвится в
|
||||
файл набора; упоминание `README.md` в конвенции она пометит ошибочно. На
|
||||
текущем каноне не срабатывает.
|
||||
- Машиночитаемого вывода находок (`--json`) нет.
|
||||
|
||||
## Тесты
|
||||
|
||||
```
|
||||
go test ./... всё
|
||||
go test ./internal/check/ -v проверки, по одному подтесту на случай
|
||||
gofmt -l . && go vet ./... перед коммитом
|
||||
```
|
||||
|
||||
Тесты фикстурные: набор пишется во временную директорию и прогоняется целиком.
|
||||
`internal/cli` проверяет обе моды, включая диалог — интерактивный режим иначе не
|
||||
покрыть, из шелла он требует терминала.
|
||||
|
||||
## Коммиты
|
||||
|
||||
Русский, строчная буква, без точки в конце, прошедшее время или страдательный
|
||||
залог. Изредка область через двоеточие (`suite check:`). Тело — маркированный
|
||||
список на 2–4 пункта с переносом по ~76 колонок, объясняет почему. Conventional
|
||||
Commits и `Co-Authored-By` не используются.
|
||||
|
||||
## Состояние
|
||||
|
||||
Наборная сторона закончена: `init`, `add`, `rule`, `retire`, `list`, `check`.
|
||||
Проектные команды (`add`, `pull`, `list`, `check` без `suite`) не начаты; отбор
|
||||
слоёв под компонент для них уже написан — `suite.Assemble`, — и переписывать его
|
||||
в сборщике не нужно.
|
||||
|
||||
Линтеров и CI нет.
|
||||
@@ -0,0 +1,147 @@
|
||||
# convy
|
||||
|
||||
CLI для управления конвенциями разработки: ведёт набор конвенций и собирает
|
||||
копии в проектах.
|
||||
|
||||
Модель, которую инструмент реализует, описана не здесь, а в репозитории набора
|
||||
(`dev-conventions`): `README.md` — устройство набора и копий, `LANGUAGE.md` —
|
||||
форма правила, `GUIDE.md` — правила ведения набора, `TOOL.md` — решения об этом
|
||||
инструменте. При расхождении истина там.
|
||||
|
||||
## Термины
|
||||
|
||||
| Уровень | Что это |
|
||||
|---|---|
|
||||
| набор | репозиторий с конвенциями, манифестом `suite.toml` и обвязкой |
|
||||
| тема | набор правил об одном фокусе разработки; единица подписки |
|
||||
| слой | один файл темы: базовый, языковой или стековый |
|
||||
| компонент | адресат сборки в проекте: один язык, один стек, один вид приложения |
|
||||
| префикс | четыре заглавные латинские буквы, адрес правила: `GTIM-3` |
|
||||
|
||||
Тему и ось слоя объявляет шапка файла, а не путь: `topic:`, `lang:`, `stack:`.
|
||||
Слой без ключей оси — базовый, он попадает в копию всегда.
|
||||
|
||||
## Установка
|
||||
|
||||
Внешняя зависимость одна (`BurntSushi/toml`), сборка обычная:
|
||||
|
||||
```
|
||||
go install git.vakhrushev.me/av/convy@latest
|
||||
```
|
||||
|
||||
или из клона репозитория:
|
||||
|
||||
```
|
||||
go build -o convy .
|
||||
```
|
||||
|
||||
Способ раздачи готовых бинарей пока не выбран — вопрос открыт в `TOOL.md`.
|
||||
|
||||
## Команды
|
||||
|
||||
```
|
||||
В наборе:
|
||||
convy suite init завести набор: директория и манифест
|
||||
convy suite add завести конвенцию: файл, тема и префикс
|
||||
convy suite rule дописать правило: следующий номер, блоки по порядку
|
||||
convy suite retire снять правило, конвенцию или тему — без переиспользования
|
||||
convy suite list что в наборе и что возьмёт компонент
|
||||
convy suite check целостность набора: префиксы, темы, оси, ссылки, форма
|
||||
|
||||
В проекте (пока не реализовано):
|
||||
convy add <тема> подписаться и собрать
|
||||
convy pull пересобрать подписанное
|
||||
convy list что подключено и что доступно
|
||||
convy check проверить форму того, что здесь
|
||||
```
|
||||
|
||||
Контекст определяется по манифесту рядом: `suite.toml` — набор,
|
||||
`.conventions.toml` — проект. Наугад не делается ничего: команда не того уровня
|
||||
отказывает и подсказывает нужную.
|
||||
|
||||
## Два режима
|
||||
|
||||
Команды, которые что-то меняют, работают в двух режимах, и режим читается по
|
||||
командной строке.
|
||||
|
||||
**Без аргументов — диалог.** Каждое поле спрашивается с подсказкой о том, что
|
||||
туда кладут и почему. Это для человека.
|
||||
|
||||
```
|
||||
$ convy suite add
|
||||
|
||||
The focus the rules are about: time, config, db-schema. A topic is the unit of
|
||||
subscription — a consumer takes it whole. The name never changes and is never reused.
|
||||
Topic: logging
|
||||
|
||||
It goes into the manifest and builds the table of conventions in a consumer's README.
|
||||
One line about the topic: логирование: уровни, структура записи
|
||||
...
|
||||
```
|
||||
|
||||
**С флагами — автоматика.** Всё передаётся сразу, вопросов не задаётся, все
|
||||
недостающие поля называются разом. Это для агентов и скриптов.
|
||||
|
||||
```
|
||||
$ convy suite add --topic logging --about "логирование: уровни" \
|
||||
--prefix SLOG --title "Логирование"
|
||||
```
|
||||
|
||||
Без терминала пустой вызов отказывает, а не виснет в ожидании ответа, которого
|
||||
некому дать.
|
||||
|
||||
## Проверка набора
|
||||
|
||||
```
|
||||
$ convy suite check
|
||||
conventions/lang/go/logging.md
|
||||
error:5 extends points at "arch/time.md" with topic "time", while the file
|
||||
carries topic "logging": the layers of one topic declare one name [spread]
|
||||
|
||||
suite: 13 files, 8 topics, language version 1 (ru)
|
||||
errors: 1, warnings: 0
|
||||
```
|
||||
|
||||
Строка находки — `уровень:строка что не так [семейство]`. Семейств четыре:
|
||||
|
||||
- **manifest** — префиксы, темы, объявленные файлы, незарегистрированные файлы;
|
||||
- **form** — форма правила: нумерация, блоки, модальные слова, словарь.
|
||||
Проверяется в любом файле, который язык употребляет;
|
||||
- **spread** — то, что относится к отъезду к потребителю: тема в шапке, ось,
|
||||
`extends`, пути канона, самодостаточность нормы. Только в конвенциях;
|
||||
- **links** — разрешение ссылок вида `PREFIX-N`.
|
||||
|
||||
Третья часть списка проверок языка — взаимоисключительность строк таблицы,
|
||||
покрытие области действия, отвечает ли обоснование на «что сломается» — разбором
|
||||
текста не даётся и остаётся работой читателя.
|
||||
|
||||
Коды возврата: `0` — чисто, `1` — есть ошибки, `2` — команда набрана неверно или
|
||||
не в том контексте.
|
||||
|
||||
## Ступени и словарь
|
||||
|
||||
Слова, которыми записаны модальность и метки, — свойство версии языка и
|
||||
естественного языка набора, а не самого набора. Инструмент знает их сам, и
|
||||
`suite.toml` их не дублирует: достаточно `[language] version` и `lang`.
|
||||
|
||||
Поэтому ступень называется категорией, а не словом:
|
||||
|
||||
```
|
||||
--modality requirement | prohibition | recommendation | not-recommended | permission
|
||||
```
|
||||
|
||||
`prohibition` в русском наборе превращается в `**НЕ ДОЛЖЕН.**`, в английском —
|
||||
в `**MUST NOT.**`. Вызывающему не нужно знать, на каком языке записан набор.
|
||||
|
||||
По той же причине `convy` умеет написать строку о версии языка, и созданный им
|
||||
файл проходит `suite check` без единой правки.
|
||||
|
||||
## Чего инструмент не делает
|
||||
|
||||
- не сливает трёхсторонне и не разрешает конфликты: правка выше маркера
|
||||
локальной части теряется, и это заявленное поведение;
|
||||
- не ведёт лок-файл: копии закоммичены, ответ на «что было в прошлый раз» даёт
|
||||
git;
|
||||
- не хранит список подписчиков: подписка — свойство проекта;
|
||||
- не переносит правки из проекта в набор: операция ручная и редкая;
|
||||
- не перенумеровывает правила: номер — идентификатор, а не позиция.
|
||||
Reference in New Issue
Block a user