Twelve scripts retired, three domains registered. `reach` now covers nine. generate: `generate-brands` and `generate-corporations` were the second and third copies of the same 24-line build-if-missing-then-exec bash `tooling/atlas` carried, so they collapsed into `core.process.cargo_binary` rather than being ported. `import_economics` shelled out to the first of those, so it now calls that helper — `generated_brands.toml` comes back byte-identical, and the stamp registry swaps the retired wrapper for `core/process.py`. pr: `watchlist-diff` derives its watched set from `generator_sources.py` instead of restating it, so it cannot drift from the stamp check. dev: the environment scripts split decision from performing, per D-263's guarded-exec rule. `godot_plan()` and `worktree_plan()` decide what would happen; `install_godot()`, `install_rust()` and `setup_worktree()` do it. `tooling/test_environment.py` pins the version pin, both override precedences, the already-current skip, the platform refusal and both worktree refusals — none of them performed. `make setup` now installs reach first, since the targets that install rust and godot are reach verbs. Two live bugs found while porting: - The clerk read its decision index from `decisions/README.md`, a path that stopped existing when the DQR tree moved to `governance/`. Every clerk agent has been grepping blind; its prompt pointed at the same dead directory. - The conformance exec-check matched any `x.system()` regardless of receiver, so `platform.system()` read as `os.system()`. Narrowed and re-proved against a real mutant. `process.run` gains `input=`, `timeout=` and a `ProcessTimeout` subclass so a killed run stays distinguishable from a verdict. The pre-push hook no longer merges the clerk's stderr into its stdout — under streaming the last merged line is a JSONL event, which would read as an unrecognised verdict and block. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
623 lines
27 KiB
Makefile
623 lines
27 KiB
Makefile
GODOT := $(shell command -v godot4 2>/dev/null || command -v godot 2>/dev/null)
|
|
|
|
.PHONY: help setup build client server game atlas stop test test-tooling lint lint-python setup-venv ci ci-client ci-server clean \
|
|
install-reach reach-repoint \
|
|
decisions-sync decisions-active decisions-validate \
|
|
setup-hooks install-hooks \
|
|
audit deny economy-db regen-db \
|
|
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 fixtures-gauntlet golden-diff golden-update \
|
|
check-star-map star-map-data \
|
|
build-sr-voice run-sr-voice test-voice-mock test-voice-real \
|
|
perf-baseline debug-schedule \
|
|
test-ipc-fixtures test-ipc-protocol test-ipc-integration test-ipc-benchmark \
|
|
screenshot visual-movie test-visual visual-update \
|
|
manifest diagrams check-diagrams
|
|
|
|
# --- Configuration ---
|
|
|
|
GODOT_VERSION ?= 4.6
|
|
# One interpreter for both .venv and the installed `reach` tool. Pinned rather
|
|
# than inferred: uv otherwise picks the lowest version satisfying
|
|
# requires-python, which forks the two environments silently (T-1261).
|
|
PYTHON_VERSION ?= 3.14
|
|
|
|
# Default
|
|
help:
|
|
@echo "The Settled Reach — Development Commands"
|
|
@echo ""
|
|
@echo " make setup Install dev dependencies (Rust, Godot, tooling, venv)"
|
|
@echo " make setup-venv Create .venv and install Python tooling deps"
|
|
@echo " make install-reach Install the 'reach' CLI onto PATH (bare name, no venv needed)"
|
|
@echo " make reach-repoint Re-point 'reach' at THIS checkout (after worktree work)"
|
|
@echo " make build Build client and server"
|
|
@echo " make game Build and run the full game (server + client)"
|
|
@echo " make atlas Standalone Atlas companion app — attach or spawn, read-only (D-254)"
|
|
@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 test-tooling Tooling test gate: sim determinism + economics dry-run"
|
|
@echo " make test-ipc-fixtures Layer 1: IPC serialization fixtures"
|
|
@echo " make test-ipc-protocol Layer 2: mock IPC protocol tests"
|
|
@echo " make test-ipc-integration Layer 3: real subprocess round-trip"
|
|
@echo " make test-ipc-benchmark IPC latency benchmark (blocked: #555/#556)"
|
|
@echo " make lint Run all linters (server, client, python)"
|
|
@echo " make lint-python Run ruff on tooling/"
|
|
@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 decisions-sync Sync governance/*.md decision records into pql.db"
|
|
@echo " make decisions-active List active confirmed decisions (pql)"
|
|
@echo " make decisions-validate Validate decision records — malformed-record gate (pql)"
|
|
@echo " make audit Run cargo audit (security advisory check)"
|
|
@echo " make deny Run cargo deny check (license/ban policy)"
|
|
@echo " make star-map-data Regenerate client/data/star_map_data.json from systems.db + wiki"
|
|
@echo " make check-star-map Assert star_map_data.json is up to date (part of pre-pr-client)"
|
|
@echo " make economy-db Import economics data into systems.db (TOML/JSON → SQLite)"
|
|
@echo " make regen-db Regenerate systems.db from all sources + stamp meta table (#855)"
|
|
@echo " make install-hooks Install pre-push + pre-commit git hooks (once per clone)"
|
|
@echo " make fixtures-client Generate GDScript->Rust cross-encoder fixtures (#475)"
|
|
@echo " make golden-diff Show diff if golden file output has changed"
|
|
@echo " make golden-update Regenerate golden file and stage for commit"
|
|
@echo " make perf-baseline Run performance benchmarks and save baseline"
|
|
@echo ""
|
|
@echo " make screenshot Ad-hoc visual capture (SCENARIO=name, default: atlas_GJ820Bc_Global)"
|
|
@echo " make visual-movie Flow capture with contact sheet (FLOW=name)"
|
|
@echo " make test-visual Run visual golden regression tests"
|
|
@echo " make visual-update Regenerate visual goldens and stage for commit"
|
|
@echo ""
|
|
@echo " make manifest Regenerate assets/characters/manifest.json from asset dirs (#720)"
|
|
@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 " make build-sr-voice Build sr-voice LLM inference service"
|
|
@echo " make serve-sr-voice Start sr-voice server (ARGS='--model <path>')"
|
|
@echo " make run-sr-voice Submit to sr-voice server (ARGS='generate|batch|benchmark ...')"
|
|
@echo " make stop-sr-voice Stop sr-voice server"
|
|
@echo " make test-voice-mock Test voice pipeline with mock sr-voice"
|
|
@echo " make test-voice-real Test voice pipeline with real sr-voice + Gemma 2B"
|
|
@echo " make debug-schedule Print bevy_ecs schedule graph (diff for PR artifacts)"
|
|
@echo ""
|
|
@echo " GODOT_VERSION=4.6 make setup Override Godot version"
|
|
|
|
# --- Setup ---
|
|
|
|
# install-reach leads: it needs only uv, and setup-rust/setup-godot are now
|
|
# reach verbs. Bootstrapping the CLI before the things it installs is the only
|
|
# order that works on a cold checkout.
|
|
setup: install-reach setup-rust setup-godot setup-tooling setup-venv setup-hooks decisions-sync
|
|
@echo "Dev environment ready."
|
|
|
|
setup-rust:
|
|
@reach dev install-rust
|
|
|
|
setup-godot:
|
|
@reach dev install-godot --version $(GODOT_VERSION)
|
|
|
|
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; }
|
|
@python3 -c "import yaml" 2>/dev/null || { echo "Install PyYAML: pip install pyyaml"; exit 1; }
|
|
@python3 -c "import jsonschema" 2>/dev/null || { echo "Install jsonschema: pip install jsonschema"; exit 1; }
|
|
|
|
setup-hooks:
|
|
@git config core.hooksPath .config/hooks
|
|
@echo "Git hooks path set to .config/hooks"
|
|
|
|
install-hooks: setup-hooks
|
|
@chmod +x .config/hooks/pre-push .config/hooks/pre-commit \
|
|
.config/hooks/post-merge .config/hooks/post-checkout .config/hooks/post-rewrite
|
|
@echo "Hooks installed — pre-commit, pre-push, post-merge, post-checkout, post-rewrite are active."
|
|
|
|
setup-venv:
|
|
@command -v uv >/dev/null 2>&1 || { echo "Install uv: https://docs.astral.sh/uv/"; exit 1; }
|
|
@uv venv --python $(PYTHON_VERSION) --allow-existing .venv
|
|
@uv pip install --python .venv/bin/python -e ".[dev]" --quiet
|
|
@echo "Venv ready at .venv — activate with: source .venv/bin/activate"
|
|
@echo "NOTE: activating is for running tests. The reach CLI does not need it — see 'make install-reach'."
|
|
|
|
# The PATH guarantee (T-1261, D-263). A [project.scripts] entrypoint alone lands
|
|
# in .venv/bin, which is on PATH only while the venv is activated — and agents
|
|
# and git hooks never activate it. `uv tool install` puts the executable in
|
|
# ~/.local/bin instead, so `reach` is a bare name everywhere: interactive shell,
|
|
# git hook, agent Bash call.
|
|
#
|
|
# --editable so the checkout IS the source: edit tooling/, run reach, no reinstall.
|
|
# --python pinned so the tool and .venv run the SAME interpreter; left to itself
|
|
# uv picks the lowest version satisfying requires-python (it chose 3.11 while the
|
|
# venv was on 3.14), which is a silent interpreter fork of exactly the kind this
|
|
# initiative exists to remove.
|
|
install-reach:
|
|
@command -v uv >/dev/null 2>&1 || { echo "Install uv: https://docs.astral.sh/uv/"; exit 1; }
|
|
@uv tool install --python $(PYTHON_VERSION) --editable . --force
|
|
@command -v reach >/dev/null 2>&1 || { \
|
|
echo "FAIL: 'reach' is not on PATH. Add ~/.local/bin to PATH (uv tool update-shell)."; exit 1; }
|
|
@echo "reach installed — verify with: reach --help"
|
|
|
|
# Re-point reach at THIS checkout. uv records the source path at install time, so
|
|
# an install made from a worktree keeps resolving there after the worktree is
|
|
# removed, and edits in the main checkout then have no effect on a working `reach`
|
|
# — a confusing failure with no error message. Same command; the alias exists so
|
|
# the situation has a name.
|
|
reach-repoint: install-reach
|
|
@echo "reach now resolves to: $(CURDIR)"
|
|
|
|
# --- Build ---
|
|
|
|
build: build-server build-client
|
|
|
|
build-server:
|
|
cd server && cargo build
|
|
|
|
build-server-release:
|
|
cd server && cargo build --release
|
|
|
|
build-client:
|
|
@test -n "$(GODOT)" || { echo "Godot not found. Run 'make setup' first."; exit 1; }
|
|
@# First import may error on theme/font loading before the import scan completes.
|
|
@# Run twice: first pass generates imports silently, second pass validates clean.
|
|
@$(GODOT) --headless --path client --import --quit 2>/dev/null || true
|
|
$(GODOT) --headless --path client --import --quit
|
|
|
|
# --- Run ---
|
|
|
|
server:
|
|
cd server && cargo run --bin settled-reach-server
|
|
|
|
client:
|
|
@test -n "$(GODOT)" || { echo "Godot not found. Run 'make setup' first."; exit 1; }
|
|
$(GODOT) --path client
|
|
|
|
game: stop build
|
|
@test -n "$(GODOT)" || { echo "Godot not found. Run 'make setup' first."; exit 1; }
|
|
@echo "Starting server..."
|
|
@cd server && cargo run --bin settled-reach-server &
|
|
@sleep 2
|
|
@echo "Starting client..."
|
|
@SR_LIVE=1 $(GODOT) --path client
|
|
@$(MAKE) stop
|
|
|
|
# D-254/T-1132: standalone Atlas companion app. Unlike `game`, no orchestration
|
|
# here — atlas_standalone.gd owns its own attach-or-spawn decision and child
|
|
# server lifecycle internally (D-254 §1/§3), so this target is just "build,
|
|
# then launch the standalone scene". build-server ensures the debug binary
|
|
# exists for spawn-mode (atlas_standalone.gd resolves it at
|
|
# server/target/debug/settled-reach-server, the same path the E2E test files
|
|
# use); build-client ensures imports are current. SR_LIVE=1 is required —
|
|
# without it SimBridge boots in test mode (instant fake CONNECTED, no network
|
|
# at all), which would make the companion open the Atlas against a dynamic
|
|
# test-harness snapshot instead of the real systems.db world via the wire.
|
|
# Release server for the atlas: a cold DEBUG server takes >10s before the
|
|
# first tile of a new body can exist (first-body terrain analysis), which
|
|
# reads as a black/broken map on entry (live-verified 2026-07-22). The
|
|
# release binary serves a cold body's first tiles in well under a second.
|
|
# SR_SERVER_BIN tells atlas_standalone.gd's spawn path which binary to use.
|
|
atlas: build-server-release build-client
|
|
@test -n "$(GODOT)" || { echo "Godot not found. Run 'make setup' first."; exit 1; }
|
|
@SR_LIVE=1 SR_SERVER_BIN=server/target/release/settled-reach-server $(GODOT) --path client scenes/atlas_standalone.tscn
|
|
|
|
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:
|
|
tests/run-rust
|
|
|
|
fixtures:
|
|
cd server && cargo test --test gen_fixtures -- --ignored
|
|
|
|
fixtures-gauntlet:
|
|
cd server && cargo test --test gen_gauntlet_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 ---"
|
|
|
|
golden-diff:
|
|
@echo "Regenerating golden output for comparison..."
|
|
@mkdir -p .cache/golden
|
|
@cp server/tests/golden/proof_room_tick_10.json .cache/golden/before.json
|
|
@cd server && UPDATE_GOLDEN=1 cargo test --test golden_suite -- proof_room_tick_10_matches_golden; \
|
|
rc=$$?; \
|
|
cp ../server/tests/golden/proof_room_tick_10.json ../.cache/golden/after.json 2>/dev/null; \
|
|
cp ../.cache/golden/before.json ../server/tests/golden/proof_room_tick_10.json; \
|
|
if [ $$rc -ne 0 ]; then echo "Cargo test failed (golden file restored)."; exit $$rc; fi
|
|
@if diff -q .cache/golden/before.json .cache/golden/after.json >/dev/null 2>&1; then \
|
|
echo "--- Golden file: UP TO DATE ---"; \
|
|
else \
|
|
echo "--- Golden file has CHANGED ---"; \
|
|
echo ""; \
|
|
diff --color -u .cache/golden/before.json .cache/golden/after.json || true; \
|
|
echo ""; \
|
|
echo "Run 'make golden-update' to accept changes."; \
|
|
exit 1; \
|
|
fi
|
|
|
|
golden-update:
|
|
@echo "Regenerating golden files..."
|
|
@cd server && UPDATE_GOLDEN=1 cargo test --test golden_suite -- proof_room_tick_10_matches_golden
|
|
@cd server && UPDATE_GOLDEN=1 cargo test --test cascade_golden
|
|
@git add server/tests/golden/
|
|
@echo "--- Golden file updated and staged ---"
|
|
@echo "Review with: git diff --cached -- server/tests/golden/"
|
|
|
|
test-client:
|
|
tests/run-godot
|
|
|
|
test-ipc-fixtures:
|
|
tests/run-ipc-fixtures
|
|
|
|
test-ipc-protocol:
|
|
tests/run-ipc-protocol
|
|
|
|
test-ipc-integration:
|
|
tests/run-ipc-integration
|
|
|
|
test-ipc-benchmark:
|
|
tests/run-ipc-benchmark
|
|
|
|
# Python with tooling deps (numpy/scipy) — .venv from `make setup-venv`, else system python3
|
|
VENV_PY := $(shell test -x .venv/bin/python && echo .venv/bin/python || echo python3)
|
|
|
|
# Tooling test gate (T-1066) — called by pre-push when tooling/ changed.
|
|
# 1. planet-gen determinism guard (#963): simulating the same body twice must
|
|
# be bit-identical (guards the expensive 271-body heightmap bake).
|
|
# Exit 2 = no testable body found — warn, don't block.
|
|
# 2. import_economics --dry-run against the committed DB: full parse +
|
|
# structural/coverage validation, no writes. Exit 2 = coverage-gate
|
|
# warning (D-175) — tolerated, matching regen-db's treatment.
|
|
test-tooling:
|
|
@echo " [test-tooling] planet-gen determinism guard (#963)..."
|
|
@rc=0; $(VENV_PY) tooling/planet-gen/test_sim_determinism.py || rc=$$?; \
|
|
if [ $$rc -eq 2 ]; then \
|
|
echo " WARNING: determinism guard found no testable body (exit 2) — not blocking"; \
|
|
elif [ $$rc -ne 0 ]; then \
|
|
echo " FAIL: planet_simulation determinism drift (exit $$rc)"; exit $$rc; \
|
|
fi
|
|
@echo " [test-tooling] oasis ring-scaling pin (T-964, PR #210 review)..."
|
|
@$(VENV_PY) tooling/planet-gen/test_oasis_ring_scaling.py 2> .cache/test-tooling-oasis-ring.log || \
|
|
{ echo " FAIL: oasis ring scaling — log follows:"; cat .cache/test-tooling-oasis-ring.log; exit 1; }
|
|
@echo " [test-tooling] canvas-generation version gate units (T-1242)..."
|
|
@mkdir -p .cache
|
|
@python3 tooling/test_canvas_version_check.py 2> .cache/test-tooling-canvas-version.log || \
|
|
{ echo " FAIL: canvas version gate units — log follows:"; cat .cache/test-tooling-canvas-version.log; exit 1; }
|
|
@echo " [test-tooling] reach lazy domain registration (T-1260)..."
|
|
@mkdir -p .cache
|
|
@$(VENV_PY) tooling/test_lazy_domains.py 2> .cache/test-tooling-lazy-domains.log || \
|
|
{ echo " FAIL: reach lazy registration — log follows:"; cat .cache/test-tooling-lazy-domains.log; exit 1; }
|
|
@echo " [test-tooling] reach detached-job exit codes (T-1279)..."
|
|
@mkdir -p .cache
|
|
@$(VENV_PY) tooling/test_job_exit_codes.py 2> .cache/test-tooling-job-exits.log || \
|
|
{ echo " FAIL: detached exit codes — log follows:"; cat .cache/test-tooling-job-exits.log; exit 1; }
|
|
@echo " [test-tooling] reach jobs service units (T-1278)..."
|
|
@mkdir -p .cache
|
|
@$(VENV_PY) tooling/test_jobs.py 2> .cache/test-tooling-jobs.log || \
|
|
{ echo " FAIL: jobs service — log follows:"; cat .cache/test-tooling-jobs.log; exit 1; }
|
|
@echo " [test-tooling] reach dev environment decisions (T-1286)..."
|
|
@mkdir -p .cache
|
|
@$(VENV_PY) tooling/test_environment.py 2> .cache/test-tooling-environment.log || \
|
|
{ echo " FAIL: environment decisions — log follows:"; cat .cache/test-tooling-environment.log; exit 1; }
|
|
@echo " [test-tooling] reach D-263 conformance (T-1270)..."
|
|
@mkdir -p .cache
|
|
@$(VENV_PY) tooling/test_conformance.py 2> .cache/test-tooling-conformance.log || \
|
|
{ echo " FAIL: reach conformance — log follows:"; cat .cache/test-tooling-conformance.log; exit 1; }
|
|
@echo " [test-tooling] reach validate verbs — behaviour (T-1282)..."
|
|
@mkdir -p .cache
|
|
@$(VENV_PY) tooling/test_validate.py 2> .cache/test-tooling-validate.log || \
|
|
{ echo " FAIL: validate verbs — log follows:"; cat .cache/test-tooling-validate.log; exit 1; }
|
|
@echo " [test-tooling] reach check gates — behaviour (T-1281)..."
|
|
@mkdir -p .cache
|
|
@$(VENV_PY) tooling/test_check.py 2> .cache/test-tooling-check.log || \
|
|
{ echo " FAIL: check gates — log follows:"; cat .cache/test-tooling-check.log; exit 1; }
|
|
@echo " [test-tooling] economy_import.traits validation units (T-995/PR #173 H2)..."
|
|
@mkdir -p .cache
|
|
@python3 tooling/economy-db/test_traits.py 2> .cache/test-tooling-traits.log || \
|
|
{ echo " FAIL: traits validation units — log follows:"; cat .cache/test-tooling-traits.log; exit 1; }
|
|
@echo " [test-tooling] atlas_city_names/atlas_feature_names idempotency (T-964)..."
|
|
@python3 tooling/economy-db/test_atlas_idempotency.py 2> .cache/test-tooling-atlas-idempotency.log || \
|
|
{ echo " FAIL: atlas name-pool idempotency — log follows:"; cat .cache/test-tooling-atlas-idempotency.log; exit 1; }
|
|
@echo " [test-tooling] import_economics --dry-run (committed DB)..."
|
|
@rc=0; python3 tooling/economy-db/import_economics.py --dry-run \
|
|
> .cache/test-tooling-dryrun.log 2>&1 || rc=$$?; \
|
|
if [ $$rc -eq 2 ]; then \
|
|
echo " WARNING: coverage gate warning (exit 2) — not blocking (matches regen-db)"; \
|
|
elif [ $$rc -ne 0 ]; then \
|
|
echo " FAIL: import_economics --dry-run exited $$rc — log follows:"; \
|
|
cat .cache/test-tooling-dryrun.log; exit $$rc; \
|
|
fi
|
|
@echo " test-tooling: PASS"
|
|
|
|
# --- Clean ---
|
|
|
|
clean-imports:
|
|
@echo "Removing Godot import cache..."
|
|
rm -rf client/.godot/imported/
|
|
@echo "Re-importing assets (this may take a while on first run)..."
|
|
$(GODOT) --headless --path client --import --quit
|
|
@echo "Import cache rebuilt."
|
|
|
|
# --- Lint ---
|
|
|
|
lint: lint-server lint-client lint-python
|
|
|
|
lint-python:
|
|
ruff check tooling/
|
|
|
|
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 audit deny
|
|
@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: check-star-map
|
|
@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 audit deny
|
|
@echo "=== Server pre-PR: PASSED ==="
|
|
|
|
pre-pr-client: lint-client build-client test-client check-star-map
|
|
@echo "=== Client pre-PR: PASSED ==="
|
|
|
|
pre-pr-content:
|
|
@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 ---
|
|
|
|
economy-db: ## Import economics data (commodities, chains, gate links) into systems.db
|
|
@echo " Generating minor brands (D-189 #829)..."
|
|
@reach generate brands
|
|
@python3 tooling/economy-db/import_economics.py
|
|
|
|
regen-db: ## Regenerate systems.db from all sources and stamp meta table (#855, #856)
|
|
@# Run as a single shell so `set -e` covers all steps. Without this
|
|
@# each recipe line was a fresh shell and a failure in step 1 did not
|
|
@# halt step 2, which could produce stale data with a fresh stamp
|
|
@# (PR #136 review T4). import_economics' exit code 2 is a valid
|
|
@# coverage-gate-warning state (DB and stamp committed), not an error,
|
|
@# so it's explicitly tolerated. Any other non-zero exit halts the
|
|
@# pipeline immediately. The atlas city/road/river geometry generator
|
|
@# was retired in #951 (D-223); import_economics now owns the atlas
|
|
@# index — it loads the names-only pool into atlas_city_names and empties
|
|
@# the geometry tables (the server cascade fills them, Phase 4).
|
|
@set -e; \
|
|
echo " [regen-db] Importing economics data (runs generate_brands internally)..."; \
|
|
ec=0; python3 tooling/economy-db/import_economics.py || ec=$$?; \
|
|
if [ $$ec -ne 0 ] && [ $$ec -ne 2 ]; then exit $$ec; fi; \
|
|
echo ""; \
|
|
echo " regen-db complete — systems.db is up to date and stamped."; \
|
|
echo " Stage it with: git add server/data/systems.db"
|
|
|
|
# The five gate targets that lived here are RETIRED, not wrapped (D-263,
|
|
# T-1281). They are tooling, and tooling has one door:
|
|
#
|
|
# make check-systems-db -> reach check systems-db-stamp
|
|
# make check-client-version -> reach check client-version
|
|
# make check-canvas-version -> reach check canvas-version
|
|
# make check-fact-ids -> reach check fact-ids
|
|
# make check-dataflow-graph -> reach check dataflow-graph
|
|
# make validate-content -> reach validate content
|
|
# make checklist-validate -> reach validate checklist --check
|
|
# make checklist-generate -> reach validate checklist
|
|
# make atlas-verify -> reach atlas verify
|
|
#
|
|
# Wrapping them would leave two ways to invoke each, and `reach --help` would
|
|
# stop being the answer to "what tooling exists" because the Makefile would
|
|
# still be a competing index. make keeps build and test ORCHESTRATION; it does
|
|
# not keep aliases for individual tools.
|
|
|
|
econ-sim: ## Build the economics simulation binary (Layer 1+2: Leontief + tâtonnement trade)
|
|
@cargo build --manifest-path tooling/econ-sim/Cargo.toml --release
|
|
@echo "Built: tooling/econ-sim/target/release/econ-sim"
|
|
|
|
econ-sim-run: ## Run a quick economics simulation (100 ticks, output to /tmp/econ-sim.csv)
|
|
@tooling/econ-sim/target/release/econ-sim --ticks 100 --output /tmp/econ-sim.csv
|
|
@echo "Output: /tmp/econ-sim.csv"
|
|
|
|
econ-sim-stability: ## Run D-179 stability checks (Tests 1 and 2)
|
|
@tooling/econ-sim/target/release/econ-sim --stability-check
|
|
|
|
# --- Decisions (pql) ---
|
|
# Decision records are markdown-sourced under governance/{decisions,questions,rejected}/
|
|
# and indexed into .pql/pql.db by `pql decisions sync`. Per-decision ticket coverage:
|
|
# `pql decisions show <id> --with-tickets`. Cross-references: `pql decisions refs <id>`.
|
|
|
|
decisions-sync:
|
|
@pql decisions sync
|
|
|
|
decisions-active:
|
|
@pql decisions list --type confirmed
|
|
|
|
decisions-validate:
|
|
@pql decisions validate
|
|
|
|
# --- Content Validation ---
|
|
|
|
audit:
|
|
cd server && cargo audit
|
|
|
|
deny:
|
|
cd server && cargo deny check
|
|
|
|
check-star-map:
|
|
@python3 tooling/generate-star-map-data.py --check
|
|
|
|
# Regenerate client/data/star_map_data.json from systems.db + wiki. Depends on
|
|
# nothing — call this after any systems.db change (e.g. the server atlas
|
|
# pipeline populating terrain_reference in #839) so the atlas viewer picks up
|
|
# the new fields. pre-pr-client / pre-pr-validate assert staleness via
|
|
# check-star-map and will fail if this step is skipped.
|
|
star-map-data:
|
|
@python3 tooling/generate-star-map-data.py
|
|
|
|
perf-baseline:
|
|
@reach dev perf
|
|
|
|
# --- Schedule debug (#346) ---
|
|
|
|
debug-schedule:
|
|
@echo "Dumping bevy_ecs schedule graph..."
|
|
@cd server && cargo run --bin settled-reach-server -- --dump-schedule
|
|
|
|
# --- Visual test harness ---
|
|
|
|
screenshot:
|
|
@tests/run-visual --screenshot $(SCENARIO)
|
|
|
|
visual-movie:
|
|
@tests/run-visual --movie $(FLOW)
|
|
|
|
test-visual:
|
|
@tests/run-visual
|
|
|
|
visual-update:
|
|
@tests/run-visual --update
|
|
|
|
LIBCLANG_PATH ?= /usr/lib64/rocm/llvm/lib
|
|
BINDGEN_CLANG_ARGS ?= -I/usr/lib64/rocm/llvm/lib/clang/19/include
|
|
SR_VOICE_ENV = LIBCLANG_PATH=$(LIBCLANG_PATH) BINDGEN_EXTRA_CLANG_ARGS="$(BINDGEN_CLANG_ARGS)"
|
|
|
|
SR_VOICE_PORT ?= 8321
|
|
|
|
build-sr-voice:
|
|
cd server/sr-voice && $(SR_VOICE_ENV) cargo build --release
|
|
|
|
serve-sr-voice:
|
|
cd server/sr-voice && $(SR_VOICE_ENV) cargo run --release -- serve $(ARGS)
|
|
|
|
run-sr-voice:
|
|
cd server/sr-voice && $(SR_VOICE_ENV) cargo run --release -- $(ARGS)
|
|
|
|
stop-sr-voice:
|
|
@lsof -ti :$(SR_VOICE_PORT) | xargs -r kill 2>/dev/null || true
|
|
@echo "Stopped sr-voice on port $(SR_VOICE_PORT)"
|
|
|
|
test-voice-mock:
|
|
@echo "Running voice pipeline test (mock sr-voice)..."
|
|
cd server && SR_VOICE_MOCK=1 cargo test --test voice_pipeline -- --nocapture
|
|
@echo "Results: .tmp/voice-test/results.txt"
|
|
|
|
test-voice-real:
|
|
@echo "Running voice pipeline test (real sr-voice + Gemma 2B)..."
|
|
@test -f server/sr-voice/target/release/sr-voice || { echo "Build sr-voice first: make build-sr-voice"; exit 1; }
|
|
@test -f server/models/gemma2.gguf || { echo "Model not found: server/models/gemma2.gguf"; exit 1; }
|
|
cd server && cargo test --test voice_pipeline -- --nocapture
|
|
@echo "Results: .tmp/voice-test/results.txt"
|
|
|
|
# --- Asset manifest ---
|
|
|
|
manifest:
|
|
@reach generate character-manifest
|
|
@echo "Manifest regenerated — commit client/assets/characters/manifest.json if changed."
|
|
|
|
# --- Diagrams ---
|
|
#
|
|
# SVG, not PNG: d2 emits SVG natively, while its PNG path wants a ~150 MB
|
|
# headless-Chromium download and prompts interactively. SVG also renders in
|
|
# Gitea and in clide (`clide draw --file <path.d2|.svg>`), diffs as text, and
|
|
# cut docs/diagrams/ from 17 MB to 2.8 MB.
|
|
#
|
|
# Do NOT use d2 `|md` blocks in a diagram: they emit an SVG <foreignObject>,
|
|
# which ImageMagick and flutter_svg both silently drop — the text is then in
|
|
# the file and invisible in every viewer except a browser. Use plain labels.
|
|
|
|
diagrams:
|
|
@for d in $$(find docs/diagrams -name '*.d2'); do \
|
|
d2 "$$d" "$${d%.d2}.svg" >/dev/null || exit 1; \
|
|
done
|
|
@echo "Diagrams rendered — commit any changed docs/diagrams/**/*.svg."
|
|
|
|
check-diagrams:
|
|
@fail=0; for d in $$(find docs/diagrams -name '*.d2'); do \
|
|
test -f "$${d%.d2}.svg" || { echo "unrendered: $$d"; fail=1; }; \
|
|
done; \
|
|
test $$fail -eq 0 || { echo "Run 'make diagrams'."; exit 1; }; \
|
|
echo "All diagrams rendered."
|
|
|
|
# --- Clean ---
|
|
|
|
clean:
|
|
cd server && cargo clean || true
|
|
rm -rf .cache/*
|
|
rm -rf client/reports
|
|
@echo "Clean complete."
|