Files
settled-reach/docs/DEVOPS.md
T
jpmschweitzerandClaude Opus 4.6 f06c8be313 feat(ci): add make pre-pr target and fixture staleness check
Implements make pre-pr chain: lint -> build -> test -> content
validation -> fixture staleness. Branch-specific variants:
pre-pr-server, pre-pr-client, pre-pr-content.

Fixture staleness is a blocker (exit 1) — stale fixtures cause
false positive client tests. Spec from hoshe-round3.md Section 5.

Tickets: #460, #465

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 22:43:40 +01:00

241 lines
8.3 KiB
Markdown

# 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 ticketing + decisions database and connectors
```
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
```bash
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
```bash
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
```bash
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
```bash
make test # Run all tests
make test-server # cargo test in server/
make test-client # gdUnit4 tests (headless runner pending)
```
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).
### Lint
```bash
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:
```bash
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:
```bash
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:
```bash
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:
```bash
make fixtures
git add client/tests/fixtures/
git commit -m "chore(fixtures): regenerate for protocol vN"
```
The fixture staleness check is a **blocker** (exit 1) — stale fixtures cause false positive client tests.
### Clean
```bash
make clean # Remove build artifacts and .cache/ contents
```
### Content Validation
```bash
make validate-content # Validate content YAML against JSON schemas
make check-fact-ids # Check fact_id references against knowledge catalogs
```
`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_id` reference that doesn't match a canonical definition.
## Pre-commit Hooks
Git hooks are stored in `.config/hooks/` (version-controlled). Activate them with:
```bash
make setup # Includes hook installation
make setup-hooks # Just hooks
```
Or manually:
```bash
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:
```bash
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:
1. **Unit tests** — Inside `server/` (Rust `#[cfg(test)]`) and `client/` (gdUnit4). Test individual systems in isolation.
2. **Integration tests** — Inside `server/tests/` (Rust) and `tests/` (cross-boundary). Test system interactions, IPC serialization round-trips.
3. **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:
```bash
db/connectors/sqlite-query "SELECT * FROM tickets WHERE status='open'"
db/connectors/sqlite-exec "UPDATE tickets SET status='done' WHERE id=1"
```
## Qdrant / Document Search
```bash
db/connectors/qdrant-search "asymmetric information design"
db/connectors/qdrant-index docs/briefings/tyre.md
db/connectors/qdrant-health
db/connectors/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.
```bash
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 `/commit` skill (`.claude/skills/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