diff --git a/README.md b/README.md index 6c012cd..6af5df7 100644 --- a/README.md +++ b/README.md @@ -228,6 +228,7 @@ claude plugin uninstall <плагин>@av-dev-skills --scope project /agents/ charter'ы сабагентов scripts/ проверки репозитория: копии, диаграммы, фронтматтеры pyproject.toml линтеры скриптов, только для этого репозитория +lefthook.yml гейт коммита: проверки документов ``` ## Проверка скриптов @@ -315,11 +316,45 @@ uv run python scripts/diagrams.py # 0 рендерятся, 1 нет, 3 нет ``` Рендерит `mmdc` с PATH или `npx --yes @mermaid-js/mermaid-cli`; ни того ни -другого нет — код 3, а не молчаливый успех. Прогон занимает секунды на блок, -поэтому он не в гейте, а в руках того, кто правит диаграмму. +другого нет — код 3, а не молчаливый успех. Прогон занимает секунды на блок — +это самая дорогая из трёх проверок, и в гейте коммита она стоит **под glob по +markdown**: правка одних скриптов проходит мгновенно. Чего проверка **не** ловит — расхождение диаграммы с прозой вокруг неё. Дословного соответствия между текстом и графом нет, сличать нечего, и держится это правилом старшинства, записанным рядом с каждой диаграммой: **в конвейере ревью старший граф** (он и есть алгоритм планировщика, проза его объясняет), **в остальных местах старшая проза** (диаграмма там сводка). + +## Гейт коммита + +Все пять проверок стоят в `pre-commit` через [lefthook](https://lefthook.dev) — +конфиг в [lefthook.yml](lefthook.yml), ставится один раз на клон: + +``` +lefthook install # пишет .git/hooks/pre-commit +lefthook run pre-commit # прогнать руками, не коммитя +``` + +| Проверка | Когда идёт | Сколько | +| --- | --- | --- | +| фронтматтеры | правка `*.md` | миллисекунды | +| копии правил | правка `*.md` | миллисекунды | +| диаграммы | правка `*.md` | ~15 с на весь репозиторий | +| `ruff check .` | правка `*.py` | доли секунды | +| `pyrefly check` | правка `*.py` | доли секунды | + +Glob разводит две половины: коммит, трогающий одни скрипты, не платит за рендер +диаграмм, а коммит в документы не гоняет линтеры. Внутри своей половины +проверяется **весь репозиторий**, а не изменённые файлы: и расхождение копии, и +находка ruff в соседнем файле — это ровно тот случай, когда правка сломала не +себя. + +Два свойства, о которых стоит знать заранее: + +- **судится рабочее дерево, а не индекс.** Скрипты обходят репозиторий целиком + и про `git add` не знают: частичный коммит при грязном дереве проверяется по + тому, что на диске. Это цена того, что проверки — обход, а не фильтр файлов, и + она принята: расхождение копий и битая диаграмма ловятся именно обходом; +- **обход разовый — `LEFTHOOK=0 git commit …`.** Он законен ровно для случая, + когда найденное нечем чинить прямо сейчас; молча пропущенная проверка — нет. diff --git a/lefthook.yml b/lefthook.yml new file mode 100644 index 0000000..07d63f7 --- /dev/null +++ b/lefthook.yml @@ -0,0 +1,48 @@ +# Гейт коммита: всё, что в этом репозитории проверяется машиной. +# +# Документы — то, что читает не человек, а машина, и чья поломка **не видна при +# чтении**: фронтматтер (его разбирает загрузчик скиллов), помеченная копия +# правила (расходится молча) и диаграмма mermaid (текст правдоподобен, рендер +# падает). Скрипты — ruff и pyrefly: они же стерегут ноль внешних зависимостей, +# без которого tasks.py и docs.py перестают работать в чужом проекте. +# Всё остальное (проза, устройство, язык) — предмет ревью, а не хука. +# +# Скрипты читают **рабочее дерево целиком**, а не индекс: частичный коммит при +# грязном дереве судится по тому, что на диске. Это осознанно — они и написаны +# как обход репозитория, а не как фильтр по файлам. +# +# Ставится `lefthook install` (см. README, «Гейт коммита»). Обойти разово — +# `LEFTHOOK=0 git commit …`; обход законен ровно для того случая, когда чинить +# найденное нечем прямо сейчас. + +pre-commit: + parallel: true + jobs: + - name: фронтматтеры + glob: "*.md" + run: python3 scripts/frontmatter.py + + - name: копии правил + glob: "*.md" + run: python3 scripts/copies.py + + # Секунды, а не миллисекунды: рендер идёт настоящим mermaid-cli. Поэтому + # glob — правка одних только скриптов проходит гейт мгновенно. Нет ни + # `mmdc`, ни `npx` — код 3, коммит отказан: «не проверено» здесь не то же + # самое, что «проверено и сошлось». + - name: диаграммы + glob: "*.md" + run: python3 scripts/diagrams.py + + # Скрипты — под своим glob и через uv: версии линтеров прибиты точно, и + # `uv run` берёт именно их, а не то, что оказалось в PATH. Обе проверки + # укладываются в доли секунды на весь репозиторий, поэтому проверяется он + # целиком, а не изменённые файлы: находка в чужом файле здесь означает, что + # правка сломала соседа. + - name: ruff + glob: "*.py" + run: uv run ruff check . + + - name: pyrefly + glob: "*.py" + run: uv run pyrefly check