Context
Found on the #18056 lane (native drop anchored on the popup's outer top-left corner) when the popup→popup e2e arm ran with viewport: null, the only configuration in which our popups carry real window chrome. Neo.manager.Window.calculateGeometry labels Chrome's screenLeft/screenTop as the viewport origin (comment: "Chrome/Edge: screenLeft/Top is Viewport position"). Two independent measurements say Chrome reports the frame origin:
- CDP probe, headed Chromium (this host, 2026-09-01):
Browser.setWindowBounds({top: 120}) → window.screenY === 120, with outerHeight - innerHeight === 87. The frame is at 120; the viewport is at 207.
- The operator's live Chrome, read through the Neural Link (Workstation session
15926019…, window 73d7ff8c…): chrome.top: 87, innerRect.y: 33, outerRect.y: -54, innerRect.height: 997, outer height 1084, on a 1728×1117 display. A frame at y = 33 spanning to 1117 is a window filling the screen under the menu bar. A frame at y = −54 is above the screen, which macOS does not allow. So screenTop (33) is the frame top, and the real viewport starts at 120.
Every emulated-viewport Playwright rig has outerHeight === innerHeight (chrome 0), so innerRect === outerRect there and no witness we own can see the mislabel. This ticket separates observation (the two measurements above) from inference (the consumer impact below).
The Problem
With viewportTop = screenTop on Chrome, innerRect is a rect with the frame's origin and the content's size, and outerRect sits chrome.top px above the real frame. Consumers convert between windows by subtracting these rects, so:
- Pointer cross-window path (
DragCoordinator.onDragMove, src/manager/DragCoordinator.mjs :826, :922-923): localY = event.screenY - targetWindow.innerRect.y. MouseEvent.screenY is physical, innerRect.y is the target's frame top, so the target-local point is chrome.top of the target too low — ≈ 87 px into the main window. Inference from code; not yet witnessed on a real Chrome.
- Native titlebar path (
DragCoordinator.getNativeWindowDropCandidate, anchor = outerRect + inset after #18056): the anchor sits chrome.top(popup) - inset above the popup's real frame, and the target-local conversion subtracts the target's frame top, so the error is chrome.top(target) - chrome.top(popup): exact for popup→popup (equal chrome, the errors cancel), ≈ 20 px for popup→main (87 vs 67). Witnessed: the popup→popup arm's park receipt shows the source outerRect.y 67 px above its screenY.
- Park / moveTo consumers (
Workspace.parkTearOutVessel, resolveVesselConversionSourceRect, windowNativeMoveTo targets; src/ai/Client.mjs, src/ai/client/InteractionService.mjs): window.moveTo positions the frame, so code that feeds frame-based "inner" rects to it is accidentally consistent today and would need the matching conversion when the rects become true viewport rects.
History: the model was chosen on #8164 (2025-12-27) — "Chrome/Edge: screenLeft/Top = viewport position; Safari: frame position, so add chrome height to get viewport; Firefox: mozInnerScreenX/Y" — replacing an earlier headerHeight subtraction. The Safari branch is the one that matches what Chrome actually reports. Related coordinate-basis history: #15924 / #15934 (screenLeft basis, closed), #16472 (large-over-small overlap, open, suspects window chrome/geometry).
The Architectural Reality
src/manager/Window.mjs calculateGeometry(data) :69-117: viewportLeft/Top branches — Firefox (mozInnerScreenX/Y), Safari (screenLeft + sideBorder, screenTop + topChrome), default/Chrome (screenLeft, screenTop). innerRect = (viewportLeft, viewportTop, innerWidth, innerHeight), outerRect = (viewportLeft - sideBorder, viewportTop - topChrome, outerWidth, outerHeight).
- Sensor:
src/main/addon/WindowPosition.mjs publishes raw screenLeft/screenTop (:86, :144); Neo.Main.getWindowData supplies outerHeight/innerHeight and mozInnerScreenX/Y.
- Consumers of
innerRect/outerRect (tree-wide): src/manager/Window.mjs, src/manager/DragCoordinator.mjs, src/ai/Client.mjs, src/ai/client/InteractionService.mjs, apps/workstation/view/Workspace.mjs.
- Rigs: every e2e spec without
viewport: null emulates the screen at the viewport size and gets chrome 0; WorkstationNativePopupOverPopupNL (viewport: null) is the one arm that carries real chrome today.
The Fix
calculateGeometry: treat Chrome/Edge like Safari — screenLeft/Top is the frame origin; viewport = frame + chrome. Keep the Firefox branch. Correct the JSDoc/comment that states the opposite. Decide the Safari branch by measurement, not by the current comment.
- Consumer audit, one row each, each either "unaffected" or converted: the two DragCoordinator conversions; the Workstation park/
moveTo geometry; ai/Client and InteractionService window placement.
- Witnesses: a unit test on
calculateGeometry per branch with the two probe payloads above; a viewport: null e2e receipt that manager.Window.get(popup).outerRect.y equals the CDP frame top and innerRect.y equals frame top + (outerHeight - innerHeight); the #18056 main arm's corner correction step reads a zero residual with no correction move.
- Operator hand check on a real Chrome: a cross-window pointer drag into the main window previews the zone under the pointer, and the native corner anchor's region overlay paints beside the popup's physical corner.
Contract Ledger
| Target surface |
Source of authority |
Proposed behavior |
Fallback |
Docs |
Evidence |
Neo.manager.Window#calculateGeometry Chrome branch |
src/manager/Window.mjs:69 |
screenLeft/Top = frame origin; innerRect = frame + chrome |
Firefox branch unchanged |
JSDoc + inline comment |
unit witness with the two measured payloads |
Neo.manager.Window innerRect / outerRect semantics |
same |
innerRect = true viewport on screen; outerRect = true frame |
— |
JSDoc |
viewport: null e2e receipt |
Neo.manager.DragCoordinator local conversions |
src/manager/DragCoordinator.mjs:826, :922 |
unchanged code, corrected inputs |
— |
— |
pointer arm with real chrome + hand check |
Workstation park / moveTo geometry |
apps/workstation/view/Workspace.mjs (parkTearOutVessel) |
audited: frame vs viewport made explicit at each moveTo |
— |
JSDoc |
popup→popup arm |
Decision Record impact
aligned-with ADR 0029 (docking design: the multi-window model assumes one shared screen coordinate basis; this restores it). Amends the #8164 branch choice with measurements.
Acceptance Criteria
Out of Scope
- The anchor choice and the zone grammar of the native drop (#18056).
- Firefox behaviour (
mozInnerScreenX/Y is already the viewport).
- Multi-display / DPR questions beyond the single-basis correction.
Avoided Traps
- Correcting in the sensor (
WindowPosition / Neo.Main): the manager is the one place that interprets raw browser geometry (#8164's own separation); keep the sensor raw.
- Adding an offset in one consumer (e.g. subtracting
chrome.top in DragCoordinator only): that was the pre-#8164 headerHeight patch and it hid the model error; fix the model.
- Trusting the emulated rigs: they cannot fail on this by construction; the witness must carry real chrome.
Related
#8164 (geometry model origin) · #15924 / #15934 (coordinate-basis family) · #16472 (open, chrome/geometry suspect) · #18056 (corner anchor; the lane that surfaced this) · #15239 (multi-window epic)
Live latest-open sweep: checked the latest 20 open issues at 2026-09-01T23:42Z; no equivalent. A2A claim sweep: no overlapping lane-claim in the last hour.
Origin Session ID: 93fd8de9-7231-4979-b906-c050bcfc25a4
Retrieval Hint: query_raw_memories("Chrome screenTop frame origin viewport manager.Window calculateGeometry chrome height cross-window rect")
Context
Found on the #18056 lane (native drop anchored on the popup's outer top-left corner) when the popup→popup e2e arm ran with
viewport: null, the only configuration in which our popups carry real window chrome.Neo.manager.Window.calculateGeometrylabels Chrome'sscreenLeft/screenTopas the viewport origin (comment: "Chrome/Edge: screenLeft/Top is Viewport position"). Two independent measurements say Chrome reports the frame origin:Browser.setWindowBounds({top: 120})→window.screenY === 120, withouterHeight - innerHeight === 87. The frame is at 120; the viewport is at 207.15926019…, window73d7ff8c…):chrome.top: 87,innerRect.y: 33,outerRect.y: -54,innerRect.height: 997, outer height 1084, on a 1728×1117 display. A frame at y = 33 spanning to 1117 is a window filling the screen under the menu bar. A frame at y = −54 is above the screen, which macOS does not allow. SoscreenTop(33) is the frame top, and the real viewport starts at 120.Every emulated-viewport Playwright rig has
outerHeight === innerHeight(chrome 0), soinnerRect === outerRectthere and no witness we own can see the mislabel. This ticket separates observation (the two measurements above) from inference (the consumer impact below).The Problem
With
viewportTop = screenTopon Chrome,innerRectis a rect with the frame's origin and the content's size, andouterRectsitschrome.toppx above the real frame. Consumers convert between windows by subtracting these rects, so:DragCoordinator.onDragMove,src/manager/DragCoordinator.mjs:826,:922-923):localY = event.screenY - targetWindow.innerRect.y.MouseEvent.screenYis physical,innerRect.yis the target's frame top, so the target-local point ischrome.topof the target too low — ≈ 87 px into the main window. Inference from code; not yet witnessed on a real Chrome.DragCoordinator.getNativeWindowDropCandidate, anchor =outerRect + insetafter #18056): the anchor sitschrome.top(popup) - insetabove the popup's real frame, and the target-local conversion subtracts the target's frame top, so the error ischrome.top(target) - chrome.top(popup): exact for popup→popup (equal chrome, the errors cancel), ≈ 20 px for popup→main (87 vs 67). Witnessed: the popup→popup arm's park receipt shows the sourceouterRect.y67 px above itsscreenY.Workspace.parkTearOutVessel,resolveVesselConversionSourceRect,windowNativeMoveTotargets;src/ai/Client.mjs,src/ai/client/InteractionService.mjs):window.moveTopositions the frame, so code that feeds frame-based "inner" rects to it is accidentally consistent today and would need the matching conversion when the rects become true viewport rects.History: the model was chosen on #8164 (2025-12-27) — "Chrome/Edge: screenLeft/Top = viewport position; Safari: frame position, so add chrome height to get viewport; Firefox: mozInnerScreenX/Y" — replacing an earlier
headerHeightsubtraction. The Safari branch is the one that matches what Chrome actually reports. Related coordinate-basis history: #15924 / #15934 (screenLeft basis, closed), #16472 (large-over-small overlap, open, suspects window chrome/geometry).The Architectural Reality
src/manager/Window.mjscalculateGeometry(data):69-117:viewportLeft/Topbranches — Firefox (mozInnerScreenX/Y), Safari (screenLeft + sideBorder,screenTop + topChrome), default/Chrome (screenLeft,screenTop).innerRect = (viewportLeft, viewportTop, innerWidth, innerHeight),outerRect = (viewportLeft - sideBorder, viewportTop - topChrome, outerWidth, outerHeight).src/main/addon/WindowPosition.mjspublishes rawscreenLeft/screenTop(:86,:144);Neo.Main.getWindowDatasuppliesouterHeight/innerHeightandmozInnerScreenX/Y.innerRect/outerRect(tree-wide):src/manager/Window.mjs,src/manager/DragCoordinator.mjs,src/ai/Client.mjs,src/ai/client/InteractionService.mjs,apps/workstation/view/Workspace.mjs.viewport: nullemulates the screen at the viewport size and gets chrome 0;WorkstationNativePopupOverPopupNL(viewport: null) is the one arm that carries real chrome today.The Fix
calculateGeometry: treat Chrome/Edge like Safari —screenLeft/Topis the frame origin; viewport = frame + chrome. Keep the Firefox branch. Correct the JSDoc/comment that states the opposite. Decide the Safari branch by measurement, not by the current comment.moveTogeometry;ai/ClientandInteractionServicewindow placement.calculateGeometryper branch with the two probe payloads above; aviewport: nulle2e receipt thatmanager.Window.get(popup).outerRect.yequals the CDP frame top andinnerRect.yequals frame top +(outerHeight - innerHeight); the #18056 main arm's corner correction step reads a zero residual with no correction move.Contract Ledger
Neo.manager.Window#calculateGeometryChrome branchsrc/manager/Window.mjs:69screenLeft/Top= frame origin;innerRect= frame + chromeNeo.manager.WindowinnerRect/outerRectsemanticsinnerRect= true viewport on screen;outerRect= true frameviewport: nulle2e receiptNeo.manager.DragCoordinatorlocal conversionssrc/manager/DragCoordinator.mjs:826, :922moveTogeometryapps/workstation/view/Workspace.mjs(parkTearOutVessel)moveToDecision Record impact
aligned-with ADR 0029 (docking design: the multi-window model assumes one shared screen coordinate basis; this restores it). Amends the #8164 branch choice with measurements.
Acceptance Criteria
calculateGeometry: the CDP payload (screenTop 120, outerHeight - innerHeight 87) yieldsouterRect.y 120,innerRect.y 207; the operator payload (screenTop 33, chrome 87) yieldsouterRect.y 33,innerRect.y 120. Firefox branch unchanged.viewport: nulle2e receipt: for a popup withouterHeight > innerHeight,manager.Window.get(popup).outerRect.yequals the CDP frame top (±1) andinnerRect.yequals frame top + chrome.innerRect/outerRectconsumer named, marked unaffected or converted, with its witness.WorkstationNativeTitlebarDragNL: the corner-anchor correction step reports a zero residual without a correction move (the aimed DOM point and the coordinator's anchor coincide on real chrome).Out of Scope
mozInnerScreenX/Yis already the viewport).Avoided Traps
WindowPosition/Neo.Main): the manager is the one place that interprets raw browser geometry (#8164's own separation); keep the sensor raw.chrome.topinDragCoordinatoronly): that was the pre-#8164headerHeightpatch and it hid the model error; fix the model.Related
#8164 (geometry model origin) · #15924 / #15934 (coordinate-basis family) · #16472 (open, chrome/geometry suspect) · #18056 (corner anchor; the lane that surfaced this) · #15239 (multi-window epic)
Live latest-open sweep: checked the latest 20 open issues at 2026-09-01T23:42Z; no equivalent. A2A claim sweep: no overlapping lane-claim in the last hour.
Origin Session ID: 93fd8de9-7231-4979-b906-c050bcfc25a4
Retrieval Hint:
query_raw_memories("Chrome screenTop frame origin viewport manager.Window calculateGeometry chrome height cross-window rect")