#!/usr/bin/env bash # Reminder + staleness check for docs/GISHEN-MASTER-SPEC.md # Does NOT call LLMs. Safe to run from pre-push or manually. set -euo pipefail ROOT="$(cd "$(dirname "$0")/.." && pwd)" cd "$ROOT" MASTER="docs/GISHEN-MASTER-SPEC.md" ADMIN_SPEC="docs/admin-backend-spec.md" RED=$'\033[1;31m' YEL=$'\033[1;33m' GRN=$'\033[1;32m' BLD=$'\033[1m' RST=$'\033[0m' echo "${BLD}Gishen master spec reminder${RST}" echo " Master: ${MASTER}" echo if [[ ! -f "$MASTER" ]]; then echo "${RED}ERROR:${RST} Missing ${MASTER}" echo " Create/update it before push. See docs/GISHEN-MASTER-SPEC.md Update rule." exit 1 fi echo "${BLD}Pre-push checklist${RST}" echo " [ ] Changelog row if domain contract changed" echo " [ ] Skim Mob / Ecom / B2B (and Dispatch if relevant) when folders exist" echo " [ ] Sources stamp + Last reconciled bumped" echo " [ ] ${ADMIN_SPEC} updated if Admin modules changed" echo mtime_of() { stat -f %m "$1" 2>/dev/null || stat -c %Y "$1" } master_mtime=$(mtime_of "$MASTER") stale=0 newest_src="" newest_ts=$master_mtime consider() { local path="$1" [[ -e "$path" ]] || return 0 local ts ts=$(mtime_of "$path") if (( ts > newest_ts )); then newest_ts=$ts newest_src="$path" fi if (( ts > master_mtime )); then stale=1 fi } consider "$ADMIN_SPEC" consider "package.json" consider "README.md" # Sample recent TypeScript under src (portable; avoid head -z) if [[ -d src ]]; then while IFS= read -r f; do [[ -n "$f" ]] || continue consider "$f" done < <(find src -type f \( -name '*.ts' -o -name '*.tsx' \) 2>/dev/null | head -n 200) fi # Relative to upstream if available RANGE="" if git rev-parse --verify @{u} >/dev/null 2>&1; then RANGE="@{u}..HEAD" elif git rev-parse --verify origin/main >/dev/null 2>&1; then RANGE="origin/main..HEAD" elif git rev-parse --verify origin/master >/dev/null 2>&1; then RANGE="origin/master..HEAD" fi changed_significant=0 master_in_range=0 if [[ -n "$RANGE" ]]; then if git diff --name-only "$RANGE" 2>/dev/null | grep -E '^(src/|docs/admin-backend-spec\.md|package\.json)' >/dev/null; then changed_significant=1 fi if git diff --name-only "$RANGE" 2>/dev/null | grep -E '^docs/GISHEN-MASTER-SPEC\.md$' >/dev/null; then master_in_range=1 fi fi # Working tree: uncommitted significant changes without master touch if git status --porcelain 2>/dev/null | grep -E '^(A |M |M|A|\?\?) (src/|docs/admin-backend-spec\.md)' >/dev/null; then if ! git status --porcelain 2>/dev/null | grep -E 'GISHEN-MASTER-SPEC\.md' >/dev/null; then changed_significant=1 fi fi if (( stale == 1 )); then echo "${YEL}WARN:${RST} ${MASTER} looks older than significant Admin sources." echo " Newer example: ${newest_src:-unknown}" echo " Refresh the master changelog + Sources stamp before push." fi if (( changed_significant == 1 && master_in_range == 0 )); then echo "${YEL}WARN:${RST} Significant Admin changes in push range, but ${MASTER} not updated in that range." echo " Agents/humans: update master per Update rule, then recommit." fi if (( stale == 0 && (changed_significant == 0 || master_in_range == 1) )); then echo "${GRN}OK:${RST} No obvious master-spec staleness signals (still verify changelog if you changed domain contracts)." fi echo echo "Sibling skim paths (read-only):" echo " ../Gishen-Mob/docs/BACKEND_SPEC.md" echo " ../Gishen-Ecom/docs/backend.md" echo " ../Gishen-B2B/docs/backend/OVERVIEW.md" echo " ../Gishen-Dispatch-Bot/docs/BACKEND_SPEC.md" echo if [[ "${GISHEN_MASTER_SPEC_STRICT:-0}" == "1" ]] && (( stale == 1 || (changed_significant == 1 && master_in_range == 0) )); then echo "${RED}STRICT:${RST} GISHEN_MASTER_SPEC_STRICT=1 → exiting 1" exit 1 fi exit 0