Skip to content

fix(#757): /game/cod-skeleton mounted a WebGL scene nobody had asked for - #794

Merged
TortoiseWolfe merged 2 commits into
mainfrom
fix/757-cod-skeleton-start-gate
Aug 18, 2026
Merged

fix(#757): /game/cod-skeleton mounted a WebGL scene nobody had asked for#794
TortoiseWolfe merged 2 commits into
mainfrom
fix/757-cod-skeleton-start-gate

Conversation

@TortoiseWolfe

Copy link
Copy Markdown
Owner

/game/cod-skeleton mounted a WebGL scene during page load. On a GPU-less runner that took
most of the mobile-layout sweep's 30s budget, so No horizontal overflow on /game/cod-skeleton
timed out three times and blocked two merges — most recently #791, which changes an edge
function and a migration and cannot touch a WebGL route.

The full finding lives in #757, rewritten with the measurement. This is the change.

It was not a flake

Measured from the results.json artifacts of the *-gen 5/6 shards across 14 e2e-local runs:

browser /game/cod-skeleton every other route
chromium 22.6–30.2s pass, 31.3–32.0s timeout — 12 pass / 6 timeout median 2.7s, p95 3.7s
firefox 3.0–3.3s — 14 pass / 0 timeout median 3.1s, p95 3.3s
webkit 12.7–20.0s pass, 30.3–41.7s timeout — 14 pass / 14 timeout median 3.4s, p95 4.7s

The route needed ~93% of the cap, so variance decided the outcome. Every green run of it was
luck, and webkit had been retry-masking a 50% per-attempt failure rate the whole time — the run
went green, so nobody looked.

Why the page, not the test

The <Canvas> mount builds a MaterialSystem and bakes its 1K texture sets synchronously
before the page is measurable. Firefox — which has no WebGL and never mounts it — completed the
identical layout measurement in 2.8s. The whole gap is that mount.

A software rasteriser stands in for a low-end visitor, and they pay the same cost on a route
they have not asked to run anything on. Raising the timeout or suppressing the render loop from
the test would each have made a true report stop arriving. So the scene now waits to be asked —
what games do anyway, and what this page already told you to do ("Click to capture the mouse").

Measured effect

Same box, root build (DISABLE_BASE_PATH), SwiftShader forced via the flags
playwright.visual.config.ts already uses:

before   /game/cod-skeleton  7.6s   canvas=1   time-to-webgl-decided 5.3s
after    /game/cod-skeleton  2.6s   canvas=0   time-to-webgl-decided 0.2s
control  /blog/seo          ~3.5s

It is now faster than the DOM-only control. The previously failing test passes locally in 6.7s.

The gate opens, and the box does not move

Driven as the real user gesture in a real browser, not asserted from unit tests alone:

before click: canvas=0  wrapperBox=358x201
after  click: canvas=1  wrapperBox=358x201  canvasBox=300x150

The placeholder lives inside the same wrapper, so aspect-video w-full gives it the
identical box and the sweep measures the geometry it always measured.

Guards

Three, each mutation-verified — and the mutant confirmed present in the file before believing
the red, because a sed whose | collided with || once produced a green "proof" here:

  • no canvas before the gate opens — killed by defaulting started to true (9 failures)
  • a canvas with a real box after it opens — a gate that never opened would ship a dead route
  • both branches carry the same wrapper class — killed by adding h-40 to one branch (1
    failure, precisely that test)

Plus the a11y suite now audits the placeholder state, which is what every visitor sees first,
and pins min-h-11 min-w-11 on the start control — mobile-touch-targets cannot see a control
that only exists after a click it never performs.

Checked, not assumed

Not fixed here

#792 — firefox has no WebGL, so the sweep measures <FallbackPanel> on one browser and a
canvas on the other two, silently. This makes both branches cheap but does not close that
divergence: the WebGL probe still runs before the start gate. Confirmed and written up there.

Closes #757
Refs #792, #793

The mobile-layout sweep timed out on this route three times and blocked two
merges. It was read as a flake twice, and closed once on #765 — a real fix, to a
different defect.

Measured across 14 CI runs from the results.json artifacts of the *-gen 5/6
shards, which is the distribution the issue asked for twice and never got:

  chromium  22.6-30.2s pass, 31.3-32.0s timeout   12 pass /  6 timeout
  firefox    3.0-3.3s                             14 pass /  0 timeout
  webkit    12.7-20.0s pass, 30.3-41.7s timeout   14 pass / 14 timeout
  every other route                               median 2.7-3.4s

Read as a distribution rather than as incidents: the route needed ~93% of a 30s
cap, so ordinary runner variance decided pass or fail. Every green run of it was
luck, and webkit had been retry-masking a 50% per-attempt failure rate the whole
time.

The cost is the <Canvas> mount. It builds a MaterialSystem and bakes its 1K
texture sets synchronously before the page can be measured. Firefox, which has no
WebGL and never mounts it, finished the identical layout measurement in 2.8s --
the whole gap is that mount.

That is a property of the PAGE, not of the test. A software rasteriser stands in
for a low-end visitor, and they pay the same cost on a route that has not yet been
asked to do anything. Raising the timeout would have hidden a true report; so
would suppressing the render loop from the test. So the scene waits to be asked,
which is what games do anyway and what this page already told you to do.

Measured on one box, root build, SwiftShader forced: 7.6s -> 2.6s, which is below
the /blog/seo control on the same run.

The placeholder lives inside the SAME wrapper, so aspect-video w-full gives it the
identical box -- verified in a real browser at 358x201 before and after the click,
so the layout sweep measures the geometry it always measured.

Three guards, each mutation-verified with the mutant confirmed present in the file
first: no canvas before the gate opens, a canvas with a real box after it does,
and both branches carrying the same wrapper class.

Closes #757
Refs #792
@TortoiseWolfe
TortoiseWolfe merged commit 8eb705c into main Aug 18, 2026
38 of 39 checks passed
@TortoiseWolfe
TortoiseWolfe deleted the fix/757-cod-skeleton-start-gate branch August 18, 2026 05:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

/game/cod-skeleton uses 28s of its 30s budget before layout can be measured — the timeouts are the cap being crossed, not a flake

2 participants