Context
Surfaced by the #16365 probe ladder (three deterministic boot cycles, CDP page.mouse, headless Chromium, dev head 7f81768063+): the first dock drag gesture after every app boot forwards its drag:start to the app worker with dragZoneId: null, while the first drag:move (6–14ms later) already carries the zone. The gesture's beginning is invisible to any consumer keyed on the zone id; its middle and end process normally and the resize commits. Live latest-open sweep: latest 20 checked 2026-08-08 ~22:2xZ (newest #16756); nearest neighbours distinguished: #16365 (synthetic-buttons=0 wedge — resolved), #16754 (the 08-02 transient — different surface).
The Problem
The zone id reaches the main thread only through the app worker: DragDrop.onDragStart (src/main/addon/DragDrop.mjs) forwards dragZoneId from its own config (default null, never assigned in that file), and the only writer is the app-side DragZone.dragStart → DragDrop.setConfigs({...getMainThreadConfigs()}) (src/draggable/DragZone.mjs:427,505), which runs in response to the very start being forwarded. So the first start in every boot is zoneless by construction — a cold-start race baked into the handshake, not a timing flake.
Deterministic receipts (probe spec, per-run fresh boot):
- run 1:
drag:start dragZoneId:null @t=602 → drag:move neo-dragzone-1 @t=614
- run 2:
drag:start dragZoneId:null @t=1115 → drag:move neo-dragzone-1 @t=1121
- run 3: same shape (earlier probe session)
The Architectural Reality
Neo.main.addon.DragDrop.dragZoneId is read at five forward sites (:309,319,512,573,613,628) and at the Escape guard (:337 — if (event.key === 'Escape' && me.dragZoneId && !me.dragCancelled)).
- Consequence with a name on it: an Escape pressed in the opening window of the FIRST-ever drag finds
dragZoneId: null and does not cancel — the logical drag continues while the user believes it cancelled. Narrow, real, and exactly the class the guard exists for.
- Open question the ticket must answer before any repair: does the app-side router deliver a zoneless start to the correct zone anyway (by event target-path id), or is
DockSplitter.onDragStart skipped for cold-start gestures? Probe evidence is ambiguous: the resize commits via moves, while the app-side dragStartState read stayed null at mid-gesture sample time (possible read race — named, not inferred away).
The Fix
- Answer the open question with a probe receipt: instrument the app-side routing of the zoneless start (which zone handler, if any, receives it; does
dragStartState set before the first move).
- Repair at the owning layer — candidates, in test order: (a)
DragDrop.onDragStart resolves the zone from the event target-path synchronously instead of reading its own config; (b) the app-side zone registers its main-thread configs eagerly at zone creation (boot), not lazily on first drag; (c) if the zoneless start is genuinely benign except the Escape window, the Escape guard keys on an engaged-gesture fact rather than the zone id.
- Witness: the cold-start boot-cycle probe (first gesture of a fresh boot) asserts the forwarded start carries a zone AND the Escape guard cancels inside the opening window.
Acceptance Criteria
Out of Scope
- The #16365 synthetic-
buttons=0 wedge (resolved) and the #16754 transient (open, different surface).
- Drag proxy rendering / drop indicators.
Avoided Traps
- Treating the null-zone start as harmless because the resize commits — the Escape guard's zone-keyed condition is the counterexample already in the file.
- Repairing at the sensor: the sensor's
'drag:start' CustomEvent is fine; the zone id is a DragDrop-config concern.
Decision Record impact
none.
Related
#16365 (probe ladder origin, resolved), #16754 (transient tracker — this observation was parked there pending this second witness), #16381 (recovery — unrelated mechanism).
Origin Session ID: 94296ece-1e77-47de-b74c-d1f3b63d8265
Retrieval Hint: query_raw_memories("dragZoneId null first drag:start cold-start DragDrop setConfigs")
Context
Surfaced by the #16365 probe ladder (three deterministic boot cycles, CDP
page.mouse, headless Chromium, dev head7f81768063+): the first dock drag gesture after every app boot forwards itsdrag:startto the app worker withdragZoneId: null, while the firstdrag:move(6–14ms later) already carries the zone. The gesture's beginning is invisible to any consumer keyed on the zone id; its middle and end process normally and the resize commits. Live latest-open sweep: latest 20 checked 2026-08-08 ~22:2xZ (newest #16756); nearest neighbours distinguished: #16365 (synthetic-buttons=0wedge — resolved), #16754 (the 08-02 transient — different surface).The Problem
The zone id reaches the main thread only through the app worker:
DragDrop.onDragStart(src/main/addon/DragDrop.mjs) forwardsdragZoneIdfrom its own config (defaultnull, never assigned in that file), and the only writer is the app-sideDragZone.dragStart→DragDrop.setConfigs({...getMainThreadConfigs()})(src/draggable/DragZone.mjs:427,505), which runs in response to the very start being forwarded. So the first start in every boot is zoneless by construction — a cold-start race baked into the handshake, not a timing flake.Deterministic receipts (probe spec, per-run fresh boot):
drag:start dragZoneId:null @t=602→drag:move neo-dragzone-1 @t=614drag:start dragZoneId:null @t=1115→drag:move neo-dragzone-1 @t=1121The Architectural Reality
Neo.main.addon.DragDrop.dragZoneIdis read at five forward sites (:309,319,512,573,613,628) and at the Escape guard (:337—if (event.key === 'Escape' && me.dragZoneId && !me.dragCancelled)).dragZoneId: nulland does not cancel — the logical drag continues while the user believes it cancelled. Narrow, real, and exactly the class the guard exists for.DockSplitter.onDragStartskipped for cold-start gestures? Probe evidence is ambiguous: the resize commits via moves, while the app-sidedragStartStateread stayed null at mid-gesture sample time (possible read race — named, not inferred away).The Fix
dragStartStateset before the first move).DragDrop.onDragStartresolves the zone from the event target-path synchronously instead of reading its own config; (b) the app-side zone registers its main-thread configs eagerly at zone creation (boot), not lazily on first drag; (c) if the zoneless start is genuinely benign except the Escape window, the Escape guard keys on an engaged-gesture fact rather than the zone id.Acceptance Criteria
drag:startforwards carry the zone id from the first gesture of a boot, verified across 3 consecutive boot cycles.Out of Scope
buttons=0wedge (resolved) and the #16754 transient (open, different surface).Avoided Traps
'drag:start'CustomEvent is fine; the zone id is a DragDrop-config concern.Decision Record impact
none.
Related
#16365 (probe ladder origin, resolved), #16754 (transient tracker — this observation was parked there pending this second witness), #16381 (recovery — unrelated mechanism).
Origin Session ID: 94296ece-1e77-47de-b74c-d1f3b63d8265
Retrieval Hint:
query_raw_memories("dragZoneId null first drag:start cold-start DragDrop setConfigs")