#!/bin/sh # Зонный pre-commit фрагмент docs/. Запускается тем же диспетчером .git/hooks/pre-commit, # что и фрагмент фронта (он перебирает */scripts/githooks/pre-commit). # # Зачем: за одну сессию №15 четыре из десяти рукописных копий производных чисел разошлись с # источником, а голова CURRENT-STATE отставала ТРЕТИЙ раз в истории проекта — у трёх разных # оркестраторов (D39.81, D39.83, D39.112 п.5б). Одна и та же ошибка у независимых сессий на одном # поле — свойство поля, а не сессий, поэтому проверка механическая, а не нормой прозой. # # ⚠ ПРЕДУПРЕЖДАЕТ, НЕ БЛОКИРУЕТ (решение оркестратора №15, 07.08): фрагмент лежит в общем # диспетчере и сработает на коммите ЛЮБОЙ сессии, включая те, которым я не писал промт. Жёсткий # гейт, останавливающий чужой коммит, ставится только словом владельца. Обход, если понадобится: # git commit --no-verify. 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 # Содержимое ПОСЛЕ коммита: для застейдженного файла это индекс, для нетронутого — HEAD. 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 'D1–D39\.[0-9]+' | sed 's/^D1–//') claimed=$(after "$prog" | head -6 | grep -oE 'голова D39\.[0-9]+' | head -1 | sed 's/^голова //') warn=0 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 # Производные числа доков — сверка пере-счётом (docs/scripts/counts.py). Считает по РАБОЧЕМУ # дереву: при частичном стейдже это advisory, а не приговор. if command -v python3 >/dev/null 2>&1 && [ -f docs/scripts/counts.py ]; then out=$(python3 docs/scripts/counts.py --check 2>&1) || { echo "pre-commit ⚠ docs: литералы в доках разошлись с пере-счётом:" >&2 printf '%s\n' "$out" | grep '✗' >&2 warn=1 } fi [ "$warn" -eq 1 ] && echo "pre-commit: это ПРЕДУПРЕЖДЕНИЕ, коммит не остановлен." >&2 exit 0