Context
After a warm F5 in a two-root Workstation, the #17844 battery's WorkstationTopologyGroupsNL arms fail in 4 of 6 runs with App Worker: Error: Target worker '<uuid>' does not exist. This holds even with #19056's and #19060's fixes applied (recorded on #19060). The <uuid> is a window id, not a worker name. That text is thrown by the main thread's worker/Manager.mjs:612, and main relays any dest that is not itself to a worker of that name.
The Problem
worker.Base#sendMessage (SharedWorker branch, src/worker/Base.mjs) resolves a port through a cascade:
getPort({windowId: dest}) || getPort({id: dest})
- then
opts.port
- then
opts.windowId
- then
opts.appName
For a message addressed to a window that has departed, steps 1–3 miss and step 4 resolves a sibling window of the same app. The message then lands in that sibling's main thread with destination set to the departed window id. Main treats the id as a worker name and rejects, and the rejection returns to the App Worker as a failure attributed to the wrong window.
Reproduced on dev@58d69efa32 with a unit stub holding two ports of app App. After removePort(win-a), sendMessage('win-a', {appName: 'App', windowId: 'win-a', …}) posts to win-b (POSTED_TO_SIBLING 1).
The block's own last-resort comment names the hazard: "delivering a keyed message to an arbitrary port would misroute it into a foreign window". The appName step does exactly that for a departed window.
The Architectural Reality
- The
appName step exists for a real case: a stale opts.port between receipt and reply, where the same logical target re-registered.
isWindowDeparted(windowId) (#18741) already records departures at the instant removePort() runs.
- #19056 / #19061 settle an unhandled
NEO_DEAD_PORT whose window departed. Once the misroute stops, these messages become exactly that shape.
The Fix
Skip the appName step when the addressed window (opts.windowId ?? dest) is known to have departed. The send then resolves no port, and promiseMessage rejects NEO_DEAD_PORT with the window id: settled if nobody awaits it, visible to a caller that does. The step keeps serving a target that re-registered and never departed.
Acceptance Criteria
Out of Scope
- The main thread's relay treating an unknown
dest as a worker name. It becomes unreachable for window ids once nothing misroutes them.
- Warm F5's remaining
.reload-retained-witness visibility timeout.
Decision Record impact
None. The change is aligned with #18741's departure predicate and #19056's settlement.
Related
Sweeps: live latest-open at 2026-09-23T00:16Z; open issues for misroute sibling window, appName fallback port and Target worker does not exist: none beyond #19060 / #17844. A2A lane-claims (last 15): none on this. Own assignments: none overlapping.
Origin Session ID: 19051047-2f38-4bf0-be51-efd6b957564d
Retrieval Hint: query_raw_memories("departed window message appName fallback sibling port Target worker does not exist sendMessage cascade")
Context
After a warm F5 in a two-root Workstation, the #17844 battery's
WorkstationTopologyGroupsNLarms fail in 4 of 6 runs withApp Worker: Error: Target worker '<uuid>' does not exist.This holds even with #19056's and #19060's fixes applied (recorded on #19060). The<uuid>is a window id, not a worker name. That text is thrown by the main thread'sworker/Manager.mjs:612, and main relays anydestthat is not itself to a worker of that name.The Problem
worker.Base#sendMessage(SharedWorker branch,src/worker/Base.mjs) resolves a port through a cascade:getPort({windowId: dest}) || getPort({id: dest})opts.portopts.windowIdopts.appNameFor a message addressed to a window that has departed, steps 1–3 miss and step 4 resolves a sibling window of the same app. The message then lands in that sibling's main thread with
destinationset to the departed window id. Main treats the id as a worker name and rejects, and the rejection returns to the App Worker as a failure attributed to the wrong window.Reproduced on
dev@58d69efa32with a unit stub holding two ports of appApp. AfterremovePort(win-a),sendMessage('win-a', {appName: 'App', windowId: 'win-a', …})posts towin-b(POSTED_TO_SIBLING 1).The block's own last-resort comment names the hazard: "delivering a keyed message to an arbitrary port would misroute it into a foreign window". The
appNamestep does exactly that for a departed window.The Architectural Reality
appNamestep exists for a real case: a staleopts.portbetween receipt and reply, where the same logical target re-registered.isWindowDeparted(windowId)(#18741) already records departures at the instantremovePort()runs.NEO_DEAD_PORTwhose window departed. Once the misroute stops, these messages become exactly that shape.The Fix
Skip the
appNamestep when the addressed window (opts.windowId ?? dest) is known to have departed. The send then resolves no port, andpromiseMessagerejectsNEO_DEAD_PORTwith the window id: settled if nobody awaits it, visible to a caller that does. The step keeps serving a target that re-registered and never departed.Acceptance Criteria
promiseMessagerejectsNEO_DEAD_PORTwith thatwindowId. Removing the guard turns it red.WorkstationTopologyGroupsNLruns show noTarget worker '<uuid>' does not existline.Out of Scope
destas a worker name. It becomes unreachable for window ids once nothing misroutes them..reload-retained-witnessvisibility timeout.Decision Record impact
None. The change is aligned with #18741's departure predicate and #19056's settlement.
Related
isWindowDepartedSweeps: live latest-open at 2026-09-23T00:16Z; open issues for
misroute sibling window,appName fallback portandTarget worker does not exist: none beyond #19060 / #17844. A2A lane-claims (last 15): none on this. Own assignments: none overlapping.Origin Session ID: 19051047-2f38-4bf0-be51-efd6b957564d
Retrieval Hint:
query_raw_memories("departed window message appName fallback sibling port Target worker does not exist sendMessage cascade")