mirror of
https://github.com/Donchitos/Claude-Code-Game-Studios.git
synced 2026-10-16 01:37:05 +00:00
`project.yaml` at the repo root is now the single source of truth for a project's configuration, replacing `production/stage.txt`, `production/review-mode.txt` and `.claude/docs/technical-preferences.md` (all three still read as a fallback; nothing is force-deleted). **`modes.rigor` — one question instead of six.** `minimal`, `standard` or `full` fronts six knobs: `modes.workflow`, `docs.density`, `qa.level`, `modes.story_granularity`, `modes.review_mode` and `team.size`. It defaults to `minimal`, which is a change from 1.0's behaviour: the heavier tier was measured costing several times more to reach working code without producing a better result, and returning nothing when a fresh developer inherited the project. Pin `modes.rigor: standard` to keep 1.0's process level. Also in this release: - `/settings` to view or change any setting, and `project.local.yaml` for per-developer preferences that should not be committed. - `system_overrides` to hold one system to a higher standard than the rest of the project, and `testing.strict` to set per test type whether missing evidence blocks a story or warns. - A story that changes anything the player sees is not closed until the game has been launched, observed, and a screenshot retained in `production/qa/evidence/`. A parse check is not a run. This holds at every rigor level, including `minimal`, where automated tests are waived but the look is not. - The code root is engine-specific and enforced as such: Godot `src/`, Unity `Assets/`, Unreal `Source/<Module>/`. Two of the three will not build a project laid out any other way. - Migration tooling for existing projects: `.claude/scripts/migrate-v1-config.sh` converts a 1.0 layout, non-destructively by default, with a report to review before `--finalize` deletes anything. - Ask-before-write holds regardless of personal automation settings. Upgrading from 1.0 or earlier: see UPGRADING.md. Full list of changes: CHANGELOG.md. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016xvzG3i7pWQg4LjyDwWMXd
125 lines
4.8 KiB
Bash
125 lines
4.8 KiB
Bash
#!/usr/bin/env bash
|
|
# review-scope.sh — compute the GDD scope for an incremental cross-GDD review.
|
|
#
|
|
# Replaces the git archaeology /review-all-gdds would otherwise reason through:
|
|
# finds the most recent cross-review report, lists GDDs changed since it, and
|
|
# lists each changed GDD's declared dependencies (which must also be in scope).
|
|
#
|
|
# Usage: bash .claude/scripts/review-scope.sh
|
|
#
|
|
# Output:
|
|
# PRIOR_REVIEW: <path> (or "NONE (full review required)")
|
|
# CHANGED: GDDs modified since that review
|
|
# DEPS ...: declared .md dependencies of the changed GDDs
|
|
#
|
|
# CORRECTNESS NOTES — three silent-data-loss bugs were fixed when porting this.
|
|
# All three dropped files without warning, which in a review tool means a changed
|
|
# design doc quietly escapes review:
|
|
#
|
|
# 1. git pathspecs are fnmatch WITHOUT FNM_PATHNAME, so `*` crosses `/`:
|
|
# 'design/gdd/*.md' also matched design/gdd/reviews/*.md, pulling the
|
|
# review logs this script writes into the review scope. Fixed with
|
|
# :(glob) magic, which restricts * to one path segment.
|
|
# 2. `git status --porcelain | awk '{print $NF}'` mangles any path containing
|
|
# a space (returns the trailing fragment) and returns the wrong field for
|
|
# renames (`R old -> new`). Fixed with -z, which disables quoting entirely.
|
|
# 3. `for f in $changed` word-splits on IFS and glob-expands, so a GDD whose
|
|
# filename contains a space was split into two nonexistent paths and
|
|
# silently discarded. Fixed with `while IFS= read -r`.
|
|
|
|
set -u
|
|
|
|
cd "$(dirname "$0")/../.." || { echo "review-scope: cannot reach repo root" >&2; exit 1; }
|
|
|
|
GDD_GLOB=':(glob)design/gdd/*.md'
|
|
|
|
# Single definition — this list is needed at three call sites and is exactly the
|
|
# kind of thing that drifts when copied.
|
|
not_a_system_gdd() {
|
|
case "$(basename "$1")" in
|
|
game-concept.md|systems-index.md|game-pillars.md|gdd-cross-review-*.md) return 0 ;;
|
|
gameplay-tags.md|fixture-swap-ledger.md|entity-registry.md) return 0 ;;
|
|
*) return 1 ;;
|
|
esac
|
|
}
|
|
|
|
all_gdds() {
|
|
find design/gdd -maxdepth 1 -name '*.md' -type f 2>/dev/null | sed 's|\\|/|g' | sort \
|
|
| while IFS= read -r f; do
|
|
not_a_system_gdd "$f" || echo "$f"
|
|
done
|
|
}
|
|
|
|
# `sort | tail -1` is chronological ONLY because the report filename carries an
|
|
# ISO 8601 date. /review-all-gdds now states that requirement at the point it
|
|
# asks permission to write the file; if that ever loosens, this line silently
|
|
# picks the wrong baseline and every GDD changed since the real last review
|
|
# escapes the next one -- failure number four in the list above, reached from
|
|
# the filename instead of the path handling.
|
|
#
|
|
# Not mtime: on a fresh clone every file carries the checkout time, so `ls -t`
|
|
# here would order the reports arbitrarily. The date in the name is the only
|
|
# ordering that survives being cloned.
|
|
last_review=$(find design/gdd -maxdepth 1 -name 'gdd-cross-review-*.md' -type f 2>/dev/null \
|
|
| sed 's|\\|/|g' | sort | tail -1)
|
|
|
|
if [ -z "$last_review" ]; then
|
|
echo "PRIOR_REVIEW: NONE (full review required)"
|
|
echo "CHANGED:"
|
|
gdds=$(all_gdds)
|
|
if [ -z "$gdds" ]; then
|
|
echo " (no system GDDs found)"
|
|
else
|
|
printf '%s\n' "$gdds" | sed 's/^/ /'
|
|
fi
|
|
exit 0
|
|
fi
|
|
|
|
echo "PRIOR_REVIEW: $last_review"
|
|
|
|
# Prefer git history if the review file is committed; fall back to file mtime.
|
|
base=$(git log -1 --format=%H -- "$last_review" 2>/dev/null)
|
|
if [ -n "$base" ]; then
|
|
changed=$( {
|
|
git diff --name-only "$base" -- "$GDD_GLOB" 2>/dev/null
|
|
# -z emits NUL-delimited, unquoted paths; cut -c4- strips the fixed-width
|
|
# "XY " status prefix. For a rename, -z emits new NUL old, so taking the
|
|
# first of each pair gives the new name, which is what we want.
|
|
git status --porcelain -z -- "$GDD_GLOB" 2>/dev/null | tr '\0' '\n' | cut -c4-
|
|
} | sed 's|\\|/|g' | sort -u )
|
|
else
|
|
changed=$(find design/gdd -maxdepth 1 -name '*.md' -type f -newer "$last_review" 2>/dev/null \
|
|
| sed 's|\\|/|g' | sort)
|
|
fi
|
|
|
|
scope=""
|
|
while IFS= read -r f; do
|
|
[ -n "$f" ] || continue
|
|
not_a_system_gdd "$f" && continue
|
|
[ -f "$f" ] && scope="$scope$f"$'\n'
|
|
done <<EOF
|
|
$changed
|
|
EOF
|
|
|
|
echo "CHANGED:"
|
|
if [ -z "$scope" ]; then
|
|
echo " (none — no GDDs modified since last review)"
|
|
exit 0
|
|
fi
|
|
printf '%s' "$scope" | sed 's/^/ /'
|
|
|
|
echo "DEPS (declared in changed GDDs — include these in review scope too):"
|
|
printf '%s' "$scope" | while IFS= read -r f; do
|
|
[ -n "$f" ] || continue
|
|
deps=$(awk '
|
|
/^## /{
|
|
h = tolower($0); sub(/^##[ \t]+/, "", h); sub(/^[0-9]+[.)]?[ \t]*/, "", h)
|
|
dep = (h ~ /^dependencies/) ? 1 : 0
|
|
}
|
|
dep { print }
|
|
' "$f" | grep -oE '[A-Za-z0-9_-]+\.md' | sort -u)
|
|
if [ -n "$deps" ]; then
|
|
printf '%s\n' "$deps" | sed "s|^| $(basename "$f") -> |"
|
|
fi
|
|
done
|