Files
settled-reach/Makefile
T
jpmschweitzerandClaude Opus 4.6 3ccac5432b fix(ci): address PR #31 review — harden cross-encoder fixture pipeline
- Fail on encode errors instead of silently writing empty .msgpack files
- Fail test on missing/empty fixture dir instead of silent skip
- Add all missing action variants (MoveSouth, MoveEast, MoveWest,
  Unpause, ToggleStanceDown, WalkAway) to GDScript fixture generator
- Add GDScript fixture staleness check to make pre-pr
- Validate repo root detection before writing outside client/
- Add file.flush() before close in headless mode
- Document fixture failure recovery in DEVOPS.md

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 09:45:13 +01:00

254 lines
8.5 KiB
Makefile

GODOT := $(shell command -v godot4 2>/dev/null || command -v godot 2>/dev/null)
.PHONY: help setup build client server game stop test lint ci ci-client ci-server clean \
decisions-sync decisions-coverage decisions-active decisions-orphan \
db-backup db-install validate-content content-ron check-fact-ids setup-hooks \
pre-pr pre-pr-lint pre-pr-build pre-pr-test pre-pr-validate pre-pr-fixtures \
pre-pr-server pre-pr-client pre-pr-content \
fixtures-client
# --- Configuration ---
GODOT_VERSION ?= 4.6
# Default
help:
@echo "The Settled Reach — Development Commands"
@echo ""
@echo " make setup Install dev dependencies (Rust, Godot, tooling)"
@echo " make build Build client and server"
@echo " make game Build and run the full game (server + client)"
@echo " make stop Stop any running server instance"
@echo " make client Run the Godot client (test mode)"
@echo " make server Run the Rust simulation server"
@echo " make test Run all tests"
@echo " make lint Run all linters"
@echo " make ci Run full CI pipeline locally"
@echo " make ci-client Run client CI checks"
@echo " make ci-server Run server CI checks"
@echo " make clean Remove build artifacts and caches"
@echo ""
@echo " make db-backup Backup shared database to git (main only)"
@echo " make db-install Restore shared database from backup"
@echo ""
@echo " make decisions-sync Sync decisions/*.md into SQLite"
@echo " make decisions-coverage Decision-to-ticket coverage by domain"
@echo " make decisions-active List active decisions"
@echo " make decisions-orphan Decisions without implementing tickets"
@echo " make validate-content Validate content YAML against schemas"
@echo " make check-fact-ids Check fact_id references against knowledge catalogs"
@echo " make content-ron Convert content YAML to RON (build-time)"
@echo " make fixtures-client Generate GDScript->Rust cross-encoder fixtures (#475)"
@echo ""
@echo " make pre-pr Run all pre-PR checks (lint, build, test, validate, fixtures)"
@echo " make pre-pr-server Server-scoped pre-PR (lint, build, test, fixtures)"
@echo " make pre-pr-client Client-scoped pre-PR (lint, build, test)"
@echo " make pre-pr-content Content-scoped pre-PR (schema + cross-ref validation)"
@echo ""
@echo " make setup-hooks Install pre-commit hooks (included in setup)"
@echo ""
@echo " GODOT_VERSION=4.6 make setup Override Godot version"
# --- Setup ---
setup: setup-rust setup-godot setup-tooling setup-hooks decisions-sync
@echo "Dev environment ready."
setup-rust:
@tooling/install-rust
setup-godot:
@GODOT_VERSION=$(GODOT_VERSION) tooling/install-godot
setup-tooling:
@echo "Checking tooling dependencies..."
@command -v python3 >/dev/null 2>&1 || { echo "Install Python 3"; exit 1; }
@command -v curl >/dev/null 2>&1 || { echo "Install curl (required for Godot download)"; exit 1; }
@command -v unzip >/dev/null 2>&1 || { echo "Install unzip (required for Godot download)"; exit 1; }
setup-hooks:
@git config core.hooksPath .config/hooks
@echo "Git hooks path set to .config/hooks"
# --- Build ---
build: build-server build-client
build-server:
cd server && cargo build
build-client:
@test -n "$(GODOT)" || { echo "Godot not found. Run 'make setup' first."; exit 1; }
$(GODOT) --headless --path client --quit
# --- Run ---
server:
cd server && cargo run
client:
@test -n "$(GODOT)" || { echo "Godot not found. Run 'make setup' first."; exit 1; }
$(GODOT) --path client
game: stop build-server
@test -n "$(GODOT)" || { echo "Godot not found. Run 'make setup' first."; exit 1; }
@echo "Starting server..."
@cd server && cargo run &
@sleep 2
@echo "Starting client..."
@SR_LIVE=1 $(GODOT) --path client
@$(MAKE) stop
stop:
@lsof -ti :9876 | xargs -r kill 2>/dev/null || true
@echo "Stopped any running server on port 9876"
# --- Test ---
test: test-server test-client
test-server:
cd server && cargo nextest run
fixtures:
cd server && cargo test --test gen_fixtures -- --ignored
fixtures-client:
@test -n "$(GODOT)" || { echo "Godot not found. Run 'make setup' first."; exit 1; }
@echo "Generating GDScript fixtures for Rust decoder..."
$(GODOT) --headless --path client -s res://tests/gen_client_fixtures.gd
@echo "Verifying Rust can decode GDScript fixtures..."
cd server && cargo test --test serialization gdscript_generated_fixtures
@echo "--- Fixtures-client: PASS ---"
test-client:
@test -n "$(GODOT)" || { echo "Godot not found. Run 'make setup' first."; exit 1; }
$(GODOT) --headless --path client -s res://addons/gdUnit4/bin/GdUnitCmdTool.gd --ignoreHeadlessMode -a res://tests/
# --- Lint ---
lint: lint-server lint-client
lint-server:
cd server && cargo clippy -- -D warnings
cd server && cargo fmt --check
lint-client:
@test -n "$(GODOT)" || { echo "Godot not found. Run 'make setup' first."; exit 1; }
@echo "Checking GDScript for errors..."
@$(GODOT) --headless --path client --quit 2>&1 | grep -i "SCRIPT ERROR" && { echo "GDScript errors found"; exit 1; } || echo "No script errors found"
# --- Pre-PR verification ---
pre-pr: pre-pr-lint pre-pr-build pre-pr-test pre-pr-validate pre-pr-fixtures
@echo ""
@echo "=== PRE-PR: ALL CHECKS PASSED ==="
@echo "Safe to create PR."
pre-pr-lint: lint-server lint-client
@echo "--- Lint: PASS ---"
pre-pr-build: build-server build-client
@echo "--- Build: PASS ---"
pre-pr-test: test-server test-client
@echo "--- Tests: PASS ---"
pre-pr-validate: validate-content check-fact-ids
@echo "--- Content validation: PASS ---"
pre-pr-fixtures:
@echo "Checking Rust->GDScript fixture staleness..."
@cd server && cargo test --test gen_fixtures -- --ignored
@if git diff --quiet client/tests/fixtures/; then \
echo "--- Rust fixtures: UP TO DATE ---"; \
else \
echo ""; \
echo "--- RUST FIXTURES STALE ---"; \
echo " Protocol changed but fixtures not regenerated."; \
echo " Stale fixtures make all client tests FALSE POSITIVES."; \
echo ""; \
echo " Changed files:"; \
git diff --stat client/tests/fixtures/; \
echo ""; \
echo " Fix: commit the updated fixtures with your protocol change."; \
exit 1; \
fi
@echo "Checking GDScript->Rust fixture staleness..."
@$(MAKE) fixtures-client
@if git diff --quiet server/tests/fixtures/gdscript/; then \
echo "--- GDScript fixtures: UP TO DATE ---"; \
else \
echo ""; \
echo "--- GDSCRIPT FIXTURES STALE ---"; \
echo " Protocol changed but GDScript fixtures not regenerated."; \
echo " Stale fixtures make cross-encoder tests FALSE POSITIVES."; \
echo ""; \
echo " Changed files:"; \
git diff --stat server/tests/fixtures/gdscript/; \
echo ""; \
echo " Fix: commit the updated fixtures with your protocol change."; \
exit 1; \
fi
# Branch-specific variants (faster, scope-appropriate)
pre-pr-server: lint-server build-server test-server pre-pr-fixtures
@echo "=== Server pre-PR: PASSED ==="
pre-pr-client: lint-client build-client test-client
@echo "=== Client pre-PR: PASSED ==="
pre-pr-content: validate-content check-fact-ids
@echo "=== Content pre-PR: PASSED ==="
# --- CI (run locally) ---
ci: ci-server ci-client
ci-server: lint-server build-server test-server
ci-client: lint-client build-client test-client
# --- Database ---
db-backup:
@tooling/db-backup
db-install:
@tooling/db-install
# --- Decisions ---
decisions-sync:
@db/connectors/decisions-sync
decisions-coverage:
@db/connectors/sqlite-query "SELECT d.domain, COUNT(DISTINCT d.id) as decisions, COUNT(DISTINCT t.decision_ref) as with_tickets FROM decisions d LEFT JOIN tickets t ON d.id = t.decision_ref WHERE d.status='active' AND d.type='confirmed' GROUP BY d.domain"
decisions-active:
@db/connectors/sqlite-query "SELECT id, domain, title FROM decisions WHERE status='active' AND type='confirmed' ORDER BY domain, id"
decisions-orphan:
@db/connectors/sqlite-query "SELECT id, title FROM decisions WHERE type='confirmed' AND status='active' AND id NOT IN (SELECT DISTINCT decision_ref FROM tickets WHERE decision_ref IS NOT NULL)"
# --- Content Validation ---
validate-content:
@tooling/validate-content
check-fact-ids:
@tooling/check-fact-ids
content-ron:
cd tooling/content-converter && cargo build --release
tooling/content-converter/target/release/content-converter --input content --output content-ron --verbose
# --- Clean ---
clean:
cd server && cargo clean || true
rm -rf .cache/*
rm -rf client/.godot client/reports
@echo "Clean complete."