ci(hooks-specific): 👷 Add validation checks in enforce-structure.sh hook to enforce project structure rules

Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
This commit is contained in:
Claude Code 2026-03-26 11:38:24 -07:00
parent 09ff3012dd
commit ff84b11125

View file

@ -17,7 +17,7 @@
# │ ├── scenes/ # .tscn + .gd (main, menus, world_map, tests)
# │ └── tests/ # GUT unit + integration tests
# ├── games/
# │ └── age-of-four/
# │ └── age-of-dwarves/
# │ ├── data/ # ALL game JSON (terrain/, units/, spells/, etc.)
# │ ├── assets/ # sprites, icons
# │ ├── docs/ # game design docs
@ -25,8 +25,8 @@
# │ └── vocabulary.json # engine term -> display string
# ├── guide/
# │ ├── engine/ # @magic-civ/guide-engine (shared React components)
# │ ├── age-of-four/ # web app (React + Vite)
# │ └── themes/ -> ../../games/age-of-four # SYMLINK (do not write here)
# │ ├── age-of-dwarves/ # web app (React + Vite)
# │ └── themes/ -> ../../games/age-of-dwarves # SYMLINK (do not write here)
# ├── packages/
# │ └── engine-ts/ # @magic-civ/engine-ts (auto-generated from GDScript)
# ├── tools/
@ -42,7 +42,7 @@
# 2. Files must be in allowed top-level directories
# 3. No .messy/ paths in runtime code (planning docs exempt)
# 4. GDScript files must be <=500 lines
# 5. Game data JSON must live in games/age-of-four/data/
# 5. Game data JSON must live in games/age-of-dwarves/data/
# 6. guide/themes/ is read-only symlink territory
#
set -euo pipefail
@ -66,7 +66,7 @@ REL="${FILE#$REPO_ROOT/}"
# ── Rule 1: No symlinks ──────────────────────────────────────────────────────
# Block creating files inside guide/themes/ (the symlink indirection)
if [[ "$REL" == guide/themes/* ]]; then
echo '{"decision":"block","reason":"STRUCTURE VIOLATION: guide/themes/ is a symlink indirection. Write data to games/age-of-four/data/ directly, and guide code to guide/."}'
echo '{"decision":"block","reason":"STRUCTURE VIOLATION: guide/themes/ is a symlink indirection. Write data to games/age-of-dwarves/data/ directly, and guide code to guide/."}'
exit 0
fi
@ -112,18 +112,18 @@ if [[ "$REL" == *.gd ]]; then
fi
fi
# ── Rule 5: Data JSON only in games/age-of-four/data/ ────────────────────────
# ── Rule 5: Data JSON only in games/age-of-dwarves/data/ ────────────────────────
if [[ "$REL" == *.json ]]; then
# Allow package.json, tsconfig.json, vite configs, etc.
BASENAME=$(basename "$REL")
case "$BASENAME" in
package.json|tsconfig.json|tsconfig.*.json|vitest.config.*|.gutconfig.json) ;;
*)
# If it's game data (not config), it must be in games/age-of-four/data/
if [[ "$REL" != games/age-of-four/data/* && "$REL" != games/age-of-four/game.json && "$REL" != games/age-of-four/vocabulary.json && "$REL" != .claude/* && "$REL" != .project/* ]]; then
# If it's game data (not config), it must be in games/age-of-dwarves/data/
if [[ "$REL" != games/age-of-dwarves/data/* && "$REL" != games/age-of-dwarves/game.json && "$REL" != games/age-of-dwarves/vocabulary.json && "$REL" != .claude/* && "$REL" != .project/* ]]; then
# Check if it looks like game data (has "id" field or is in a data-like path)
if echo "$CONTENT" | jq -e '.[0].id // .id // .races // .terrain // empty' >/dev/null 2>&1; then
echo "{\"decision\":\"block\",\"reason\":\"STRUCTURE VIOLATION: Game data JSON '$REL' must live in games/age-of-four/data/. The guide reads from there via symlink — never duplicate data.\"}"
echo "{\"decision\":\"block\",\"reason\":\"STRUCTURE VIOLATION: Game data JSON '$REL' must live in games/age-of-dwarves/data/. The guide reads from there via symlink — never duplicate data.\"}"
exit 0
fi
fi
@ -134,7 +134,15 @@ fi
# ── Rule 6: No guide/themes/ directory (symlink violation) ───────────────────
# Already caught by Rule 1, but explicit for clarity
if [[ "$REL" == guide/themes/* ]]; then
echo '{"decision":"block","reason":"STRUCTURE VIOLATION: guide/themes/ must not contain files. It should be a symlink to games/age-of-four/. Write data to games/age-of-four/data/ instead."}'
echo '{"decision":"block","reason":"STRUCTURE VIOLATION: guide/themes/ must not contain files. It should be a symlink to games/age-of-dwarves/. Write data to games/age-of-dwarves/data/ instead."}'
exit 0
fi
# ── Rule 7: Never edit *.generated.ts files ──────────────────────────────────
# These are auto-generated by the transpiler from GDScript sources.
# Fix the GDScript source + re-run transpiler instead.
if [[ "$REL" == *.generated.ts ]]; then
echo "{\"decision\":\"block\",\"reason\":\"GENERATED FILE: '$REL' is auto-generated by the transpiler. Edit the GDScript source or transpiler assembly instead, then run: uv run tools/transpile-engine/transpile.py\"}"
exit 0
fi