LearnNewsExamplesServices
Frontmatter
id19988
titleAn in-window tab drag sends a strip header flying to the window's top-left
stateClosed
labels
bugaidashboard
assigneesneo-gemini-maryam
createdAtOct 22, 2026, 11:54 AM
updatedAtOct 22, 2026, 6:33 PM
githubUrlhttps://github.com/neomjs/neo/issues/19988
authorneo-opus-ada
commentsCount1
parentIssuenull
subIssues[]
subIssuesCompleted0
subIssuesTotal0
contentTrust
projected
quarantined2
signals[]
blockedBy[]
blocking[]
closedAtOct 22, 2026, 6:33 PM

An in-window tab drag sends a strip header flying to the window's top-left

Closed Backlog/active-chunk-10 bugaidashboard
neo-opus-ada
neo-opus-ada commented on Oct 22, 2026, 11:54 AM

Context

Found in manual testing of apps/workstation on dev (2026-10-22): resorting tab headers in the pane that holds 12 tabs. In @tobiu's screen recording (about 39.4–41.6 s), "Runtime Health Envelope" is dragged and the pointer rises toward the workspace's top edge. Meanwhile the only other visible header, "Distributed Trace Explorer", leaves its strip. It rises above its row, is clipped by the pane's top border, disappears, and reappears above the strip further left. The headers "fly away" toward the top-left.

A further frame from the same drag (the operator's screenshot follows in a comment) shows "Priority Alert Observatory" being dragged inside its pane. Meanwhile the other header's teal active-tab underline sits outside the pane, over the neighbouring pane's header to the left.

Measurements

Headless Chromium, 2200×1000, at 8bb3574d0f (its src/, apps/ and resources/scss/ are identical to dev at 84b711878a). A requestAnimationFrame sampler records every tab button's rect against the strip box.

gesture tab buttons outside the strip during the drag
2nd visible tab, 180 px left, in-strip none
2nd visible tab, into the pane body and back none
2nd visible tab, 45 px rise above the strip and back, leftwards none
3rd visible tab ("Workspace Topology Inspector"), 120 px right, 45 px rise and back 126 frames, 2 of 2 runs: the button is absolutely positioned and travels from the strip (y 105) to (−180, 0), the window's top-left corner offset by its own width

The reproduction moves the dragged tab's own strip button; the recording moves its sibling. Both are strip headers absolutely positioned and sent toward the top-left during an in-window drag.

The Problem

During a tab drag the strip's SortZone positions its items absolutely, freezing their rects for the gesture. A 45 px rise takes the roughly 32 px proxy fully out of the 33 px strip. That is the base container.SortZone's boundary-exit condition (detachThreshold, then isWindowDragging and dragBoundaryExit), and the dock's TabSortZone layers its window-drag embodiment on top (startWindowDrag / endWindowDrag). That this path is entered during the reproducing gesture is inferred, not traced.

At least one header gets coordinates that are not its strip slot, and a CSS transition makes the move a visible flight across the window. Which write does it is not yet traced.

Design authority: the dock TabSortZone#startWindowDrag docblock. "No dashboard layout re-flow: a tab strip's geometry is owned by the committed model projection, which this gesture has not touched." A header leaving its strip while the gesture is still in-window contradicts that.

The Architectural Reality

  • src/draggable/container/SortZone.mjs: the absolute-positioning setup for sortable items, the boundary-exit / window-drag transition (detachThreshold, reattachThreshold, dragBoundaryExit), and the cleanup that restores item styles.
  • src/dashboard/dock/interaction/TabSortZone.mjs: startWindowDrag / endWindowDrag (in-window proxy hidden or restored, base reorder parked or un-parked), plus the cross-zone events on every move.
  • Prior art: a returned tab header kept absolute drag positioning (top: 0) outside its strip after a drag, on 2026-10-07 in another consumer. That is the same item-styles seam, after the drag rather than during it.

The Fix

First trace which write sends the button to (−180, 0): the base SortZone's park or window-drag path, or the dock's startWindowDrag. Then keep every strip header inside its strip slot for the whole in-window gesture. Hiding a header that is not shown (e.g. the dragged original) must not move it across the window, and its transition must not animate it there.

Acceptance Criteria

  • During any in-window tab drag, including rises out of the strip and returns, no tab button's rect leaves the strip box, and no header animates across the window.
  • After the drop, every header sits in its committed slot with no residual absolute positioning.
  • E2E: a new spec under test/playwright/e2e/workstation/ (e.g. WorkstationTabDragHeadersStayNL.spec.mjs) drags the 12-tab pane's 3rd visible tab with the reproducing gesture (120 px right, a 45 px rise above the strip, back down) using a real pointer. It samples every frame and asserts all tab buttons stay inside the strip. It must be red on dev (126 frames outside, (−180, 0)) and green with the fix, and it joins the hosted Workstation tier (#19655).
  • Existing tab sort-zone and dock drag specs stay green.

Out of Scope

  • The flash after the drop: #19987, the overflow plugin's recapture window.
  • Cross-pane and edge-preview behaviour of a docked pane's tab drag, which is legitimate in a docked pane. For the maximized case see #19986.

Related

  • #19986: a tab drag in a maximized pane targeting the layout behind it. Same gesture family, maximized.
  • #19533 (closed): a vessel parked at the display's top-left during a cross-window drag.

Live latest-open sweep: checked latest 20 open issues at 2026-10-22T09:52:58Z; no equivalent found. Keyword sweep: as for the sibling ticket filed with this one; closed adjacent only. A2A claim sweep: no overlapping lane-claim. MC sweep: "tab header resorting flickers on drop… headers fly to the top-left…", 6 results; the 2026-10-07 retained-absolute-position finding is adjacent, not a decision. Own-assignment sweep: none overlapping.

Origin Session ID: 70e59a84-efd6-4e7a-9262-c5478bd314ff Retrieval Hint: "tab drag strip header flies to top-left, SortZone absolute positioning, window-drag boundary exit"

tobiu referenced in commit b353c5a - "fix(draggable): exclude unrendered overflow items from SortZone drag snapshot (#19988) (#20005) on Oct 22, 2026, 6:33 PM
tobiu closed this issue on Oct 22, 2026, 6:33 PM