LearnNewsExamplesServices
Frontmatter
id19288
titleHeadless Chrome's 800 px screen clamps every script-moved popup
stateClosed
labels
bugaitest
assigneesneo-opus-grace
createdAtSep 26, 2026, 3:49 PM
updatedAtSep 27, 2026, 12:37 PM
githubUrlhttps://github.com/neomjs/neo/issues/19288
authorneo-opus-grace
commentsCount2
parentIssuenull
subIssues[]
subIssuesCompleted0
subIssuesTotal0
contentTrust
projected
quarantined0
signals[]
blockedBy[x] 19285 The tab Overflow projection withholds a focused tab and drops focus to the body, [x] 19303 Drag start throws when the pressed node is replaced during the start delay
blocking[ ] 19297 Large-over-small NL arms assert the old proxy and never run headless
closedAtSep 27, 2026, 12:37 PM

Headless Chrome's 800 px screen clamps every script-moved popup

neo-opus-grace
neo-opus-grace commented on Sep 26, 2026, 3:49 PM

Context

Several of #17844's census rows are classed environment-bound ("headed-only"). Measured today, at least one of them is bound by a single launch default: headless Chrome gives every window an 800×600 screen, and the window manager clamps a script-moved popup into it. A test's CDP placement is not clamped, so a spec can stage a target popup off that screen, and the product's own window.moveTo then cannot follow it there.

The Problem

DemoBPerspectivesNL stalls in its cross-window step. The conversion park moves the torn-out vessel to the target's origin with Neo.Main.windowNativeMoveTo(822, 22). #moveWindow polls 6 × 50 ms, sees the popup at x = 320 and answers false, so the park is refused (refusedAt: 'move') and re-proposed about every 670 ms. The tour's step never completes, and the spec's 10 s hosting poll reports "the tour has not reached its cross-window step". A main-thread trail of parkWindowDrag / windowNativeMoveTo / windowNativeFocus recorded the loop.

x = 320 is 800 − 480. A standalone probe with the e2e channel (chrome, headless) opens a 480×360 popup and calls moveTo:

launch screen.width moveTo(900, 20) lands at moveTo(1400, 20) lands at
default 800 320, 20 320, 20
--screen-info={1920x1080} 1920 900, 20 1400, 20
--window-size=1920,1080 800 not moved not moved

With the overlay --screen-info={1920x1080}, DemoBPerspectivesNL passes the hosting poll: the popup hosts the live Workbench pane. It then fails at the next assertion, "worker truth must show the original instance mounted once into the popup", which is a separate question for the next owner.

The Architectural Reality

  • The e2e browser's arguments are declared once in test/playwright/e2e/utils/gpuIntent.mjs: BASE_LAUNCH_ARGS, shared by PRESENTING_LAUNCH_ARGS and ENGINE_LAUNCH_ARGS. playwright.config.e2e.mjs launches the local chrome channel with activeLaunchArgs().
  • Specs that set contextOptions.screen change only what window.screen reports; the window manager still clamps to the real headless screen.
  • Neo.Main#moveWindow verifies the requested coordinates, which is correct: the clamp is real, and the product reports it truthfully.

The Fix

Give the headless browser a realistic screen: add --screen-info={1920x1080} to BASE_LAUNCH_ARGS. The switch belongs to Chrome's headless mode; this ticket must confirm that a headed run ignores it before relying on that.

Acceptance Criteria

  • AC-1: BASE_LAUNCH_ARGS carries --screen-info={1920x1080}, with JSDoc stating why: the clamp, plus the probe table above in short.
  • AC-2: A headless census of the NL battery with the change, diffed by title against the 22 at a9abb6c1dc (#17844 trap 1). Each environment-bound row is re-classified: DemoBPerspectivesNL, DockPlacementNL (needs 1,620 px), WorkstationTearOutSourceContinuityNL (needs 1,200 px) and DemoBCrossWindowDragNL ×3. The last three are predictions, not measurements.
  • AC-3: No row that is green today turns red. WorkstationNativePopupOverPopupNL's rig chooses its stage by screen size (#19260) and now takes the large-stage branch; it must stay green.
  • AC-4: CI's e2e-engine tier is green at the head, since it runs headless with these arguments.
  • AC-5: A headed run shows screen.width equal to the real display's, proving the switch is headless-only. Run it on the operator's go, because headed runs place windows on his displays.

Out of Scope

  • DemoBPerspectivesNL's next assertion (the instance mounts once into the popup): a separate ticket once measured.
  • Product placement code: it reports the clamp truthfully.

Related

#17844 · #19260 (the rig that adapted to the 800 px screen) · #18698 (placeBesideSource skips the fit test under emulation) · gpuIntent.mjs author: Emmy (#16138, #16160)

Live latest-open sweep: latest 20 open at 2026-09-26T13:49:23Z, plus gh search issues for "headless screen" and "screen-info"; no equivalent (only #17844 and closed issues). A2A sweep: latest 30, all read states; no claim on a headless screen size. MC sweep: "headless Chrome 800x600 screen clamps popup moveTo, native placement rows only pass headed", 10 results. Prior notes name the clamp's symptoms (a 1200 px native display, an unclamped moveTo); no decision on the launch default. Own-assignment sweep: #17844 is the parent census, and no open ticket of mine covers this. Origin Session ID: 81d1894c-d8fd-4192-8350-42e32eb0101e Retrieval Hint: "headless 800x600 screen clamps window.moveTo popup screen-info 1920x1080 park refused move DemoBPerspectivesNL"

tobiu referenced in commit 95493e4 - "test(e2e): headless Chrome gets a 1920×1080 screen, so script-moved popups are not clamped (#19288) (#19309) on Sep 27, 2026, 12:37 PM
tobiu closed this issue on Sep 27, 2026, 12:37 PM