Context
Seen in the App Worker console during the D#18224 popup-birth arm (apps/workstation at dev@2ee23d7801, Playwright e2e rig): every scroll of the Feed grid logs two warnings —
sendMessage destination "main" is deprecated. Use a windowId instead.
{"action":"remoteMethod","data":{"id":"neo-base-33"},"destination":"main","remoteClassName":"Neo.main.addon.GridRowHoverSync","remoteMethod":"suspendHover"}
… remoteMethod: "resumeHover"neo-base-33 is the grid's Neo.grid.ScrollManager. The warning is the engine telling us the call carried no routing key and went to the first connected port (src/worker/Base.mjs:478–484) — the same routing class #18276 found for the Workspace geometry arm.
The Problem
ScrollManager#suspendGridRowHoverSyncAddon and #resumeGridRowHoverSyncAddon (src/grid/ScrollManager.mjs:227–246) resolve the addon for the right window — Neo.currentWorker.getAddon('GridRowHoverSync', windowId) — and then call it with {id: me.id} only. The remote-method proxy routes on the payload's windowId; without one the message falls back to ports[0]. In a single window that is the same window, so only the warning shows. With the grid in a popup (the pop-out the arm measured), ports[0] is the opener: its GridRowHoverSync addon receives suspendHover/resumeHover for an id it never registered and does nothing, while the popup's addon, which does hold the registration, is never told — so hover sync is not suspended while the popped-out grid scrolls. (Derived from the routing; the popup-side effect is not yet measured — the arm's headed scroll ran in the opener.)
The sibling in the same class already does it right: updateGridHorizontalScrollSyncAddon passes windowId in both register and unregister payloads (:340–350).
The Fix
Pass windowId in both hover-sync payloads (addon.suspendHover({id: me.id, windowId}), same for resume) — two lines, mirroring the horizontal-sync sibling. Consider one private callRowHoverSyncAddon(method, windowId) so the two methods stop diverging.
Contract Ledger Matrix
| Target Surface |
Source of Authority |
Proposed Behavior |
Fallback |
Docs |
Evidence |
ScrollManager#suspendGridRowHoverSyncAddon / resume… (:227–246) |
worker/Base#sendMessage routing contract; sibling :340–350 |
payload carries windowId; the call reaches the window that holds the registration |
— |
method docblocks |
no deprecated-destination warning during a scroll; a popped-out grid's hover sync suspends in its own window |
Decision Record impact
none.
Acceptance Criteria
Out of Scope
- The geometry arm's routing (#18276) and the row
windowId relay (#18291, PR #18294) — same class, separate leaves.
- Retiring the
ports[0] fallback itself: the deprecation warning is doing its job; this leaf removes one caller.
Related
- #18276 · #18291 / PR #18294 · D#18224 popup-birth arm receipt (worker console tail) ·
src/main/addon/GridRowHoverSync.mjs.
Live latest-open sweep: the latest 15 open issues (created-desc, 2026-09-04 15:17Z) — none equivalent (#18292 … #18215). Issue search "GridRowHoverSync windowId" (all states): none. A2A claim sweep (all read-states, last 60 min): none on the grid scroll surface. Memory Core sweep: no prior note on this routing. Own-assignment sweep: none.
unowned-rationale: a two-line routing fix with a red-first unit; claimable by any seat; found as a side receipt of a peer-role arm, not on my lanes.
Origin Session ID: ee061205-8271-4458-b73b-b132c1bec310
Retrieval Hint: query_raw_memories("ScrollManager GridRowHoverSync suspendHover windowId ports[0] deprecated destination main")
Context
Seen in the App Worker console during the D#18224 popup-birth arm (
apps/workstationatdev@2ee23d7801, Playwright e2e rig): every scroll of the Feed grid logs two warnings —sendMessage destination "main" is deprecated. Use a windowId instead. {"action":"remoteMethod","data":{"id":"neo-base-33"},"destination":"main","remoteClassName":"Neo.main.addon.GridRowHoverSync","remoteMethod":"suspendHover"} … remoteMethod: "resumeHover"neo-base-33is the grid'sNeo.grid.ScrollManager. The warning is the engine telling us the call carried no routing key and went to the first connected port (src/worker/Base.mjs:478–484) — the same routing class #18276 found for the Workspace geometry arm.The Problem
ScrollManager#suspendGridRowHoverSyncAddonand#resumeGridRowHoverSyncAddon(src/grid/ScrollManager.mjs:227–246) resolve the addon for the right window —Neo.currentWorker.getAddon('GridRowHoverSync', windowId)— and then call it with{id: me.id}only. The remote-method proxy routes on the payload'swindowId; without one the message falls back toports[0]. In a single window that is the same window, so only the warning shows. With the grid in a popup (the pop-out the arm measured),ports[0]is the opener: itsGridRowHoverSyncaddon receivessuspendHover/resumeHoverfor an id it never registered and does nothing, while the popup's addon, which does hold the registration, is never told — so hover sync is not suspended while the popped-out grid scrolls. (Derived from the routing; the popup-side effect is not yet measured — the arm's headed scroll ran in the opener.)The sibling in the same class already does it right:
updateGridHorizontalScrollSyncAddonpasseswindowIdin bothregisterandunregisterpayloads (:340–350).The Fix
Pass
windowIdin both hover-sync payloads (addon.suspendHover({id: me.id, windowId}), same for resume) — two lines, mirroring the horizontal-sync sibling. Consider one privatecallRowHoverSyncAddon(method, windowId)so the two methods stop diverging.Contract Ledger Matrix
ScrollManager#suspendGridRowHoverSyncAddon/resume…(:227–246)worker/Base#sendMessagerouting contract; sibling:340–350windowId; the call reaches the window that holds the registrationDecision Record impact
none.Acceptance Criteria
ScrollManagerwhosewindowIdis'w2'callssuspendHoverandresumeHoverwithwindowId: 'w2'in the payload (today: nowindowId).sendMessage destination "main" is deprecatedwarning forGridRowHoverSync.Out of Scope
windowIdrelay (#18291, PR #18294) — same class, separate leaves.ports[0]fallback itself: the deprecation warning is doing its job; this leaf removes one caller.Related
src/main/addon/GridRowHoverSync.mjs.Live latest-open sweep: the latest 15 open issues (created-desc, 2026-09-04 15:17Z) — none equivalent (#18292 … #18215). Issue search "GridRowHoverSync windowId" (all states): none. A2A claim sweep (all read-states, last 60 min): none on the grid scroll surface. Memory Core sweep: no prior note on this routing. Own-assignment sweep: none.
unowned-rationale: a two-line routing fix with a red-first unit; claimable by any seat; found as a side receipt of a peer-role arm, not on my lanes.
Origin Session ID: ee061205-8271-4458-b73b-b132c1bec310
Retrieval Hint:
query_raw_memories("ScrollManager GridRowHoverSync suspendHover windowId ports[0] deprecated destination main")