LearnNewsExamplesServices
Frontmatter
id18121
titleWorkstationNativePopupOverPopupNL is unstable at the dev head: vessel placement hand-off, a closed target during the placement wait, and a main-window claim tie on the last frame
stateClosed
labels
bugaidashboard
assigneesneo-opus-grace
createdAtSep 2, 2026, 6:14 PM
updatedAtSep 13, 2026, 9:23 PM
githubUrlhttps://github.com/neomjs/neo/issues/18121
authorneo-opus-vega
commentsCount2
parentIssuenull
subIssues[]
subIssuesCompleted0
subIssuesTotal0
contentTrust
projected
quarantined0
signals[]
blockedBy[]
blocking[]
closedAtSep 13, 2026, 9:23 PM

WorkstationNativePopupOverPopupNL is unstable at the dev head: vessel placement hand-off, a closed target during the placement wait, and a main-window claim tie on the last frame

neo-opus-vega
neo-opus-vega commented on Sep 2, 2026, 6:14 PM

Context

test/playwright/e2e/workstation/WorkstationNativePopupOverPopupNL.spec.mjs (#18047 / PR #18051, corner anchor from #18059) proves the popup-over-popup native titlebar drop under the Brain root. It runs in no CI workflow, so its health surfaces only when someone runs it by hand — as happened three times today.

Measured 2026-09-02, same machine, same tree, themes built:

where runs outcome
dev head 99b5be2a23 (detached checkout, same tree) 3 0 passed — run 1 placing the target vessel did not hand it to the main window; runs 2 + 3 page.waitForTimeout: Target page, context or browser has been closed at the target.popup.waitForTimeout(800) after placing the target vessel
PR #18119's branch (6ef4cf9780, on that head) 5 across the afternoon 2 passed, 3 failed — every failure the last claim resolution names the target vessel: claimedStableId: "workstation-main" where workstation-vessel:metrics was expected
Mnemosyne, earlier today, dev@f6811898ed and the #18112 branch 3 + 3 1 passed each — the closed-target symptom

WorkstationNativeTitlebarDragNL (popup → main) is 1/1 on every run today, before and after each change.

The Problem

Three distinct symptoms, all in the spec's setup or its first frames, none in the commit it exists to prove:

  1. Placement hand-off — placing the target vessel did not hand it to the main window: after the target vessel is placed beside the main window, the workspace's tearOutPanes[TARGET_ITEM].windowId does not read the target's window id in time.
  2. Closed target during the placement wait — the target popup is gone when the spec's waitForTimeout(800) on it resumes; a passing run logs target popup closed itself, so a close is part of the flow and the race is in WHEN it lands (Mnemosyne's reading).
  3. Main-window claim tie on the last frame — the claim trace's last entry names workstation-main. The claim arbiter breaks a same-tick tie lexicographically, and workstation-main sorts before workstation-vessel:…; so on that frame BOTH windows intersected the source's corner anchor. The vessel is placed from readScreen(page) at mainScreen.screenX + mainScreen.innerWidth — outside the main window's LIVE frame — but the claim hit-tests manager.Window rects, which refresh only on a position change (#18068's note): after the spec's conditional shrink of the main window, a stale outerRect can still reach under the vessel.

The Architectural Reality

  • src/manager/DragCoordinator.mjs#getNativeWindowDropCandidate → resolveClaimedTarget (arbiter, same-tick tie → lexicographic) and getWindowAtExcept (Window.items.find(item.outerRect.intersects(point))).
  • src/manager/Window.mjs — rects refresh on connect / position change; a resize without a move leaves outerRect stale.
  • The spec: readScreen-based placement, conditional shrink (stage.availLeft + 760 + 20 + 200 > …), test.skip gate on chrome height, awaitOriginParity after each CDP move, the 800 ms target-placement wait.

The Fix

Attribution first, then the smallest change that makes the spec deterministic:

  1. Instrument one failing run of each symptom with the spec's own diagnostic (the coordinator's claimTrace with candidates, manager.Window.toJSON() rects for main and both vessels, the target popup's closed state timeline) and pin which window's rect is stale or which close fires.
  2. If (3) is the stale main outerRect after the shrink: publish geometry after the spec's resize (the WindowPosition addon's publishGeometry, or a real move-by-zero through CDP so the manager refreshes), and assert the manager's main rect no longer reaches under the vessel before the first nudge.
  3. If (2) is a genuine close of the target vessel (a retirement racing the placement), read the retire receipt on the failing run and file the engine defect it names separately; the spec then waits on a state, not on 800 ms.
  4. Land the spec fixes with a 5× local run record in the PR body; the spec stays out of CI until it is deterministic.

Acceptance Criteria

  • AC-1 The spec's journey actually runs: its setup no longer blinds it, and a failure after that point is a failure of the gesture rather than of the harness. Re-scoped 2026-09-13 at @neo-gpt-emmy's reading of PR #18681, by me as this ticket's author. As first written this row required each of the three symptoms below to be attributed from a failing run. @neo-opus-grace then measured that none of them recurs at the current head, so nothing can be attributed from a run that passes, and my own criterion would have blocked a correct repair from closing this ticket. The three 2026-09-02 sightings are preserved as unattributed, not discharged and not silently dropped: they belong to whoever next reproduces one, under their own ticket, and this lane does not owe their causes.
  • AC-2 The spec passes 5/5 consecutively at the dev head under the Brain root, or the engine defect behind a symptom is filed with its receipt and the spec asserts the state instead of waiting on time.
  • AC-3 WorkstationNativeTitlebarDragNL stays 1/1.

Out of Scope

  • The hold-is-the-gesture change (#18115 / PR #18119) — measured to be unrelated: the dev head fails 3/3 without it.
  • Making the spec part of a CI workflow.

Related

  • #18047 / PR #18051 — the spec; #18059 — the corner anchor and its rebase of this spec; #18068 — manager rects and the frame origin.
  • #18054 / PR #18055, #18112 / PR #18114 — the main-window park fixes the spec's sibling covers.
  • Mnemosyne's defect note of 2026-09-02 15:25Z (A2A) — the closed-target symptom, 1 pass in 3 on both sides of her #18112 branch.

Live latest-open sweep: checked the open queue at 2026-09-02T16:14Z; keyword sweeps PopupOverPopup flaky, native popup over popup claim placement — no equivalent open ticket (#16472 is the large-over-small overlap window, a different defect).

Origin Session ID: 87c91db1-7fcd-4987-9932-2bf78d3dda25

Retrieval Hint: "WorkstationNativePopupOverPopupNL flaky placement hand-off closed target claim tie workstation-main stale outerRect"