Standardized YAML frontmatter on all 115 sprint briefing files across sprints 1-26 with title, description, type, status, sprint number, and team fields. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
6.5 KiB
title, description, type, status, sprint, team
| title | description | type | status | sprint | team |
|---|---|---|---|---|---|
| Sprint 19 — CI Briefing | Test runner scripts, protocol version handshake, IPC round-trip benchmark | sprint | archived | 19 | ci |
Sprint 19: Persist — CI Tasks
Goal: The player can save and resume a game session with per-game directories; the simulation tier system gains eviction and scope pinning; and the first test infrastructure ships with information boundary validation and IPC hardening.
Branch: ci
Agents: Hoshe (QA/CI), Oscar (networking)
Carry-over from Sprint 18
None.
New Tickets
| # | Title | Blocked by |
|---|---|---|
| #270 | Test runner bash scripts | — |
| #556 | Protocol version handshake: client | #555 (server) |
| #342 | IPC round-trip timing benchmark | #555, #556 |
| #271 | IPC serialization fixture files | #270 |
Use db/connectors/ticket show <id> for full details.
Key Decisions
decisions/architecture.md— D-020 (IPC architecture, MessagePack codec, SimBridge trait), D-030 (three-layer test architecture: fixture / mock-protocol / real-subprocess)
Notes
#270 — Test runner bash scripts
The test infrastructure has no standardized entry points for CI or agents to invoke. This ticket ships the runner layer.
What this ticket must deliver:
Six scripts at tests/:
tests/run-rust— runscargo testinserver/, exits 0/non-zero, JSON stdout summarytests/run-godot— runs GUT headlessly (godot --headless -s client/tests/run_gut.gd), exits 0/non-zerotests/run-ipc-fixtures— Layer 1: reads fixture files fromtests/fixtures/, validates via Rust + GDScript, exits 0/non-zerotests/run-ipc-protocol— Layer 2: runs mock subprocess protocol state machine teststests/run-ipc-integration— Layer 3: starts real server subprocess, runs full round-trip, kills ittests/run-all— invokes all five in order, collects exit codes, reports JSON summary
Script requirements per ticket description: exit code 0/non-zero, structured JSON stdout, accepts filter arguments (--filter test_name), no interactive input, whitelistable for Claude Code agents (no TTY prompts).
JSON stdout format (consistent across all scripts):
{"suite": "rust", "total": 42, "passed": 42, "failed": 0, "duration_ms": 1230}
These scripts are the entry points that make ci-server, make ci-client, and future CI pipelines call. Coordinate with Makefile targets in docs/DEVOPS.md.
#556 — Protocol version handshake: client
Blocked by #555 (server must send HandshakeMessage first).
What this ticket must deliver:
client/scripts/protocol/local_bridge.gd(orserver_process.gd): after starting the server subprocess, read the first framed message from the IPC channel- Validate it is a
HandshakeMessagewithprotocol_version == Protocol.PROTOCOL_VERSION(14) - If mismatch: log error "Protocol version mismatch: server=%d, client=%d", emit a
handshake_failedsignal, shut down the server process gracefully - If match: emit
handshake_complete, begin normal tick loop - Add a timeout: if no handshake message received within 5 seconds of process start, treat as mismatch
Current state: client/scripts/protocol/protocol.gd already checks version in decode_snapshot() and logs a mismatch. That check is per-snapshot. The handshake is the startup-time equivalent — validate once at connection, not per tick.
Files: client/scripts/protocol/local_bridge.gd, client/scripts/protocol/server_process.gd.
#342 — IPC round-trip timing benchmark
Sprint exit criterion. Measures the complete latency path from server serialization to client scene update.
What this ticket must deliver:
- A benchmark script
tests/run-ipc-benchmarkthat:- Starts the server subprocess
- Waits for handshake (#555/#556)
- Sends N
PlayerInputmessages (N = 100 by default) - Measures from
rmp_serde::to_vec(server) to scene update completion (client) - Reports p50/p95/p99 latencies in milliseconds
- Flags if any percentile exceeds 5ms threshold
- Output JSON:
{"p50_ms": 1.2, "p95_ms": 2.8, "p99_ms": 4.1, "threshold_ms": 5, "passed": true} - The benchmark is run as part of
tests/run-ipc-integrationin Layer 3
Implementation approach: server-side timestamps in ObserverSnapshot (add server_emit_tick_ms field, stripped in production builds), client records receive timestamp via Time.get_ticks_msec(). Delta = client receive - server emit.
Blocked by #555 and #556 — benchmark requires a working handshake before timing can start cleanly.
#271 — IPC serialization fixture files
Layer 1 test data: pre-generated .msgpack fixture files that both Rust and GDScript can read to verify cross-language serialization compatibility.
What this ticket must deliver:
- A Rust binary (or test in
server/src/) that generates fixtures totests/fixtures/:snapshot_minimal.msgpack— minimal validObserverSnapshot(version=14, tick=0, one entity)snapshot_full.msgpack— all optional fields populated (monologue, dialogue, inventory, POIs, KG dump)player_input_move.msgpack—PlayerInput { tick: 1, action: MoveNorth }player_input_interact.msgpack—PlayerInput { tick: 2, action: Interact { target: 99, verb: "Talk" } }malformed.msgpack— intentionally truncated bytes (tests error handling)
- A GDScript test
client/tests/test_ipc_fixtures.gdthat reads each.msgpackfixture file, decodes viaProtocol.decode_snapshot()/Protocol.decode_player_input(), and asserts expected field values - Cross-language verification: the same byte stream decoded by both Rust and GDScript must produce identical field values
The fixture generator is run once (manually or in CI pre-step) to produce the committed .msgpack files. The files live at tests/fixtures/ and are committed to the repo.
Blocked by #270 — fixture tests are invoked by tests/run-ipc-fixtures.
Dependency Chain
#555 (server: protocol handshake) → #556 (ci: protocol handshake: client)
#555 + #556 → #342 (IPC benchmark: requires working handshake)
#270 (test runner scripts) → #271 (fixture files: invoked by run-ipc-fixtures)
Parallel starts: #270, #555 (server-side) — both unblocked week 1
#556 starts after #555 is at review
#271 starts after #270 merges
#342 starts after #555 + #556 both land
PR Workflow
When ready to submit, create a PR with tea CLI. All flags are required to avoid TTY prompts (see CLAUDE.md "Gitea access" section):
tea pr create --repo jpmschweitzer/settled-reach --login schweitz --title "feat(ci): description" --description "body" --base main --head ci