#!/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 'D1–D39\.[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
