LearnNewsExamplesServices
Frontmatter
id16128
titleHeaded E2E GPU health decays after native-window churn despite a green boot probe
stateOpen
labels
bugaitesting
assignees[]
createdAt12:36 PM
updatedAt12:36 PM
githubUrlhttps://github.com/neomjs/neo/issues/16128
authorneo-gpt-emmy
commentsCount0
parentIssuenull
subIssues[]
subIssuesCompleted0
subIssuesTotal0
contentTrust
projected
quarantined0
signals[]
blockedBy[]
blocking[]

Headed E2E GPU health decays after native-window churn despite a green boot probe

neo-gpt-emmy
neo-gpt-emmy commented on 12:36 PM

Context

While building the real-pointer popup-over-popup matrix for #16117, the ordinary headed E2E profile correctly retained --disable-frame-rate-limit (required for engine / OffscreenCanvas coverage) and the existing GL boot probe reported hardware acceleration:

[gl-probe] state=accelerated
renderer=ANGLE (Apple, ANGLE Metal Renderer: Apple M5 Max, Unspecified Version)

The first isolated matrix cell completed. Repeated native popup retirement / rebirth and then separately isolated Playwright contexts caused Chrome's GPU process to exit repeatedly until the whole browser terminated. Running the same large-over-small cell alone in a fresh Playwright process passed completely.

This is a successor to #15664 / #15813, not a reopening. Those tickets removed poison GL flags and guarded initial GL resolution; both remain correctly closed.

Live duplicate sweep on 2026-07-29:

  • searched all issues for GPU process isn't usable popup
  • searched for disable-frame-rate-limit Chrome GPU crash
  • searched for Playwright native window GPU exit_code 11
  • inspected the latest 30 open issues
  • no open equivalent found

Problem

The suite's effect-shaped boot probe proves GPU health only at browser birth. It cannot detect a later transition from healthy ANGLE/Metal to repeated GPU-process death during a headed multi-window run.

That creates two false signals:

  1. Product tests fail as if a page, App Worker, or popup lifecycle broke, although Chrome terminated the browser.
  2. A green boot probe can be read as run-wide GPU health even after the measured state has decayed.

The current workaround is process isolation per matrix cell. That is valid evidence isolation, but it is not yet an automated suite contract.

Evidence

Normal-profile command:

NEO_E2E_PORT=8158 npx playwright test   workstation/WorkstationHumanPopupOverlapNL.spec.mjs   -c test/playwright/playwright.config.e2e.mjs   --headed --workers=1

Chrome stderr after the green GL probe:

ContextResult::kTransientFailure: Failed to send GpuControl.CreateCommandBuffer.
GPU process exited unexpectedly: exit_code=11
GPU process exited unexpectedly: exit_code=11
GPU process exited unexpectedly: exit_code=11
FATAL:content/browser/gpu/gpu_data_manager_impl_private.cc:416]
GPU process isn't usable. Goodbye.

Observed matrix boundary:

  • large-over-small alone in a fresh Playwright process: PASS (including early conversion, one target-local proxy, five target choices, two-frame pointer-follow, exact outer-size restoration, and clean retirement).
  • four cells in one serial browser lifecycle: product assertions pass while the browser remains alive; later contexts fail during initial app boot because Chrome has crossed its GPU-crash threshold.
  • each Playwright invocation still starts its own webpack server with reuseExistingServer: false; cross-serving is not implicated.
  • film capture is a separate profile and is not evidence for the ordinary engine-profile failure.

Architectural Reality

  • test/playwright/e2e/utils/gpuIntent.mjs is the launch-argument authority.
  • test/playwright/e2e/gl.setup.mjs is an initial-state gate, not a continuous liveness monitor.
  • test/playwright/playwright.config.e2e.mjs is intentionally serial (workers: 1) for benchmark/native-window stability.
  • --disable-frame-rate-limit must remain in the ordinary profile. Removing it would hide the required engine / OffscreenCanvas surface and is not an acceptable repair.
  • Native windows and the GPU crash threshold are browser-process state. A fresh BrowserContext is insufficient isolation when the browser process survives across tests.

Acceptance Criteria

  • Reduce the failure to a minimal headed witness on current dev, preserving --disable-frame-rate-limit.
  • Identify whether the repeated exit_code=11 is caused by a current launch-flag interaction, Chrome/macOS runtime decay, native-window lifecycle, or another measurable browser-process condition.
  • Preserve the existing green-at-boot ANGLE/Metal assertion while adding a truthful way to distinguish mid-suite GPU death from product failure.
  • Make multi-cell native-window witnesses reliable without silently dropping engine coverage. Acceptable shapes include a proven root-cause repair or explicit per-cell browser-process isolation owned by the harness.
  • Keep reuseExistingServer: false; every Playwright invocation continues to serve its own checkout.
  • Add a regression witness that would fail on the observed green-boot-then-fatal sequence and pass after the chosen repair.
  • Document the evidence boundary between the ordinary engine profile and NEO_FILM_TAKE=1.

Out of Scope

  • Dropping --disable-frame-rate-limit from the ordinary profile.
  • Treating film-mode pixel capture as a substitute for engine-profile coverage.
  • Product-side docking changes from #16117.
  • Reopening or rewriting the resolved truth of #15664 / #15813.

Related

  • #16117 — the popup-over-popup witness that exposed this.
  • #15664 — resolved predecessor: poison GL flags caused the former popup-birth browser kill.
  • #15813 — resolved predecessor: initial GL effect probe.
  • test/playwright/e2e/utils/gpuIntent.mjs
  • test/playwright/e2e/gl.setup.mjs
  • test/playwright/playwright.config.e2e.mjs

Decision Record impact: none.

Origin Session ID: 5f3ec5da-f2a5-45e9-aa47-7c4f3866a06f Retrieval Hint: "green ANGLE Metal boot probe then GPU exit_code 11 native popup churn disable-frame-rate-limit"