--- title: "Sprint 9 — Client Briefing" description: "Client P2/P3 Gauntlet tests, WRONG button MVP, room timer, MessagePack fix" type: sprint status: archived sprint: 9 team: "client" --- # Sprint 9: Gauntlet — Client Tasks **Goal:** Build the test infrastructure backbone — test client binary, Gauntlet rooms 1-3, golden file suite, and client QA harness — so every future sprint can be validated end-to-end. **Branch:** `client` **Agents:** Stig (client dev), Hoshe (QA) ## New Tickets | # | Title | Blocked by | |---|-------|------------| | #492 | Client P2 tests: remaining camera (5), entity alpha/color (4), UI (7) | — | | #493 | Client P3 tests: z-layer ordering (4), entity lerp (3), Tyre additions (5) | — | | #494 | Client anti-tedium tests: bug report capture, progress hidden when not gauntlet | — | | #495 | WRONG button (F12) MVP: snapshot + text render + description | #481 (server), #490 (server) | | #496 | Room timer + personal bests | #487 (server) | | #516 | Fix MessagePack int_64 encoder dead code branch | — | ## Key Decisions - `decisions/architecture.md` — D-020 (ObserverSnapshot protocol, client is pure renderer), D-030 (gdUnit4 test framework, JSON output, headless stable) - `decisions/architecture.md` — D-068 (5-bus AudioManager — audio_manager.gd exists), D-066 (dual-scale grid: TILE_SIZE in constants.gd maps 0.5m sim tiles) - `decisions/scope.md` — D-053 (movement stances — entity lerp speed tuned per stance in entity_renderer.gd) ## Notes ### #492 — Client P2 tests: remaining camera (5), entity alpha/color (4), UI (7) What exists: `client/scripts/rendering/entity_renderer.gd` handles entity alpha dimming (Peripheral vision = `Constants.PERIPHERAL_ALPHA`), entity color by kind via `Constants.color_for_entity_kind()`. Camera logic is in `client/scripts/` — check for a camera or follow node in the main scene. Existing tests at `client/tests/test_rendering.gd` and `client/tests/test_camera_anchor.gd` provide patterns. What to deliver: 16 new gdUnit4 tests split across categories: - Camera (5): smoothing convergence, zoom levels, viewport clamping, follow target tracking, no-panning constraint (D-014) - Entity alpha/color (4): `Peripheral` -> `PERIPHERAL_ALPHA`, `Forward` -> alpha 1.0, NPC color by relationship state, Player color constant - UI (7): monologue display visible/hidden, interaction panel shows nearest verb, inventory HUD shows carried items, dialogue overlay appears on `current_dialogue` set, pause indicator on `TickRate::Paused`, recognition blob rendered for `pending_recognitions`, fog overlay covers occluded tiles Use `GdUnitSceneRunner` for scene lifecycle tests. Follow patterns in `client/tests/test_p0_regressions.gd` and `client/tests/test_client_p1.gd`. ### #493 — Client P3 tests: z-layer ordering (4), entity lerp (3), Tyre additions (5) What exists: `entity_renderer.gd` implements framerate-independent lerp with `LERP_SPEED = 12.0` (exponential smoothing). `_entity_targets` Dictionary tracks target pixel positions. `tile_renderer.gd` and `world_renderer.gd` handle tile layers. What to deliver: 12 new gdUnit4 tests: - Z-layer ordering (4): floors render below walls, walls below entities, entities below UI, verify draw order via node tree position or `z_index` - Entity lerp (3): entity node position starts at spawn point (no lerp on first appear), position moves toward `_entity_targets` over time (mock delta), position converges within ~0.3s of real time at `LERP_SPEED = 12.0` - Tyre additions (5): recognition transition timing (grey blob -> colored entity over `total_delay_ticks`), facing indicator rotation matches `player_facing` from snapshot, sprint snappiness (lerp arrives faster at higher lerp weight), plus two further items from Tyre's round3 notes — check `db/connectors/ticket show 493` for full list ### #494 — Client anti-tedium tests: bug report capture, progress hidden when not gauntlet What exists: Sprint 9 introduces the WRONG button F12 MVP (#495) and room timer (#496). These features have "anti-tedium" guards — the progress/timer UI must not appear in non-Gauntlet mode. What to deliver: 2 regression tests: - F12 bug report capture: when F12 is pressed, client pauses, capture dialog appears, saved files are produced (mock the file system or check paths are attempted) - Gauntlet progress UI: in non-Gauntlet mode (no `gauntlet_mode` flag or room metadata), the room timer and personal-bests overlay must not be visible These are client-side regression tests. Add to `client/tests/test_p0_regressions.gd` or a new `test_anti_tedium.gd`. ### #495 — WRONG button (F12) MVP: snapshot + text render + description What exists: Blocked by #481 (server text renderer, provides `format_snapshot_text()`) and #490 (server room reset — context for room metadata in capture). `game_state.gd` holds `current_snapshot` (full Dictionary), `current_tick`, `player_stance`. The `sim_bridge.gd` handles IPC. Audio is in `audio_manager.gd`. What to deliver: F12 key binding in `client/scripts/autoloads/input_mapper.gd` (or main scene). On press: 1. Send `PlayerAction::Pause` via sim_bridge 2. Show a one-line prompt: "Describe the issue:" (simple LineEdit dialog) 3. On confirm: save three files to `tests/bug-reports/YYYY-MM-DD_HH-MM-SS/`: - `snapshot.json` — `current_snapshot` as JSON - `render.txt` — text render output from server's `format_snapshot_text()` (request via a special IPC call, or reproduce in GDScript using snapshot data) - `description.txt` — tester's typed description + tick/room/seed metadata 4. Send `PlayerAction::Unpause` Gotcha: `format_snapshot_text()` is a server-side Rust function (#481). For MVP, reproduce a simplified version client-side in GDScript using `current_snapshot` data, so this ticket is not blocked at runtime even if the test client binary isn't connected. Full fidelity (exact server text output) is a stretch goal. ### #496 — Room timer + personal bests What exists: Blocked by #487 (Gauntlet rooms — provides room_id per snapshot). `game_state.gd` tracks `current_tick`. The `ObserverSnapshot` does not currently include `room_id` — this needs a server-side field or derivation from entity positions. What to deliver: Client-side GDScript in the main scene or a new `gauntlet_hud.gd`: - Timer label: `TIMER: MM:SS` displayed in corner - Timer starts on room entry event (snapshot indicates new room), resets on room reset trigger - Personal bests loaded from / saved to `tests/gauntlet-stats.json` (FileAccess) - Session summary printed on disconnect - UI hidden entirely in non-Gauntlet mode Coordinate with server team: `ObserverSnapshot` needs a `room_id: Option` field or equivalent (may be added as part of #487/#488 server work). Use `#[serde(default)]` on the server side so the client can handle both old and new snapshots. ### #516 — Fix MessagePack int_64 encoder dead code branch What exists: The GDScript MessagePack encoder has a dead code branch for `int_64` encoding. Identified as a bug in Sprint 8 backlog scan. Location: likely in the MessagePack encode/decode utility in `client/scripts/protocol/` — check for the file handling integer encoding. What to deliver: Fix the dead code branch, add a test case for the int_64 path, verify it encodes and decodes correctly. Small ticket (~0.5d). Do this early in the sprint as a warm-up before the larger test suites. ## Dependency Chain ``` #516 (msgpack fix) — standalone, start early #492 (P2 tests) — standalone, parallel #493 (P3 tests) — standalone, parallel #494 (anti-tedium tests) — standalone (can stub #495 behavior) #495 (WRONG button F12) — blocked by #481 + #490 (server) -> (unblocks #507 in Sprint 10) #496 (room timer) — blocked by #487 (server) ``` ## 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): ```bash tea pr create --repo jpmschweitzer/settled-reach --login schweitz --title "feat(client): sprint 9 gauntlet — QA harness and F12 WRONG button" --description "body" --base main --head client ```