Files
settled-reach/docs/sprints/sprint-9/client.md
T
jpmschweitzerandClaude Opus 4.6 85a3e87d36 docs(sprints): add Sprint 9 Gauntlet briefing files
Sprint 9 theme: Gauntlet — test infrastructure backbone with test
client binary, Gauntlet rooms 1-3, golden file suite, and client QA
harness. 23 tickets across server (9), client (6), CI (6), audio (2).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 01:32:28 +01:00

7.8 KiB

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.jsoncurrent_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<String> 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):

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