12 KiB
title, description, type, status
| title | description | type | status |
|---|---|---|---|
| DevOps Procedures | Build, test, lint, and CI procedures for the Settled Reach project — Makefile targets, worktree setup, server/client builds | architecture | active |
DevOps Procedures
Operational procedures for building, testing, and running The Settled Reach.
Repository Layout
client/ Godot 4 client (GDScript, scenes, assets)
server/ Rust/bevy_ecs simulation server
tooling/ Build tools, scripts, asset pipelines
tests/ Integration and end-to-end tests (cross-boundary)
decisions/ Decision domain files (source of truth for all D/Q/R entries)
.config/ Configuration files (linters, formatters, CI)
.cache/ Local caches for testing/linting (gitignored)
docs/ Design, architecture, briefings, workshops
db/ SQLite schema + seed data (connectors at tooling/db/)
Unit tests live inside their respective projects (server/ uses #[cfg(test)] inline + tests/ directory per D-030). The top-level tests/ directory is for integration tests that cross the client-server boundary (IPC round-trip, serialization fixtures, divergence tests).
Prerequisites
| Tool | Version | Purpose |
|---|---|---|
| Rust (via rustup) | stable | Server compilation, clippy, rustfmt (auto-installed by make setup) |
| Godot | 4.x | Client editor and runtime (auto-installed to ~/bin/ by make setup) |
| Python | 3.x | Tooling scripts, db connectors |
| Make | any | Task runner (see below) |
| curl | any | Downloading Godot |
| unzip | any | Extracting Godot |
Makefile Targets
All development operations go through the top-level Makefile. Run make with no arguments for a summary.
Setup
make setup # Install/verify all dev dependencies
GODOT_VERSION=4.4 make setup # Pin a specific Godot version
Downloads and installs Godot to ~/bin/godot4, installs Rust clippy + rustfmt, and verifies Python/curl/unzip. Skips the download if the correct version is already installed. The GODOT_VERSION variable defaults to 4.6 and can be overridden.
Build
make build # Build both client and server
make build-server # cargo build in server/
make build-client # Client builds are editor-managed (prints guidance)
Run
make server # cargo run in server/
make client # Launch Godot with client/ project
The server must be running before the client connects (subprocess launch will be automated later per D-020).
Test
make test # Run all tests (test-server + test-client)
make test-server # Rust tests via tests/run-rust (cargo nextest, JSON summary)
make test-client # Godot tests via tests/run-godot (gdUnit4 headless, JSON summary)
The IPC test layers (D-030) have dedicated targets:
make test-ipc-fixtures # Layer 1: serialization round-trip fixtures
make test-ipc-protocol # Layer 2: mock LocalBridge protocol tests
make test-ipc-integration # Layer 3: real subprocess round-trip (+ benchmark when ready)
make test-ipc-benchmark # IPC latency benchmark (blocked: #555/#556 handshake)
Each tests/run-* script outputs a JSON summary to stdout and streams progress to stderr:
{"suite":"rust","total":42,"passed":42,"failed":0,"duration_ms":1230}
All scripts accept --filter <name> to run a subset of tests. They are whitelistable for agent use (no TTY prompts, no interactive input).
Server tests use Rust's built-in test framework with #[cfg(test)] inline tests and tests/ integration tests (D-030). Client tests use gdUnit4 (D-030).
Cross-Encoder Fixtures
make fixtures # Regenerate Rust->GDScript fixtures (server/tests/gen_fixtures.rs)
make fixtures-client # Generate GDScript->Rust fixtures + verify Rust decoder (#475)
The bidirectional protocol is validated by two sets of committed fixtures:
- Rust encodes, GDScript decodes:
client/tests/fixtures/msgpack/(generated bymake fixtures) - GDScript encodes, Rust decodes:
server/tests/fixtures/gdscript/(generated bymake fixtures-client)
Regenerate both after any protocol change. Commit the updated fixtures alongside the code change.
Troubleshooting fixture failures:
make fixtures-clientfails with encode errors: Check thatclient/addons/messagepack/messagepack.gdis up to date. The script exits non-zero on any encode failure.gdscript_generated_fixtures_deserializefails: Fixtures inserver/tests/fixtures/gdscript/are stale or corrupted. Re-runmake fixtures-clientand commit the updated files.- Fixture staleness in
make pre-pr: Protocol changed but fixtures were not regenerated. Runmake fixtures && make fixtures-client, then commit bothclient/tests/fixtures/andserver/tests/fixtures/gdscript/.
Golden File Management
make golden-diff # Show diff if golden file output has changed
make golden-update # Regenerate golden file and stage for commit
The golden file (server/tests/golden/proof_room_tick_10.json) is a committed snapshot of ObserverSnapshot output after a deterministic 10-tick replay. It catches unintentional changes to simulation output.
Workflow after intentional simulation changes:
- Run
make golden-diffto see what changed - Review the diff — confirm changes are expected
- Run
make golden-updateto regenerate and stage the new golden file - Commit the updated golden file alongside your simulation change
golden-diff exits 1 if the golden file has changed (useful in scripts). golden-update regenerates the file and runs git add but does not commit — the developer reviews and commits manually.
Lint
make lint # Run all linters
make lint-server # clippy (deny warnings) + rustfmt --check
make lint-client # gdlint/gdformat (pending setup)
CI (Local)
Run the full CI pipeline locally before pushing:
make ci # Both pipelines
make ci-server # lint-server → build-server → test-server
make ci-client # lint-client → build-client → test-client
CI targets chain lint → build → test sequentially. A failure in any stage stops the pipeline.
Pre-PR Checks
Before pushing a PR, run:
make pre-pr
This runs all checks in order: lint → build → test → content validation → fixture staleness. Total runtime ~2.5 minutes (incremental build), under 3 minutes clean.
For branch-specific checks:
make pre-pr-server # Server changes: lint, build, test, fixture staleness
make pre-pr-client # Client changes: lint, build, test
make pre-pr-content # Content changes: schema + cross-reference validation
If pre-pr-fixtures fails, your protocol changes require fixture regeneration:
make fixtures
git add client/tests/fixtures/
git commit -m "chore(fixtures): regenerate for protocol v8"
The fixture staleness check is a blocker (exit 1) — stale fixtures cause false positive client tests.
Clean
make clean # Remove build artifacts and .cache/ contents
Content Validation
make validate-content # Validate content YAML against JSON schemas
make check-fact-ids # Check fact_id references against knowledge catalogs
Gauntlet Checklists
make checklist-validate # Validate checklist YAML against schema (standalone)
make checklist-generate # Validate + print per-room condition summary
Checklists live at content/gauntlet/rooms/{room_id}/checklist.yaml (per-room) and content/gauntlet/cross_room_checks.yaml (cross-room). Each condition is evaluable from an ObserverSnapshot.
7 condition types: player_near, player_facing, entity_present, entity_absent, expected_monologue, expected_dialogue, expected_interaction_verb.
Schema: content/_schema/checklist.schema.json. The checklist format feeds into #503 (client auto-checklist progress tracking).
check-fact-ids operates in two modes:
- Advisory — when knowledge catalogs (
content/global/knowledge/*.yaml) have no fact definitions yet: lists referenced fact_ids and exits cleanly. - Enforcing — when catalogs are populated: fails on any
fact_idreference that doesn't match a canonical definition.
Pre-commit Hooks
Git hooks are stored in .config/hooks/ (version-controlled). Activate them with:
make setup # Includes hook installation
make setup-hooks # Just hooks
Or manually:
git config core.hooksPath .config/hooks
Active checks:
| Check | Script | Behavior |
|---|---|---|
| fact_id validation | tooling/check-fact-ids |
Warns if catalogs are stubs; fails on unknown fact_ids when populated |
The core.hooksPath setting uses a relative path (.config/hooks) that resolves per worktree, so it works correctly across all worktrees in the repository.
To bypass hooks in an emergency:
git commit --no-verify -m "fix: emergency hotfix"
Configuration Files
The .config/ directory holds shared configuration for linters, formatters, and CI. Examples of what goes here:
- Clippy configuration overrides
- gdlint/gdformat rules
- CI workflow definitions (before moving to
.github/workflows/) - Editor config templates
Project-specific config that lives in subdirectories (e.g., server/Cargo.toml, client/project.godot) stays in those directories. .config/ is for cross-cutting or shared configuration.
Cache Directory
.cache/ is gitignored and used for:
- Test result caches
- Linter caches
- Build artifact caches (if configured)
- Coverage reports
Agents and CI jobs can write freely to .cache/ without polluting the working tree. make clean clears it.
Testing Architecture (D-030)
Three-layer testing strategy:
- Unit tests — Inside
server/(Rust#[cfg(test)]) andclient/(gdUnit4). Test individual systems in isolation. - Integration tests — Inside
server/tests/(Rust) andtests/(cross-boundary). Test system interactions, IPC serialization round-trips. - Fixture-based tests — IPC serialization fixture files in
tests/for protocol regression testing. Known-good MessagePack payloads verified against both sides.
Key components:
- CauseChain (production ECS component) — Tracks causal attribution for testable observation sequences (D-030).
- Deterministic replay — Server simulation is deterministic given the same seed + input sequence. Replay logs enable regression testing (#201, critical).
SQLite Access
Never use the sqlite3 CLI — it crashes in Claude Code (std::bad_alloc).
Use wrapper scripts:
tooling/db/sqlite-query "SELECT * FROM tickets WHERE status='open'"
tooling/db/sqlite-exec "UPDATE tickets SET status='done' WHERE id=1"
Qdrant / Document Search
tooling/db/qdrant-search "asymmetric information design"
tooling/db/qdrant-index docs/briefings/tyre.md
tooling/db/qdrant-health
tooling/db/qdrant-count
Decisions System
Decisions are split into domain files under decisions/ (see decisions/README.md for the full index). A SQLite index table syncs metadata for cross-referencing and querying.
make decisions-sync # Parse decisions/*.md into SQLite
make decisions-coverage # Decision-to-ticket coverage by domain
make decisions-active # List all active confirmed decisions
make decisions-orphan # Decisions without implementing tickets
The sync runs automatically as part of make setup and via pre-commit hook. Markdown files are the source of truth; the DB is a derived index.
Commit Conventions
See the /git-commit skill (.claude/skills/git-commit/) for full details. Summary:
- Conventional commits:
type(scope): summary - Types:
feat,fix,refactor,chore,docs,data,loc - Scopes match project subsystems:
client,server,engine,simulation,ui,audio,meta, etc. - Imperative mood, lowercase, no period, max 72 chars
- CHANGELOG.md updated after each commit group