feat(client): sprint 9 gauntlet — room timer, WRONG button, 24 tests #34

Closed
jpmschweitzer wants to merge 0 commits from client into main
Owner

Summary

Sprint 9 client remaining deliverables: both blocked tickets now complete.

  • #496 — Gauntlet room timer + personal bests. GauntletHUD in UILayer shows TIMER: MM:SS (PB: MM:SS). Timer starts on room entry, resets on room change, persists stats to user://gauntlet-stats.json. Session summary on disconnect. Hidden in non-gauntlet mode (anti-tedium guard).
  • #495 — WRONG button (F12) MVP. Bug report capture: F12 pauses sim, shows modal prompt on ModalLayer (CL 30), saves snapshot.json + render.txt + description.txt to user://bug-reports/gauntlet-t{tick}-{timestamp}/. Esc cancels. Double-activation guard.
  • 24 new tests — GauntletHUD lifecycle (16: timer, PB, visibility, room change, session tracking, roundtrip) + BugReportDialog (8: pause/unpause, wire guard, text render with entities/monologue/dialogue, empty snapshot edge case). Anti-tedium assertions now falsifiable.

Tickets

# Title Status
#496 Room timer + personal bests Done
#495 WRONG button (F12) MVP Done

Test plan

  • make test-client passes headless (all new + existing tests green)
  • GauntletHUD hidden when gauntlet_mode absent from snapshot
  • GauntletHUD visible + timer running when gauntlet_mode: true + room_id present
  • F12 activates BugReportDialog, sends Pause, Esc cancels with Unpause
  • BUG_REPORT action not sent on wire (client-only guard)
  • No regressions in existing 315 tests

🤖 Generated with Claude Code

## Summary Sprint 9 client remaining deliverables: both blocked tickets now complete. - **#496** — Gauntlet room timer + personal bests. GauntletHUD in UILayer shows `TIMER: MM:SS (PB: MM:SS)`. Timer starts on room entry, resets on room change, persists stats to `user://gauntlet-stats.json`. Session summary on disconnect. Hidden in non-gauntlet mode (anti-tedium guard). - **#495** — WRONG button (F12) MVP. Bug report capture: F12 pauses sim, shows modal prompt on ModalLayer (CL 30), saves `snapshot.json` + `render.txt` + `description.txt` to `user://bug-reports/gauntlet-t{tick}-{timestamp}/`. Esc cancels. Double-activation guard. - **24 new tests** — GauntletHUD lifecycle (16: timer, PB, visibility, room change, session tracking, roundtrip) + BugReportDialog (8: pause/unpause, wire guard, text render with entities/monologue/dialogue, empty snapshot edge case). Anti-tedium assertions now falsifiable. ## Tickets | # | Title | Status | |---|-------|--------| | #496 | Room timer + personal bests | Done | | #495 | WRONG button (F12) MVP | Done | ## Test plan - [ ] `make test-client` passes headless (all new + existing tests green) - [ ] GauntletHUD hidden when gauntlet_mode absent from snapshot - [ ] GauntletHUD visible + timer running when gauntlet_mode: true + room_id present - [ ] F12 activates BugReportDialog, sends Pause, Esc cancels with Unpause - [ ] BUG_REPORT action not sent on wire (client-only guard) - [ ] No regressions in existing 315 tests 🤖 Generated with [Claude Code](https://claude.com/claude-code)
jpmschweitzer added 4 commits 2026-02-18 10:54:17 +01:00
GauntletHUD in UILayer shows TIMER: MM:SS (PB: MM:SS). Timer starts on
room entry, resets on room change, records personal bests to
user://gauntlet-stats.json. Session summary printed on disconnect.
Hidden in non-gauntlet mode (anti-tedium guard).

Adds room_id and gauntlet_mode fields to GameState, parsed from
ObserverSnapshot. Main.gd wires update_from_state() and finalize().

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
F12 pauses simulation, shows modal LineEdit prompt, saves three files
to user://bug-reports/gauntlet-t{tick}-{timestamp}/: snapshot.json
(full ObserverSnapshot), render.txt (simplified client-side text
render), description.txt (tester notes + tick/room/stance metadata).
Esc cancels without saving. Double-activation guard prevents stacking.

BUG_REPORT action added to InputMapper with wire guard in SimBridge
(client-only, never sent to server). Dialog on ModalLayer (CL 30).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace stub F12 tests with BugReportDialog integration tests (dialog
exists, activates on action, pause/unpause, wire guard, text render
with entities/monologue/dialogue, empty snapshot edge case). Add 16
GauntletHUD tests (format_time, visibility toggle, timer lifecycle,
room change reset, personal bests record/overwrite/preserve, null room,
timer paused when hidden, finalize, session attempts, snapshot
roundtrip). Anti-tedium assertions now falsifiable against real
GameState.room_id and gauntlet_mode properties.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Author
Owner

Review: client -> main (PR #34, type: code)

Hoshe (Code Quality): REQUEST_CHANGES

Two features well-structured with 24 tests. Three warnings need fixing.

# File Severity Issue
1 gauntlet_hud.gd:update_from_state warning Variant passed to String-typed parameter — runtime type error in strict mode
2 gauntlet_hud.gd:update_from_state warning _current_room_id not cleared on null transition — re-entry to same room skips timer restart
3 bug_report_dialog.gd:_save_report warning Silent file-write failures — no feedback when dir creation or file open fails
4 gauntlet_hud.gd:line 5 suggestion Doc says tests/gauntlet-stats.json, actual path is user://gauntlet-stats.json
5 test_anti_tedium.gd suggestion No test covers file-write failure path in _save_report

Tyre (Architecture): APPROVE

Correct D-020 client-server separation, proper CanvasLayer 30 placement, BUG_REPORT correctly excluded from wire protocol.

# File Severity Issue
1 gauntlet_hud.gd:_on_room_change suggestion Variant/String type mismatch on parameter — safe but strict-mode warning
2 gauntlet_hud.gd:STATS_PATH suggestion user:// root will collide with future save data — namespace to user://dev/
3 bug_report_dialog.gd:_save_report suggestion print() inconsistent with codebase style (push_warning/push_error)
4 test_anti_tedium.gd suggestion _action_enum_to_wire emits false-alarm push_warning for known client-only actions

Verdict: CHANGES REQUESTED

## Review: client -> main (PR #34, type: code) ### Hoshe (Code Quality): REQUEST_CHANGES Two features well-structured with 24 tests. Three warnings need fixing. | # | File | Severity | Issue | |---|------|----------|-------| | 1 | gauntlet_hud.gd:update_from_state | warning | `Variant` passed to `String`-typed parameter — runtime type error in strict mode | | 2 | gauntlet_hud.gd:update_from_state | warning | `_current_room_id` not cleared on null transition — re-entry to same room skips timer restart | | 3 | bug_report_dialog.gd:_save_report | warning | Silent file-write failures — no feedback when dir creation or file open fails | | 4 | gauntlet_hud.gd:line 5 | suggestion | Doc says `tests/gauntlet-stats.json`, actual path is `user://gauntlet-stats.json` | | 5 | test_anti_tedium.gd | suggestion | No test covers file-write failure path in `_save_report` | ### Tyre (Architecture): APPROVE Correct D-020 client-server separation, proper CanvasLayer 30 placement, BUG_REPORT correctly excluded from wire protocol. | # | File | Severity | Issue | |---|------|----------|-------| | 1 | gauntlet_hud.gd:_on_room_change | suggestion | Variant/String type mismatch on parameter — safe but strict-mode warning | | 2 | gauntlet_hud.gd:STATS_PATH | suggestion | `user://` root will collide with future save data — namespace to `user://dev/` | | 3 | bug_report_dialog.gd:_save_report | suggestion | `print()` inconsistent with codebase style (`push_warning`/`push_error`) | | 4 | test_anti_tedium.gd | suggestion | `_action_enum_to_wire` emits false-alarm `push_warning` for known client-only actions | ### Verdict: CHANGES REQUESTED
jpmschweitzer added 1 commit 2026-02-18 11:07:01 +01:00
- Cast Variant to String via str() before passing to _on_room_change
- Clear _current_room_id on null room transition (fixes re-entry skip)
- Add push_error for failed dir creation and file writes in _save_report
- Fix docstring: tests/gauntlet-stats.json → user://dev/gauntlet-stats.json
- Namespace stats path to user://dev/ to avoid save data collision
- Replace print() with push_warning in _save_report (codebase consistency)
- Downgrade client-only wire guard from push_warning to silent return

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Author
Owner

Re-Review: client -> main (PR #34, type: code) — Post-Fix

Hoshe (Code Quality): APPROVE

All 3 warnings FIXED. Suggestions addressed.

# Original Item Status
1 Variant/String type mismatch FIXED — str(new_room_id) cast
2 _current_room_id not cleared on null FIXED — explicit null assignment
3 Silent file-write failures FIXED — push_error on all failure paths
4 Doc path mismatch FIXED
5 No file-write failure test REMAINING (suggestion)

Tyre (Architecture): APPROVE

All 4 items FIXED. Surgical fixes, no regressions.

# Original Item Status
1 Variant/String mismatch FIXED — str() cast
2 STATS_PATH namespace FIXED — user://dev/
3 print() style FIXED — push_warning/push_error
4 False-alarm push_warning FIXED — silent return

Verdict: APPROVED

## Re-Review: client -> main (PR #34, type: code) — Post-Fix ### Hoshe (Code Quality): APPROVE All 3 warnings FIXED. Suggestions addressed. | # | Original Item | Status | |---|--------------|--------| | 1 | Variant/String type mismatch | FIXED — `str(new_room_id)` cast | | 2 | `_current_room_id` not cleared on null | FIXED — explicit null assignment | | 3 | Silent file-write failures | FIXED — `push_error` on all failure paths | | 4 | Doc path mismatch | FIXED | | 5 | No file-write failure test | REMAINING (suggestion) | ### Tyre (Architecture): APPROVE All 4 items FIXED. Surgical fixes, no regressions. | # | Original Item | Status | |---|--------------|--------| | 1 | Variant/String mismatch | FIXED — `str()` cast | | 2 | STATS_PATH namespace | FIXED — `user://dev/` | | 3 | `print()` style | FIXED — `push_warning`/`push_error` | | 4 | False-alarm `push_warning` | FIXED — silent return | ### Verdict: APPROVED
jpmschweitzer closed this pull request 2026-02-18 11:14:14 +01:00

Pull request closed

This pull request cannot be reopened because the branch was deleted.
Sign in to join this conversation.
No Reviewers
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: jpmschweitzer/settled-reach#34