#!/usr/bin/env bash # Phase 10.2 fail-closed gate for the nested framework layout and onboarding. set -euo pipefail ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" APP="$(cd "$ROOT/../fonoteka.go" && pwd)" NAMES=(backpack boardwalk bonfire bouncer cabana compass festival fetchguard lagoon pact party phrasebook postcard surf tide towel wire wristband) IMPORT_PREFIX='git.golem15.com/golem15/summercms/' STALE_STATUS='Pre-alpha. Planning and research. Nothing runs yet.' usage() { cat >&2 <<'EOF' usage: check-phase10.2.sh --self-test check-phase10.2.sh --layout check-phase10.2.sh --imports check-phase10.2.sh --readmes check-phase10.2.sh --status check-phase10.2.sh --go check-phase10.2.sh --all EOF exit 2 } refuse() { echo "refuse: $*" >&2 return 1 } tracked_source_files() { local repo="$1" if git -C "$repo" rev-parse --is-inside-work-tree >/dev/null 2>&1; then git -C "$repo" ls-files -z -- '*.go' '*.tmpl' '*.sh' ':(exclude).planning/**' return fi ( cd "$repo" find . -path './.planning' -prune -o -type f \( -name '*.go' -o -name '*.tmpl' -o -name '*.sh' \) -print0 ) } check_layout() { local root="$1" name for name in "${NAMES[@]}"; do if [[ -d "$root/$name" ]]; then refuse "leftover root dir: $name" return 1 fi done } check_imports_in() { local repo="$1" file name while IFS= read -r -d '' file; do [[ "$file" != .planning/* ]] || continue [[ "$file" != 'scripts/check-phase10.2.sh' ]] || continue for name in "${NAMES[@]}"; do if grep -Fq "${IMPORT_PREFIX}${name}" "$repo/$file"; then refuse "old import: $repo/$file uses ${name} outside modules" return 1 fi done done < <(tracked_source_files "$repo") } check_imports() { check_imports_in "$1" || return 1 check_imports_in "$2" } check_readmes() { local root="$1" name for name in "${NAMES[@]}"; do if [[ ! -f "$root/modules/$name/README.md" ]]; then refuse "missing README: modules/$name/README.md" return 1 fi done } check_status() { local root="$1" if grep -Fq "$STALE_STATUS" "$root/README.md"; then refuse "stale Status: README still claims nothing runs" return 1 fi } check_hygiene() { local root="$1" app="$2" check_layout "$root" || return 1 check_imports "$root" "$app" || return 1 check_readmes "$root" || return 1 check_status "$root" || return 1 } run_go() { (cd "$ROOT" && go vet ./...) (cd "$ROOT" && go test ./...) (cd "$APP" && go vet ./... ./plugins/golem15/fonoteka/... ./plugins/golem15/user/...) (cd "$APP" && go test ./... ./plugins/golem15/fonoteka/... ./plugins/golem15/user/...) echo "phase10.2 go passed" } expect_refusal() { local name="$1" want="$2" root="$3" app="$4" output if output="$(check_hygiene "$root" "$app" 2>&1)"; then echo "refuse: self-test accepted planted $name" >&2 exit 1 fi if ! grep -Fq "$want" <<<"$output"; then echo "refuse: self-test $name failed for the wrong rule: $output" >&2 exit 1 fi } run_self_test() { bash -n "${BASH_SOURCE[0]}" local scratch app name scratch="$(mktemp -d)" app="$(mktemp -d)" trap 'rm -rf "$scratch" "$app"' RETURN cp "$ROOT/README.md" "$scratch/README.md" for name in "${NAMES[@]}"; do mkdir -p "$scratch/modules/$name" cp "$ROOT/modules/$name/README.md" "$scratch/modules/$name/README.md" done check_hygiene "$scratch" "$app" mkdir -p "$scratch/.planning" printf '%s%s\n' "$IMPORT_PREFIX" backpack >"$scratch/.planning/historical.go" git -C "$scratch" init -q git -C "$scratch" add README.md modules .planning/historical.go check_hygiene "$scratch" "$app" mkdir "$scratch/backpack" expect_refusal 'leftover root dir' 'leftover root dir' "$scratch" "$app" rmdir "$scratch/backpack" printf '%s%s\n' "$IMPORT_PREFIX" backpack >"$scratch/old_import.go" git -C "$scratch" add old_import.go expect_refusal 'old import' 'old import' "$scratch" "$app" git -C "$scratch" rm -q -f old_import.go mv "$scratch/modules/backpack/README.md" "$scratch/modules/backpack/README.saved" expect_refusal 'missing README' 'missing README' "$scratch" "$app" mv "$scratch/modules/backpack/README.saved" "$scratch/modules/backpack/README.md" printf '\n%s\n' "$STALE_STATUS" >>"$scratch/README.md" expect_refusal 'stale Status' 'stale Status' "$scratch" "$app" echo "phase10.2 self-test passed" } case "${1:-}" in --self-test) run_self_test ;; --layout) check_layout "$ROOT" ;; --imports) check_imports "$ROOT" "$APP" ;; --readmes) check_readmes "$ROOT" ;; --status) check_status "$ROOT" ;; --go) run_go ;; --all) check_hygiene "$ROOT" "$APP" run_go echo "phase10.2 check passed" ;; *) usage ;; esac