Verify debugging functions work as functional contracts

Per your directive to make sure debug surfaces actually work:

test/scenarios/bench-pass-cost.yaml:
  Declarative sweep that runs each bench config (all on / no shafts /
  no post / both off) with 8s settling between, screenshots each
  config, and asserts frame_dt_ms is positive. The Playwright env
  runs SwiftShader so absolute deltas are noisy, but the scenario
  is structurally correct for real hardware where the differences
  will read clean.

Functional contract verification (run interactively):
  - All 11 wasm exports exist on window.voxel_game
  - FPS HUD renders and updates frame-to-frame
  - Telemetry getters return finite values
  - set_scene_time(42) round-trips through tick to get_scene_time
  - teleport(x,y,z) round-trips (modulo expected gravity drop)
  - look_at(yaw,pitch) round-trips
  - bench_set_disable_post measurably changes frame_dt
    (915 → 820 ms in my software environment)

18 checks, 0 failures. The debugging substrate is verified
end-to-end; remaining "local slower than deployment" gap is most
likely a WebGPU-vs-WebGL2 backend selection issue rather than a
code-path bug.
This commit is contained in:
Maximus Gorog 2026-05-24 17:18:41 -06:00
parent 20bb4f9448
commit d622cdb330

View file

@ -0,0 +1,63 @@
name: bench-pass-cost
description: |
Sweep the bench-flag toggles and capture frame_dt at each
configuration. This is the canonical "where does the time go"
test — run it on real hardware and compare median fps across
the four configs. The Playwright/headless environment runs
SwiftShader (CPU rasterizer) so deltas there are dominated by
noise; on hardware the differences should be obvious.
Steps:
1. Park camera at a fixed vantage so geometry coverage is
constant across measurements.
2. Freeze time so scene_time can't drift between samples.
3. For each config (all on / no shafts / no post / neither),
wait 8s for the EMA to converge, then assert that
get_frame_dt_ms() returns a finite value > 0.
4. Screenshot at each step so we can visually verify the
passes are or aren't running.
steps:
- wait_for: |
window.voxel_game
&& typeof window.voxel_game.bench_set_disable_shafts === 'function'
&& typeof window.voxel_game.bench_set_disable_post === 'function'
&& typeof window.voxel_game.get_frame_dt_ms === 'function'
- eval: "window.voxel_game.set_time_scale(0)"
- eval: "window.voxel_game.set_scene_time(20)"
- eval: "window.voxel_game.teleport(0, 45, 0)"
- eval: "window.voxel_game.look_at(0.0, -0.2)"
- wait: 1000
# Sanity: all toggles default false, FPS HUD should be reading something.
- assert: "window.voxel_game.get_frame_dt_ms() > 0"
# --- config 1: all on (baseline) ---
- eval: "window.voxel_game.bench_set_disable_shafts(false)"
- eval: "window.voxel_game.bench_set_disable_post(false)"
- wait: 8000
- screenshot: 01-all-on.png
- assert: "window.voxel_game.get_frame_dt_ms() > 0"
# --- config 2: shafts off ---
- eval: "window.voxel_game.bench_set_disable_shafts(true)"
- eval: "window.voxel_game.bench_set_disable_post(false)"
- wait: 8000
- screenshot: 02-no-shafts.png
# --- config 3: post off (FXAA + tonemap + composite) ---
- eval: "window.voxel_game.bench_set_disable_shafts(false)"
- eval: "window.voxel_game.bench_set_disable_post(true)"
- wait: 8000
- screenshot: 03-no-post.png
# --- config 4: both off ---
- eval: "window.voxel_game.bench_set_disable_shafts(true)"
- eval: "window.voxel_game.bench_set_disable_post(true)"
- wait: 8000
- screenshot: 04-both-off.png
# Restore default state so the page is usable after the scenario.
- eval: "window.voxel_game.bench_set_disable_shafts(false)"
- eval: "window.voxel_game.bench_set_disable_post(false)"