Files
settled-reach/docs/workshops/test-architecture/ozzie-round2.md
T
jpmschweitzerandClaude Opus 4.6 a87c95a6eb docs(workshops): complete QA test architecture workshop
3-round workshop with 7 agents (Tyre, Dudley, Stig, Hoshe,
Justine, Gestalt, Ozzie) plus Qatux documenting. Produced:

- 59-item prioritized test backlog (60 tickets under epic #455)
- Gauntlet test world spec: 7 rooms + hub, 48 entities
- Test client binary spec (tooling/test-client/)
- Determinism fixes (3 patches, ~22 lines)
- Server --test-mode + --port 0 design
- Content cross-reference validation (9 checks)
- make pre-pr pipeline (6-step)
- 38 client tests prioritized
- Anti-tedium features (reset plate, hub teleport, WRONG button)
- Human tester walkthrough
- CI pipeline design (deferred but documented)

Sprint 8 scope: ~17.75 team-days across 26 tickets.

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

29 KiB

Ozzie — Round 2: Test Client UX + Anti-Tedium Specs

Workshop: QA Strategy & Test Architecture Track: 1 (Test World Design) — Human Tester Experience Date: 2026-02-17


1. Test Client Text Output Format

The test client is a Rust binary that connects to the server via TCP, receives ObserverSnapshots, and renders them as text in the terminal. This is the human tester's "eyes" when they can't (or don't want to) run the full Godot client.

Display Mode: Live-Updating Terminal (not file dumps)

Live-updating. Not per-tick dumps to a file.

Here's why: a tester watching text scroll by can react in real time. They see the NPC move, they see the fog update, they see the monologue fire. Dumping to a file means the tester has to stop the server, open the file, find the relevant tick, and compare. That's a context switch. Context switches kill testing momentum.

Architecture: The test client uses a terminal UI library (crossterm or similar) to maintain a fixed-layout display that refreshes every tick. Not a TUI framework — just cursor positioning and ANSI escape codes. The display is split into sections that update in-place.

But ALSO log to file. Every tick's text output is appended to gauntlet-session-{timestamp}.log. The live display is for the tester's eyes. The log is for the WRONG button's bug report (see Section 2.5). Both exist simultaneously.

Terminal Layout

╔══════════════════════════════════════════════════════════════════════╗
║ GAUNTLET TEST CLIENT v0.1            Tick: 42  TickRate: Full      ║
║ Room: Occlusion Corridor             Seed: 42  Session: 00:01:23  ║
╠══════════════════════════════════════════════════════════════════════╣
║ PLAYER (15,10) → East | Walk | HP: -- | Inventory: 2/9            ║
╠══════════════════════════════════════════════════════════════════════╣
║ ENTITIES                                                           ║
║  ● npc:guard-1    (18,10) Fwd   Neutral (#4a9ebb)  VISIBLE  d=3  ║
║  ◐ npc:worker-2   (20,10) Fwd   Unknown (#4a9ebb)  REMEMBERED d=5 ║
║  ✕ npc:hidden-1   (19,12) ---   Unknown (#4a9ebb)  BLOCKED        ║
║    └─ wall at (17,10) blocks LOS                                   ║
╠══════════════════════════════════════════════════════════════════════╣
║ FOG  Clear:31 | Peripheral:12 | Deep:58 | Map:89 | Dark:312       ║
╠══════════════════════════════════════════════════════════════════════╣
║ SOUND                                                              ║
║  🔊 footsteps ~(22,10) — 2 entities, unhurried [MEDIUM RANGE]     ║
║     └─ visual indicator rendered at fog edge (no audio asset)      ║
╠══════════════════════════════════════════════════════════════════════╣
║ COGNITION                                                          ║
║  ⏳ Recognizing entity at ~(22,10): 0.3s / 0.6s elapsed           ║
║     Pending monologue: "Those footsteps... that's—"               ║
╠══════════════════════════════════════════════════════════════════════╣
║ INTERACTIONS                                                       ║
║  guard-1 [Talk(1) Observe(2)] d=3 in-LOS                         ║
╠══════════════════════════════════════════════════════════════════════╣
║ MONOLOGUE: "Quiet shift. Too quiet."                              ║
║ DIALOGUE: none                                                     ║
╠══════════════════════════════════════════════════════════════════════╣
║ INVENTORY: [0:keycard] [3:manifest] [_] [_] [_] [_] [_] [_] [_]  ║
╠══════════════════════════════════════════════════════════════════════╣
║ CHECKLIST: Occlusion Corridor — 4/7 ██████░░░░ 57%                ║
║ TIMER: 00:47 (PB: 00:38)            [F12:WRONG] [Home:Hub] [R:Reset]║
╚══════════════════════════════════════════════════════════════════════╝

Section-by-Section Spec

Header Bar:

  • Tick: N — current simulation tick
  • TickRate: Full/Half/Paused — simulation speed
  • Room: {name} — detected from player position against Gauntlet room bounds
  • Seed: N — the SimRng seed (for bug reproduction)
  • Session: HH:MM:SS — wall-clock time since test client connected

Player Line:

  • Position (x,y), facing arrow (→ East), stance (Walk/Sprint/Careful/Crouch), inventory count

Entities Section: Each entity on its own line. Symbols indicate visibility state:

  • VISIBLE (in clear vision cone)
  • REMEMBERED (in fog, previously seen)
  • FOGGED (detected in fog, not yet recognized — grey blob state)
  • BLOCKED (exists but LOS blocked — debug info only, requires Dudley's blocked_entities field)
  • RECOGNIZING (mid-cognitive-delay transition)

Per entity: name, position, sector (Fwd/Periph/Behind), relationship state with color hex AND semantic label, visibility state, distance.

For BLOCKED entities: indented line showing WHICH wall blocks LOS. This is the "show your work" data that lets a tester say "the wall at (17,10) should NOT be blocking LOS here" vs "the NPC is correctly hidden."

Fog Section: Five numbers matching D-059's five fog layers. At a glance, the tester sees the fog distribution. If Clear drops to 0, something is very wrong. If Dark is 0, fog isn't working.

Sound Section: EVERY sound event that fired this tick. This is the critical missing piece from Stig's Round 1 spec. D-018 defines three information quality ranges — Close (stereo, identity possible), Medium (directional, imprecise), Long (insert alerts, delayed). Each sound event shows:

  • Approximate source position
  • Description (footsteps, conversation murmur, alarm)
  • Range classification [CLOSE/MEDIUM/LONG]
  • Whether an audio asset played or only a visual indicator rendered

Cognition Section: Active cognitive delays (D-060). Shows:

  • Which entity is being recognized
  • Time elapsed vs total delay
  • Any pending monologue text that will fire during the delay
  • Recognition chime state (D-067): "chime played at onset" / "chime complete"

Interactions Section: Available verbs per entity within range. Includes priority numbers, distance, and whether the entity is currently in LOS.

Monologue/Dialogue Section:

  • Monologue: the EXACT text currently displayed. Not "active" — the words.
  • Dialogue: NPC name, current line, number of response options, walk-away state.

Inventory Section: Visual slot map. Filled slots show item name. Empty slots show [_]. Matches the 9-slot grid (D-065).

Status Bar:

  • Checklist progress for current room (auto-tracked, see Section 2.6)
  • Room timer
  • Hotkey reminders: F12 for WRONG, Home for Hub teleport, R for Reset

Data Requirements from ObserverSnapshot

The test client needs these fields that Dudley identified as missing (Round 1, Track 3 Q1):

  1. blocked_entities: Vec<BlockedEntity> — entities not visible with the blocking wall position. Essential for the ✕ BLOCKED line. Populated only in debug/test mode to avoid production overhead.
  2. Entity display namesVisibleEntity needs a display_name: Option<String> or the test client resolves StableIds against a loaded name table from the Gauntlet content pack.
  3. Fog layer counts per type — the snapshot has visible_tiles but not the 5-layer breakdown. Either the server computes this (preferred — it has the fog state) or the test client derives it from tile visibility data.
  4. Sound events — a Vec<SoundEvent> with source position, type, range classification, and whether it triggered audio or visual-only feedback.

Items 1, 3, and 4 should be gated behind a --debug flag or test-mode marker on the snapshot request to avoid production overhead.


2. Anti-Tedium Feature Specs

All approved by lead. Here are the full specs.

2.1 Room Reset

Trigger: Player steps on a reset plate at the room entrance. Reset plates are 2x2 tile areas (matching D-066 visual tile size) with a distinct floor pattern (striped hazard marking — fits the station maintenance aesthetic).

UX Flow:

  1. Player walks onto reset plate
  2. Terminal displays: ⟳ RESET: Occlusion Corridor? [Enter to confirm / any move to cancel]
  3. Player presses Enter (or sends a dedicated ResetRoom action)
  4. Server resets the room:
    • All entities in the room return to tick-0 positions
    • Entity knowledge graph entries related to this room are reverted
    • Fog for room tiles reverts to initial state (unexplored for fresh rooms, or the room's default)
    • Player inventory changes from this room are reverted (items taken are returned, items dropped are removed)
    • Player position stays on the reset plate (they don't teleport)
  5. Terminal displays: ✓ Occlusion Corridor reset to tick-0 state. Room timer reset.
  6. Room timer restarts from 0

Server-side implementation hint: Each room has a RoomState snapshot taken at Gauntlet load time. Reset = restore that snapshot for all entities within the room's bounding box. Player entity is excluded from the state restore (they stay where they are with their current stance/facing).

What does NOT reset:

  • Other rooms (isolation is critical — resetting the Occlusion Corridor doesn't touch the Dialogue Room)
  • Player position (stays on reset plate)
  • Session timer (wall-clock time keeps running)
  • Checklist progress for OTHER rooms

Edge case: What if the player is carrying an item from this room when they reset? The item is removed from inventory and returned to its tick-0 position. Terminal shows: Items returned: keycard → crate_1

2.2 Hub Teleport

Hotkey: Home key. Universal, always available, no modifier needed.

UX Flow:

  1. Player presses Home from any room
  2. Terminal displays: ⟳ Teleporting to Central Hub...
  3. Server teleports player entity to GAUNTLET.hub_spawn position
  4. Next tick's snapshot reflects new position
  5. Terminal displays: ✓ Central Hub. Choose a room.

No confirmation required. Hub teleport is non-destructive — it doesn't reset any room state. The player's inventory, knowledge graph, and all room states are preserved. They're just... elsewhere now.

What happens to active states:

  • Active dialogue: walk-away triggers (D-064 300ms fade equivalent, dialogue fades)
  • Active cognitive delay: cancelled (entity recognition interrupted by teleport)
  • Active monologue: cleared (new room, new context)
  • Interaction buffer: cleared (D-055 pattern — stance change clears, teleport should too)

In text mode: The display refreshes instantly to show the Hub's snapshot. Room timer pauses (the tester left the room).

2.3 WRONG Button

Hotkey: F12. THE most important anti-tedium feature. This is how testing becomes sustainable.

Full Capture Flow:

  1. Tester sees something wrong. Presses F12.
  2. Test client immediately captures:
    • Current ObserverSnapshot (the exact server state at this tick)
    • Last 60 ticks of snapshot history (the test client buffers these in a ring buffer)
    • Last 60 ticks of player inputs (what the tester was doing)
    • Current text renderer output (what the tester was seeing)
    • Room metadata (which room, expected behaviors, checklist state)
    • Gauntlet seed (for reproduction)
    • Session timestamp (wall-clock time)
  3. Terminal pauses the live display and shows:
╔══════════════════════════════════════════════════════════════════╗
║ 🚨 BUG REPORT — Tick 42 — Occlusion Corridor                  ║
╠══════════════════════════════════════════════════════════════════╣
║ What's wrong? (one line, then Enter):                          ║
║ > _                                                             ║
╚══════════════════════════════════════════════════════════════════╝
  1. Tester types one sentence: NPC behind wall was visible
  2. Presses Enter.
  3. Test client writes bug report to disk. Terminal shows:
✓ Bug report saved: tests/bug-reports/gauntlet-2026-02-17T08-42-13/
  ├── report.md          (human-readable summary)
  ├── snapshot_current.json
  ├── snapshot_history.jsonl   (last 60 ticks)
  ├── input_history.jsonl      (last 60 inputs)
  ├── text_output.txt          (what the terminal showed)
  └── room_metadata.json       (room name, checklist, expected state)
  1. Live display resumes. Tester continues testing.

Bug Report Format (report.md):

# Bug Report — Gauntlet
- **Date:** 2026-02-17 08:42:13
- **Room:** Occlusion Corridor
- **Tick:** 42
- **Seed:** 42
- **Tester description:** NPC behind wall was visible

## State at time of report
Player (15,10) facing East | Walk | Inventory: 2/9

### Entities
| Name | Position | Sector | Relationship | Visibility | Distance |
|------|----------|--------|-------------|------------|----------|
| guard-1 | (18,10) | Forward | Neutral | VISIBLE | 3 |
| worker-2 | (20,10) | Forward | Unknown | REMEMBERED | 5 |
| hidden-1 | (19,12) | --- | Unknown | **VISIBLE** | 7 |

### Expected (from room checklist)
- hidden-1 should be BLOCKED by wall at (17,10)

### Fog State
Clear: 31 | Peripheral: 12 | Deep: 58 | Map: 89 | Dark: 312

## Reproduction
1. Start Gauntlet with seed 42
2. Navigate to Occlusion Corridor
3. Stand at (15,10) facing East
4. Observe: hidden-1 at (19,12) is visible (should be blocked)

File location: tests/bug-reports/gauntlet-{ISO-timestamp}/. Each report gets its own directory. The reports accumulate across sessions — developers browse them, fix bugs, delete resolved reports.

Ring buffer size: 60 ticks = ~6 seconds at 10 tps. Enough to capture "what just happened" without burning memory. Configurable via CLI flag (--history-buffer 120 for longer captures).

2.4 Room Timer

Visual in text mode: Bottom status bar shows:

TIMER: 00:47 (PB: 00:38)
  • 00:47 — time spent in this room this run (wall-clock, not tick time)
  • PB: 00:38 — personal best for this room across all sessions

Timer starts when the player enters a room (crosses room bounding box). Timer pauses when the player leaves the room (hub teleport or walking to another room). Timer resets when the room resets (Section 2.1).

Personal bests are stored in a local file: tests/gauntlet-stats.json. Simple key-value: room name → best time in seconds. Persists across sessions. Not committed to git (it's local QA data).

{
  "occlusion_corridor": { "best_seconds": 38, "runs": 12 },
  "fog_theater": { "best_seconds": 52, "runs": 8 },
  "inventory_warehouse": { "best_seconds": 25, "runs": 15 }
}

Why this matters for anti-tedium: "Can I beat my time?" turns testing into a personal challenge. The tester isn't just checking boxes — they're getting FASTER at checking boxes. That's intrinsic motivation. Free. No server changes needed.

2.5 Auto-Checklist Progress

How it works: Each room has a checklist.yaml co-located with its definition (matches Stig's proposal — see Section 3). The test client loads these at startup and tracks which items have been verified.

Tracking mechanism: The test client watches the ObserverSnapshot for conditions that match checklist items. When a condition is met, the checklist item is marked as "observed" (not "passed" — the tester decides if the behavior is correct).

Example checklist item:

- id: occ_hidden_npc_not_visible
  description: "NPC behind wall is NOT visible in Visual mode"
  condition:
    entity: hidden-1
    expected_visibility: blocked
    player_position_near: [15, 10]
    player_facing: East

When the player is near (15,10), facing East, and hidden-1 is NOT in the visible entities list, this item transitions from [ ] to [?] (observed — was it correct?). The tester explicitly confirms with a keypress or it auto-confirms if the condition matches expectation.

Terminal display:

CHECKLIST: Occlusion Corridor — 4/7 ██████░░░░ 57%
  [✓] NPC behind wall: NOT visible
  [✓] NPC in front: IS visible
  [✓] Peripheral NPC: dimmed
  [?] Sensor mode: hidden NPC detected     ← auto-observed, awaiting confirm
  [ ] Sound ping: directional indicator
  [ ] Cognitive delay: ~0.6s timing
  [ ] Recognition: monologue fires DURING delay

Auto-confirm vs manual-confirm: For objective conditions (entity visible/not-visible, inventory count, fog state), auto-confirm when the snapshot matches. For subjective conditions (timing "feels right", monologue text is appropriate), require manual confirmation (tester presses Y on the highlighted item).

Progress persists within a session but resets when the room resets (Section 2.1). Cross-session progress is stored in tests/gauntlet-stats.json alongside timer data.


3. Cross-Review: Stig's Checklist Proposal

Stig proposes: Checklists co-located with room YAML definitions, make checklist generates docs/workshops/test-architecture/gauntlet-checklist.md.

My Layer 3 (Round 1) proposed: Generated checklist from room metadata, lives at docs/qa/gauntlet-checklist.md, printable, checkboxes.

Verdict: Stig's approach is BETTER than mine. Here's why, and what's missing.

What Stig Gets Right

  1. Co-location with room YAML. Checklist items live next to the things they test. When you add a new entity to the Occlusion Corridor YAML, the checklist is right there — you can't forget to add a test for it. My Round 1 proposed a separate checklist file, which would drift from the room definitions over time.

  2. Auto-generation via make checklist. Single source of truth. The markdown output is the artifact, not the source. Change the YAML, regenerate, done.

  3. Example format is concrete. Stig's examples ("Stand at (15,8) face East → guard-1 visible/Forward/full alpha") are actionable. A tester can follow them step-by-step.

What's Missing from Stig's Proposal

  1. No machine-readable condition format. Stig's checklists are human-readable prose. For auto-tracking in the test client (Section 2.5), we need structured conditions — entity name, expected visibility state, player position, etc. The YAML needs both: a description field (human prose) and a condition field (structured data).

  2. No subjective vs objective distinction. Some checklist items are objectively verifiable ("NPC not visible" — check the snapshot). Others are subjective ("cognitive delay feels like 0.6s" — tester judgment). The checklist YAML should tag items as auto (snapshot-verifiable) or manual (requires human judgment). This drives the auto-confirm vs manual-confirm behavior in the test client.

  3. No cross-room checklist items. Stig's examples are per-room. But Gestalt's Round 1 identified critical cross-room scenarios (sprint from Crowd Plaza into Occlusion Corridor). Where do those checklist items live? Proposal: a cross_room_checks.yaml at the Gauntlet root level, separate from per-room checklists.

  4. No failure guidance. Each checklist item should include a if_wrong field: "If this fails, the likely cause is X. Check Y." This is the "articulate failures" requirement from the brief. Example:

- id: occ_hidden_npc_not_visible
  description: "NPC behind wall is NOT visible in Visual mode"
  condition:
    entity: hidden-1
    expected_visibility: blocked
  type: auto
  if_wrong: >
    LOS is leaking through the wall at (17,10).
    Check: symmetric shadowcasting treating wall tile as transparent?
    Check: entity position exactly at (19,12)? Off-by-one puts them in LOS.
    File: server/src/perception/shadowcast.rs

Proposed Merged Format

# content/gauntlet/rooms/occlusion_corridor/checklist.yaml
room: occlusion_corridor
description: "Tests LOS, shadowcasting, vision cone, and perception modes"

checks:
  - id: occ_01_hidden_not_visible
    description: "NPC behind wall is NOT visible in Visual mode"
    type: auto
    condition:
      player_near: [15, 10]
      player_facing: East
      entity: hidden-1
      expected: blocked
    if_wrong: |
      LOS leaking through wall at (17,10).
      Check symmetric shadowcasting in server/src/perception/shadowcast.rs.

  - id: occ_02_guard_visible
    description: "NPC in front of wall IS visible with full alpha"
    type: auto
    condition:
      player_near: [15, 10]
      entity: guard-1
      expected: visible
      expected_sector: Forward
    if_wrong: |
      Guard should be in clear LOS at distance 3.
      Check entity spawn position in room YAML.

  - id: occ_03_cognitive_delay_timing
    description: "Cognitive delay for fog recognition takes ~0.6s"
    type: manual
    guidance: |
      Walk to the fog boundary. Wait for a sound event.
      Count: does recognition take roughly 0.6 seconds?
      The pending_recognitions field shows elapsed/total.
    if_wrong: |
      Cognitive delay timing off. Check D-060 values in
      server/src/perception/recognition.rs.

This format serves BOTH Stig's generated markdown checklist AND my test client auto-tracking. make checklist renders the human-readable version. The test client loads the structured conditions.


4. Human Tester Workflow — Full Step-by-Step

Pre-Session Setup

# Terminal 1: Start the Gauntlet server
make test-world-headless SEED=42

# Terminal 2: Connect test client
make test-client-connect
# or: cargo run --bin gauntlet-client -- --host 127.0.0.1 --port 9876 --history-buffer 60

The test client connects, receives the first ObserverSnapshot, and displays the live terminal UI. The tester is in the Central Hub.

Typical Testing Flow

Step 1: Choose a room. Tester is in the Central Hub. The terminal shows room exits with labels:

EXITS: [N] Fog Theater | [E] Occlusion Corridor | [S] Dialogue Room | [W] Inventory

Tester sends movement input (arrow keys or WASD mapped to PlayerAction) toward the desired room. Or presses a room-select hotkey if quick-nav is implemented.

Step 2: Enter the room. Player walks through the corridor into the Occlusion Corridor. Terminal updates:

  • Room name changes to "Occlusion Corridor"
  • Timer starts
  • Checklist section loads this room's checklist items
  • Progress bar shows 0/7

Step 3: Execute the checklist. Tester moves to the specified positions and observes. The test client auto-tracks objective items:

CHECKLIST: Occlusion Corridor — 0/7
  [ ] NPC behind wall: NOT visible    ← move to (15,10), face East

Tester moves to (15,10), faces East. Test client checks snapshot:

  • hidden-1 is NOT in visible entities. Condition met.
CHECKLIST: Occlusion Corridor — 1/7
  [✓] NPC behind wall: NOT visible
  [ ] NPC in front: IS visible        ← auto-checked: guard-1 visible ✓

Wait — that auto-checked too, because guard-1 IS visible from this position. Two items checked simultaneously.

CHECKLIST: Occlusion Corridor — 2/7
  [✓] NPC behind wall: NOT visible
  [✓] NPC in front: IS visible
  [?] Peripheral NPC: dimmed          ← auto-observed, confirm? [Y/N]

Tester looks at the entity list: peripheral NPC shows ◐ PERIPHERAL. They press Y to confirm.

Step 4: Encounter a bug. Tester switches perception mode (sends a TogglePerceptionMode action). The hidden NPC should now be detected in Sensor mode. But it's not. The entity list still shows ✕ BLOCKED.

Tester presses F12.

╔═══════════════════════════════════════════════╗
║ 🚨 BUG REPORT — Tick 87 — Occlusion Corridor ║
║ What's wrong?                                 ║
║ > Sensor mode doesn't detect NPC behind wall_ ║
╚═══════════════════════════════════════════════╝

Tester types description, presses Enter. Bug report saved.

Step 5: Reset and retry (or move on). Tester presses R to reset the room. All entities return to tick-0. Timer resets. Checklist resets. Tester retries the perception mode test.

Or, tester presses Home to teleport to Hub and test a different room.

Step 6: Complete the session. After testing all target rooms, tester presses Ctrl+C to disconnect.

Test client prints session summary:

═══════════════════════════════════════════════════
SESSION SUMMARY — 2026-02-17 08:42
═══════════════════════════════════════════════════
Rooms visited:     4/7
Checklist coverage: 22/38 items (58%)

  Occlusion Corridor:  6/7  ██████████░  86%  00:47  (PB: 00:38)
  Fog Theater:         5/8  ████████░░░  63%  01:12  (PB: 00:52)
  Inventory Warehouse: 7/7  ███████████ 100%  00:25  (PB: 00:25) ★ NEW PB
  Crowd Plaza:         4/9  ██████░░░░░  44%  01:35  (PB: --)

Bug reports filed: 2
  → tests/bug-reports/gauntlet-2026-02-17T08-42-13/
  → tests/bug-reports/gauntlet-2026-02-17T08-43-57/

Stats saved to tests/gauntlet-stats.json
═══════════════════════════════════════════════════

THAT'S a session that felt productive. The tester knows exactly what they covered, what they missed, and where the bugs are. They can hand the bug reports to a developer and say "here, everything you need is in the folder."

Quick-Test Workflow (developer fixing a specific bug)

Not every session is a full walkthrough. A developer just fixed the fog shader and wants to verify:

# Start server + client
make test-world-headless SEED=42
make test-client-connect

# Press Home (already in Hub)
# Walk to Fog Theater (or press room-select hotkey)
# Run through fog-specific checklist items
# If it passes: done in 60 seconds
# If it fails: F12, bug report, fix, repeat

Total time: under 2 minutes. THAT'S why hub-and-spoke layout matters. THAT'S why room reset matters. The developer doesn't touch any room they don't care about.


Summary

Deliverable Status
Test client terminal layout specification Complete
Live-updating display rationale Complete
Missing ObserverSnapshot fields identified Complete (4 fields)
Room reset full UX flow Complete
Hub teleport spec Complete
WRONG button full capture flow + file format Complete
Room timer + personal bests spec Complete
Auto-checklist progress tracking spec Complete
Cross-review of Stig's checklist: gaps identified Complete (4 gaps)
Merged checklist YAML format proposed Complete
Full human tester workflow (step-by-step) Complete
Quick-test developer workflow Complete

Open Questions

  1. For Dudley: The blocked_entities debug field on ObserverSnapshot — is this feasible within the current compute_observer_snapshot pipeline? Estimated cost per tick?
  2. For Stig: Can the Godot client also render the checklist progress overlay (my Layer 2 debug overlay from Round 1)? Or is checklist tracking test-client-only?
  3. For Tyre: The test client binary — should it live in server/src/bin/gauntlet-client.rs (alongside the server binary) or in a separate tools/gauntlet-client/ crate? The former shares types easily. The latter keeps the server crate focused.
  4. For Gestalt: Your cross-room transition scenarios (Round 1) — should these have their own checklist section? Where does "sprint from Crowd Plaza into Occlusion Corridor" live in the room YAML hierarchy?