textmachine/docs/scripts/githooks/pre-commit

69 lines
5.8 KiB
Bash
Executable file
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.

#!/bin/sh
# Зонный pre-commit фрагмент docs/. Ставится тем же диспетчером .git/hooks/pre-commit, что и
# фрагмент фронта (диспетчер перебирает */scripts/githooks/pre-commit).
#
# ┌─ ЧТО ЭТО ДЕЛАЕТ И ЧЕГО НЕ ДЕЛАЕТ — читать до того, как ругаться на него ───────────────────┐
# │ ДЕЛАЕТ: при коммите, задевающем D-лог или PROGRESS, сверяет три носителя номера головы и │
# │ производные числа доков (счёт очереди, зон, вес открытых строк регистра платформы). │
# │ НЕ ДЕЛАЕТ: не блокирует коммит НИКОГДА — только печатает предупреждение и выходит 0. │
# │ Не трогает содержимое, не правит файлы, не лезет в сеть, не запускает тесты. │
# │ ЕСЛИ МЕШАЕТ: `git commit --no-verify` обходит всю цепочку; выключить только этот фрагмент — │
# │ `chmod -x docs/scripts/githooks/pre-commit`. Ни то, ни другое ничего не ломает. │
# │ ПОЧЕМУ ВООБЩЕ: голова CURRENT-STATE отставала ТРИЖДЫ у трёх РАЗНЫХ оркестраторов │
# │ (D39.81 · D39.83 · D39.112 п.5б). Одна ошибка у независимых сессий на одном поле — │
# │ свойство поля, а не сессий, поэтому проверка механическая, а не нормой прозой. │
# │ ПОЧЕМУ ПРЕДУПРЕЖДАЕТ, А НЕ БЛОКИРУЕТ: фрагмент общий, он сработает у сессии, которой я не │
# │ писал промт. Останавливать чужой коммит — решение владельца, не моё (оркестратор №15). │
# └────────────────────────────────────────────────────────────────────────────────────────────┘
#
# Ложные тревоги, которых здесь СОЗНАТЕЛЬНО избегают, — это важнее, чем полнота: хук, который
# врёт, учат игнорировать, и тогда он хуже отсутствующего.
# · числа считаются по СОДЕРЖИМОМУ КОММИТА (`--from-index`), а не по рабочему дереву, иначе
# частичный стейдж (своя правка в общем файле) давал бы ругань на то, что в коммит не поедет;
# · голова сверяется ТОЛЬКО когда в коммите есть D-лог, то есть когда идёт ратификация — норма
# требует бампать голову в том же коммите, что аппенд ноты, и вот этот случай и ловится;
# коммит, который правит PROGRESS по другому поводу, про голову не спрашивают.
staged=$(git diff --cached --name-only)
[ -z "$staged" ] && exit 0
dlog='docs/architecture/05-decisions-log.md'
prog='docs/PROGRESS.md'
# Быстрый выход: ни один из двух носителей не в коммите — нам тут нечего делать.
printf '%s\n' "$staged" | grep -qE "^($dlog|$prog)$" || exit 0
warn=0
# 1) Голова. Только при ратификации (D-лог в коммите).
if printf '%s\n' "$staged" | grep -qx "$dlog"; then
after() {
if printf '%s\n' "$staged" | grep -qx "$1"; then git show ":$1" 2>/dev/null; else git show "HEAD:$1" 2>/dev/null; fi
}
note=$(after "$dlog" | grep -oE '^## D39\.[0-9]+' | tail -1 | sed 's/^## //')
banner=$(after "$dlog" | head -1 | grep -oE 'D1D39\.[0-9]+' | sed 's/^D1//')
claimed=$(after "$prog" | head -8 | grep -oE 'голова D39\.[0-9]+' | head -1 | sed 's/^голова //')
if [ -n "$note" ] && [ -n "$claimed" ] && [ "$note" != "$claimed" ]; then
echo "pre-commit ⚠ docs: голова разошлась — последняя нота D-лога $note, CURRENT-STATE говорит $claimed." >&2
echo " Норма: голова бампается в ТОМ ЖЕ коммите, что аппенд ноты (промт оркестратора)." >&2
warn=1
fi
if [ -n "$note" ] && [ -n "$banner" ] && [ "$note" != "$banner" ]; then
echo "pre-commit ⚠ docs: шапка-диапазон D-лога $banner при последней ноте $note." >&2
warn=1
fi
fi
# 2) Производные числа — по содержимому коммита. Ненайденный литерал скрипт тоже считает
# расхождением: проверка, молча перестающая проверять, хуже отсутствующей.
if command -v python3 >/dev/null 2>&1 && [ -f docs/scripts/counts.py ]; then
if ! out=$(python3 docs/scripts/counts.py --check --from-index 2>&1); then
echo "pre-commit ⚠ docs: производные числа разошлись с пере-счётом:" >&2
printf '%s\n' "$out" | grep '✗' >&2
warn=1
fi
fi
[ "$warn" -eq 1 ] && echo "pre-commit: это ПРЕДУПРЕЖДЕНИЕ — коммит не остановлен (обход: --no-verify)." >&2
exit 0