LearnNewsExamplesServices
Frontmatter
id20004
titleA drag inside a popup lying over the main window is carried into main
stateClosed
labels
bugaidashboard
assigneesneo-opus-grace
createdAtOct 22, 2026, 4:45 PM
updatedAtOct 22, 2026, 11:25 PM
githubUrlhttps://github.com/neomjs/neo/issues/20004
authorneo-opus-grace
commentsCount1
parentIssuenull
subIssues[]
subIssuesCompleted0
subIssuesTotal0
contentTrust
projected
quarantined0
signals[]
blockedBy[]
blocking[]
closedAtOct 22, 2026, 11:25 PM
milestonev13.3.1

A drag inside a popup lying over the main window is carried into main

Closed Backlog/active-chunk-10 bugaidashboard
neo-opus-grace
neo-opus-grace commented on Oct 22, 2026, 4:45 PM

Context

Found while fixing #19990 (Workstation; headless Chrome through the Neural Link fixture). A popup opened by the header pop-out sits where its pane sat, so it lies over the main window. In the run: main at screen (22, 22) 1280×720, the popup at (1070, 143) 320×240, overlapping for x 1070–1302.

The Problem

A tab drag that never leaves the popup, parked at a popup point main also covers (screen 1242, 263), is claimed by main. The coordinator's claim trace reads outcome: claimed, claimedStableId: workstation-main, and the release transfers the tab out of the popup into main (transferItem, popup → workstation-main, target splitNode on right-bottom-tabs). The drop lands in a window the popup hides.

  • Identical on dev (8abdcf978c) and on #19990's branch.
  • With #19990 the same claim also takes a detached drag that comes back over the popup: the re-entry into the source window is never reached where main lies beneath.
  • Likely the "not always" in #19990's report: wherever the popup overlapped main, drags inside it were carried there.

The Architectural Reality

  • TabSortZone#onDragMove hands every move frame to Neo.manager.DragCoordinator#onDragMove. resolveClaimedTarget skips only the source window (skipped: 'source-or-excluded'); any other window of the group whose inner rect contains the pointer can claim. Nothing models the source window lying above the windows beneath it.
  • TabSortZone#resolveRemoteDragTransition engages a claim whenever the zone has a drag rect and opts into vessel conversion. Without the opt-in (popups on dev) the coordinator's generic path engages it anyway.
  • Design authority: ADR 0029 §2.8.6 (amended 2026-10-09): "inside a window it is that window's tab-header proxy, outside every window it is a vessel, the rule re-entry into the source window always followed." It does not say which window owns a point two windows of the group cover; §2.8.1's claim protocol resolves overlap among targets only. The record is silent on source-versus-target overlap, so this ticket carries a fork, not a fix.

The Fork

A page cannot read window order. Two facts are known: a press fronts the window it lands in, and a scripted popup opens above its opener (#19533).

  1. The source window owns every point inside its own bounds for the gesture. Recommended: the press is the only window-ordering event inside a gesture, and the riding vessel, fronted at birth, refuses claims until its pane lands. Falsifier: a window manager that does not raise on press would leave a popup above the source unreachable in the overlap. Effect on main-sourced drags: a popup lying over main is a target only where it does not cover main, which is all main's raise leaves visible.
  2. Track window order from focus events and resolve overlaps by it. Falsifier: every focus change must reach the App worker before the next claim frame; inside a gesture it reduces to 1.
  3. Keep the current resolution and record it in §2.8.1. Falsifier: the operator's #19990 recording.

Acceptance Criteria

  • The fork is decided, and ADR 0029 §2.8.1 / §2.8.6 state the overlap rule.
  • A drag inside a popup lying over main stays in the popup: its preview and its commit are the popup's, and main claims nothing. Witness: a Neural Link e2e arm with the popup over main, red on dev.
  • Main-sourced drags into popups behave as the chosen rule says; existing Workstation arms that encode the old resolution are updated with the decision, not deleted.

Out of Scope

  • What a vessel does over another window (#19533).
  • Why a popup opens over main (placement).

Related

#19990 (found there; its e2e aims where the windows do not overlap) · #19533 · #15239 (the choreography epic; past its sub-issue budget, so not linked) · #15246 (claim arbitration)

Live latest-open sweep: checked latest 20 open issues at 2026-10-22T14:43:03Z, plus gh search issues for "popup overlaps main drag claimed" and "claim overlap source window"; no equivalent found. A2A claim sweep: latest 30 messages at 2026-10-22T14:44Z; no overlapping lane-claim. MC sweep: "drag inside a popup window lands in the main window behind it where the popup overlaps main", 6 results; #19533's window-order census settles vessel-versus-main order only, no prior decision on source-versus-target overlap. Own-assignment sweep: 5 open, none overlapping (#19919 is a target refusing a claim, not this).

Origin Session ID: cdb5023d-349c-443c-b1ad-d8c57688c97c Retrieval Hint: "drag inside a popup over the main window carried into main, claim pass skips only the source window"

tobiu referenced in commit b0af996 - "fix(drag): a point inside the source's frame is the source's for the whole gesture (#20004) (#20016)" on Oct 22, 2026, 11:25 PM
tobiu closed this issue on Oct 22, 2026, 11:25 PM