LearnNewsExamplesServices
Frontmatter
id18432
titleThe engine's tear-out flashes the UA default because it never passes the stagedColorScheme its own Main API accepts
stateClosed
labels
bugdashboard
assigneesneo-opus-grace
createdAtSep 7, 2026, 4:10 AM
updatedAtSep 8, 2026, 7:28 AM
githubUrlhttps://github.com/neomjs/neo/issues/18432
authorneo-opus-grace
commentsCount1
parentIssue18304
subIssues[]
subIssuesCompleted0
subIssuesTotal0
contentTrust
projected
quarantined0
signals[]
blockedBy[]
blocking[]
closedAtSep 8, 2026, 7:28 AM

The engine's tear-out flashes the UA default because it never passes the stagedColorScheme its own Main API accepts

Closed Backlog/active-chunk-22 bugdashboard
neo-opus-grace
neo-opus-grace commented on Sep 7, 2026, 4:10 AM

Serves: #18304 — one of the two seams that epic's seam account identified as belonging in the engine, narrowed to its actionable half by the mechanism correction.

Context

Main.windowOpen opens a blank same-origin staging document before navigating to the real URL, so the child can connect to the shared worker while the opener is warm. That staging realm paints before the app exists, so its colour is whatever the platform defaults to.

The parameter that fixes this already exists and has for some time — Main.mjs:1175:

windowOpen({nativeCapabilities, stagedColorScheme, topologyIdentity=null, url, useTotalHeight=true, windowFeatures, windowName})

Main.mjs:1206-1211 writes it onto the staging document as a color-scheme meta.

The Problem

Exactly one caller passes it.

caller passes stagedColorScheme
apps/workstation/view/Workspace.mjs:2507 yes — schemes[selectedTheme]
src/dashboard/dock/Workspace.mjs#openTearOutVessel no

So a tear-out driven by the engine flashes the user-agent default before the pane appears, and the same gesture in apps/workstation does not — because that app built the compensation itself.

This is the same shape as every other finding in #18304's seam account: the capability exists, the engine does not use it, and the consumer supplies what the engine did not. It is the reason the account lists openTearOutVessel as an engine gap rather than as app policy.

The Architectural Reality

The author's pre-implementation correction supersedes the original worker-side map prescription. The schemes already exist in component theme declarations, and the value is needed by Main.windowOpen on the main thread where computed CSS is available.

The Fix

Declare --neo-color-scheme in each theme's Global.scss. Main.windowOpen defaults an omitted stagedColorScheme through resolveThemeColorScheme(), reading the themed document element. The existing explicit caller value wins; an absent or invalid declaration yields undefined and preserves the existing platform fallback. No theme-name parsing or new worker payload is required.

Acceptance Criteria

  • AC-1: Main.windowOpen defaults stagedColorScheme from the live document's declared theme scheme when the caller supplies none.
  • AC-2: an undeclared or unknown theme supplies no scheme; no value is guessed.
  • AC-3: no theme-name parsing anywhere in the path. theme-cyberpunk declares dark despite its name.
  • AC-4: Workstation's existing explicit schemes[selectedTheme] path remains unchanged and wins.

Constraints

Declared, never inferred. The engine tear-out caller needs no change; the main-thread staging owner resolves the default. The eventual vessel app theme remains outside this ticket under #18304, as does consolidating component-level color-scheme declarations onto this token.

Contract Ledger

Surface Authority Proposed behavior Fallback Docs Evidence
Main.windowOpen / stagedColorScheme Existing staging API and author's AC revision Explicit caller value wins; omitted value defaults from live theme declaration No admitted scheme means no staging meta windowOpen JSDoc Computed-style component case and call-boundary probe
--neo-color-scheme / Main.resolveThemeColorScheme Theme Global.scss declarations Read declared dark/light from the themed document element Unknown, absent, or invalid declaration yields undefined Reader JSDoc and theme tokens Five theme declarations; live dark/light and absence controls

Decision Record impact

none — preserves the staging parameter, adds its document-owned default, and introduces no worker wire change.

Prior art

#18414 / PR #18418 is the sibling half of the same missing capability, reached from the other end: the cross-window placeholder rendered black-on-white under every theme because nothing carried theme values across the tear-out boundary. Two independent defects, one gap.

Filed by @neo-opus-grace (Claude Opus 5), origin session 70502f9a-5b14-4dcf-bcdf-4a29b546df77.