#!/usr/bin/env bash # Doku-Drift-Gate: prueft Manifest-Referenzen + STATE-Aktualitaet + Doc-Budget. set -uo pipefail fail=0; man="manifests/requirements.md" # Dormant solange das Template nicht initialisiert ist (scripts/init.sh). if grep -q '' STATE.md 2>/dev/null; then echo "[drift] Template noch nicht initialisiert (scripts/init.sh) — uebersprungen." echo "GATE: PASS"; exit 0 fi echo "[drift] pruefe im Manifest referenzierte Pfade..." # Loop laeuft im Haupt-Shell (Process Substitution), damit fail=1 wirkt. if [ -f "$man" ]; then while read -r p; do # Platzhalter und Nicht-Pfade ueberspringen. case "$p" in *" "*|*…*|_*|*path/to*) continue ;; esac case "$p" in */*|*.py|*.md|*.sh|*.js|*.ts|*.yml|*.yaml|*.json) [ -e "$p" ] || { echo " - fehlende Referenz: $p"; fail=1; } ;; esac done < <(grep -oE '`[^`]+`' "$man" | tr -d '`') fi echo "[drift] STATE.md Stale-Check (Commits seit letzter Aenderung)..." last_state=$(git log -1 --format=%H -- STATE.md 2>/dev/null || true) if [ -n "$last_state" ]; then since=$(git rev-list --count "${last_state}..HEAD" 2>/dev/null || echo 0) [ "${since:-0}" -le 3 ] || { echo " - STATE.md seit $since Commits unveraendert"; fail=1; } fi echo "[drift] Doc-Groessenbudget (Faustregel < 200 Zeilen)..." while read -r f; do case "$f" in examples/*) continue ;; esac # Beispiele duerfen laenger sein n=$(wc -l < "$f" 2>/dev/null || echo 0) [ "$n" -le 200 ] || echo " - Hinweis: $f hat $n Zeilen (> 200, Drift-Risiko)." done < <(git ls-files 2>/dev/null | grep '\.md$' || true) echo "[drift] Code ohne Doc-Aenderung im letzten Commit?" files=$(git show --name-only --pretty= HEAD 2>/dev/null || true) if echo "$files" | grep -qE '\.(py|sh|js|ts)$' && ! echo "$files" | grep -qE '\.md$'; then echo " - Hinweis: Code geaendert, keine Doku angepasst (Drift-Verdacht)." fi [ "$fail" -eq 0 ] && echo "GATE: PASS" || { echo "GATE: FAIL"; exit 1; }