Repository navigation
#542 AC4: port four WebGL-era specs to WebGPU engine unit tests - #585
Merged
MaximumTrainer merged 1 commit intoOct 25, 2026
Merged
Conversation
The four React/WebGL specs (gl-context-budget, webgl-context-recovery,
rower3d-postfx, scene-quality-match) targeted the retired three.js
renderer. Replace them with engine unit tests under
src/lib/renderer/engine/__tests__/ac4PortedBehaviors.test.ts, split by
the behaviour each one used to check:
(A) context budget — 1 adapter + 1 device per attach, 0 WebGL probes
(B) device-lost — publishDeviceLost + counter on first loss,
renderer-unavailable on the second, contextState stays ready on
the first loss (today's observed behaviour)
(C) post-fx — pass tree assembles at every tier, SSAO/DOF gates
follow tierCaps
(D) scene quality — shadow + content gates climb monotonically with
the tier, software adapters are declined outright
Measured first against the real engine on Dan's Intel Gen-9 laptop
(hardware WebGPU, next/svelte-webgpu @ b32f746) so every assertion
encodes observed behaviour, not aspiration. The one gap the RC pass
found — first-loss recovery (banner, reattach, fallback publish) is
not wired up today — is tracked as it.todo in the new file and in #584
with its own ACs; writing it green would smuggle an engine fix into
this PR.
Also drops the four spec files, their testIgnore entries in
playwright.config.next.ts, and their shard-weights.json rows.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q5D9BTXmu7SeMa3LghJD8b
6 of 8 tasks
MaximumTrainer
added a commit
that referenced
this pull request
Oct 25, 2026
The WebGPU engine detected device.lost but did nothing with it: no re-attach, no banner, no fallback publish, and the rAF loop kept submitting work to a dead device. Measured on Intel Gen-9 against next/svelte-webgpu @ 43433ba: 45 GPUCommandEncoder.finish + 45 queue.submit in 1.5s after a forced loss, no visible sign to the rower, __ROWER3D_CONTEXT_STATE stuck at 'ready'. Factors the per-device scene into src/lib/renderer/engine/rideScene.ts; attach.ts stays the thin orchestration layer (telemetry, outer render loop, device session lifecycle). On the first device.lost (D1-a): - publish fallbackReason='device-lost' - flip __ROWER3D_CONTEXT_STATE.kind to 'lost', backend stays 'webgpu' - publish the "restoring…" banner (D2-a copy ported verbatim from the retired WebGL spec) - dispose the current scene so no further work lands on the dead device - request a fresh device with isRetry: true - on retry success, build a new scene on the SAME canvas and continue; on retry failure, the retry's own onDeviceLost fires with 'renderer-unavailable', the engine publishes the "couldn't get it back" banner and stops drawing (D3-a). FR2 (D4-a): installs __ROWER3D_FORCE_DEVICE_LOST on the current device, gated on window.__PLAYWRIGHT_TESTING, so a spec can trigger a loss without reaching into the Chrome rendering panel. Replaced on every scene build, cleared on dispose. FR3 (D6-c): device opts in to the timestamp-query feature when the adapter has it (follow-up wires per-pass timestampWrites + readback for __ROWER3D_FRAME_STATS.gpuMs). cpuMs lands this PR as the always-on fallback — measured around frameOnce with performance.now, written to telemetry every frame. UI: /row polls window.__ROWER3D_BANNER at 250 ms and renders a banner overlay at the top of the stage with variant-colored backgrounds for restoring (amber) and failed (red). The row keeps counting through either state (ride.currentSession is DOM-driven, not render-driven). Flips the it.todo in ac4PortedBehaviors.test.ts (added in #585) to a passing test; adds three more: reattach-success, retry-also-dies, and force-loss seam presence. rideScene.ts is a mechanical extraction from attach.ts, exercised transitively via the attach suite — TDD guard off for the file move only (no new behaviour). Claude-Session: https://claude.ai/code/session_01Q5D9BTXmu7SeMa3LghJD8b Co-authored-by: Claude <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
#542 AC4. The four React/WebGL-era specs (
gl-context-budget,webgl-context-recovery,rower3d-postfx,scene-quality-match) targeted the retired three.js renderer — not a line of them can pass against the Svelte + WebGPU engine. This PR replaces them with engine unit tests that check the same four behaviours against the new engine, drops the specs and their shard-weight / testIgnore entries, and opens #584 for the integrated boot-and-row half of the port (which needs engine seams that don't exist yet, plus a GPU runner).Dan's call ("a, b & c") was all three options; this is (b) + (c), with (a) folded into #584's AC5 because the e2e ports need engine seams first (device-lost reattach, timestamp-query, forced-loss helper) and a real GPU runner that's still dormant.
Summary
src/lib/renderer/engine/__tests__/ac4PortedBehaviors.test.ts:publishDeviceLost+ counter on first loss,renderer-unavailableon the second,contextStatestaysreadyon first loss (today's observed behaviour; the recovery gap is tracked asit.todoand in AC4 follow-up: wire real device-lost recovery + GPU-runner e2e ports #584)tierCapstestIgnoreentries inplaywright/playwright.config.next.ts, and their rows inplaywright/shard-weights.json.onDeviceLost(null)fire) but no re-attach, no banner, nofallbackReason, and the rAF loop keeps submitting to the dead device.Measured first, written second
Every assertion was measured against the real engine on Dan's Intel Gen-9 laptop (hardware WebGPU,
next/svelte-webgpu @ b32f746) on 2026-10-25 before being encoded. The one gap the measurement found is the device-lost recovery hole — not the first-loss detection, which works, but the follow-through (reattach, banner copy, state flip). That's in #584 with its own ACs; smuggling it into AC4 as a drive-by engine fix would make this PR a different change.Test plan
npx vitest run src/lib/renderer/engine/__tests__/ac4PortedBehaviors.test.ts— 15 pass, 1 todonpx vitest run src/lib/renderer/engine/__tests__/— 116 tests + 1 todo, all passnpx tsc --noEmit -p tsconfig.app.jsonnpx tsc -p tsconfig.playwright.json --noEmitnpm run lintnext/svelte-webgpubranch (preflight / scaffold smoke / WebGPU engine smoke / e2e-shards 1 of 2 + 2 of 2 / GPU runner skipped)Generated by Claude Code