LearnNewsExamplesServices
Frontmatter
id15207
titleWorkstation drag-affordance layers: DockPreview + DockDropIndicators overlay siblings
stateClosed
labels
enhancementai
assigneesneo-fable-clio
createdAtJul 16, 2026, 8:45 AM
updatedAtJul 26, 2026, 5:45 AM
githubUrlhttps://github.com/neomjs/neo/issues/15207
authorneo-fable-clio
commentsCount0
parentIssue15239
subIssues[]
subIssuesCompleted0
subIssuesTotal0
contentTrust
projected
quarantined0
signals[]
blockedBy[]
blocking[ ] 15252 The five-beat multi-window wow demo: recorded journey on the workstation, [x] 15250 Keyboard detach path: a11y parity for the multi-window choreography, [x] 15241 Register the workstation app in the portal examples catalogs
closedAtJul 16, 2026, 8:18 PM
milestonev13.2

Workstation drag-affordance layers: DockPreview + DockDropIndicators overlay siblings

Closed Backlog/active-chunk-6 enhancementai
neo-fable-clio
neo-fable-clio commented on Jul 16, 2026, 8:45 AM

⚠ Authority correction (2026-07-16, from PR #15237's Drop+Supersede review)

The original premise below is FALSE and struck: "the agentos DockPreview consumes --fm-* tokens the workstation theme family already loads — reuse, don't fork". Accepted extraction #15144 removed exactly that coupling: the workstation owns its classes and theme; it loads NO --fm-* tokens and imports NO AgentOS.* classes. Importing the AgentOS renderer (and copying the Demo-A controller into a second app) reverses an accepted boundary — PR #15237 was closed unmerged on this ground plus two exact-head async defects (a cancelled gesture's awaited drop could still commit; the producer was never destroyed).

Superseding scope (this ticket, re-scoped in place):

  1. Lift the shared authority into src/dashboard — the preview renderer and the reusable gesture controller (geometry memoization, candidate/preview tiers, release-truth drop, cancel hygiene) become ONE app-neutral owner. Demo-A and the workstation both become thin consumers; the duplicated controller copy this ticket originally prescribed was itself the friction signal.
  2. Explicit gesture/document-generation ownership: promise-identity re-checks after EVERY await (drop included — the falsified defect), cancel/refresh/destroy teardown symmetry, and producer lifecycle (create/destroy pairing).
  3. Witness upgrades: hover-zone-A / release-zone-B with the EXACT reducer descriptor asserted (release truth must be discriminated from cached hover); the production measurement path exercised (no injected pre-resolved geometry as the only path); plus a durable current-head real-pointer workstation journey.
  4. #15144's boundary preserved: no AgentOS.* imports, no --fm-* consumption in the workstation tree; the affordances style through the settled --agent-dock-preview-* domain aliases each app projects (the PR #14955 / PR #15208 boundary).
  5. AC-3 (the previewLanguage re-skin on the flagship) closes only when the combination with #15206's variants is actually demonstrated — never by inference.

D#15204's merge-order step 2 ("settle the active G5/#15207 surfaces") binds to THIS shape.

Context

Found while building the G5 preview-language switch (#15206, D#15204): apps/workstation/view/Workspace.mjs composes the dock host with the projection child ONLY — no DockPreviewProducer, no DockPreview renderer, no DockDropIndicators overlay (grep-verified, zero hits). The dense workstation — the release's flagship surface — therefore renders no drag-preview affordances at all: no §06 indicator menu, no zone-preview fill during a drag. Demo-A (the dockdemo childapp) carries the full pattern; the flagship does not.

This is a product capability gap independent of which preview design language wins the D#15204/G5 selection — the workstation needs the affordance layers under ANY skin. Filed separately from #15206 per scope discipline (the switch leaf must not ratchet a new capability mid-lane); #15206's recording pair lands on Demo-A where the affordances exist today, and the workstation previewLanguage config (already shipped, live-verified) becomes visually consequential the moment this leaf lands.

The Problem

A viewer dragging a tab on the flagship workstation gets proxy motion and commit — but no drop-indicator menu, no target-zone preview: the exact affordances the §06 grammar shipped for Demo-A (#14974) and the wow-tier scenario (D#15204 North Star beats 3–4) presume everywhere. The 20-tab dense scene is precisely where drop-targeting guidance matters most.

The Architectural Reality

The Demo-A composition is the verbatim precedent (apps/agentos/childapps/dockdemo/view/DemoAWorkspace.mjs): DockPreviewProducer created at construct; DockPreview (the renderer) + DockDropIndicators added as persistent overlay siblings of the projection child (object permanence across re-projections — the surgical removeAt(0)/insert(0) refresh pattern); the projection threads onDockCrossZoneDragMove/onDockCrossZoneDrop (measure-once-per-gesture memoized geometry, candidate-set swap on zone change, indicator-first/pointer-inference-fallback tier order, previewToOperation commits). The workstation's refreshDockWorkspace currently replaces its single child — the surgical refresh is part of this leaf. Renderer + controller authority (per the correction above): BOTH lift into src/dashboard as the app-neutral shared owner; Demo-A and the workstation compose it as thin consumers, styled through the --agent-dock-preview-* domain aliases each app projects (no --fm-* consumption, no AgentOS.* imports in the workstation tree — #15144's boundary).

The Fix

One PR (the superseding scope above): lift the renderer + gesture controller into src/dashboard (DockPreview, DockDragAffordances); convert Demo-A to the thin-consumer composition; compose the same owner on the workstation Workspace as persistent overlay siblings with the surgical refresh; controller witnesses (release truth, move + drop generation guards, the production measurement path, producer create/destroy pairing) plus a durable real-pointer workstation journey.

Contract Ledger

Target Surface Source of Authority Behavior Fallback / Edge Case Docs Evidence
Neo.dashboard.DockDragAffordances (new shared class: clear / ensureGeometry / onDragMove / onDrop / onDragCancel / destroy; consumer duck-type owner = {dockModel, applyDockZoneOperation, onDockZoneDocumentChange}; direct refs host / indicators / preview) this ticket's superseding scope + the §06 tier order (ADR 0029 consumer grammar) once-per-gesture memoized geometry; per-frame candidate/preview tiers (indicator-first, pointer-inference fallback); release-truth drop through previewToOperation; promise-identity generation guards after EVERY await; producer create/destroy pairing null overlay refs = silent no-op per tier; degenerate frames (missing OR zero-area rects) uncache + self-heal next frame; cancelled/re-projected gestures commit nothing class JSDoc (contract documented on the class + members) test/playwright/unit/dashboard/DockDragAffordances.spec.mjs (release truth, both generation guards, production measurement path incl. the zero-area frame, producer pairing) + the flagship journey
Neo.dashboard.DockPreview — moved renderer (formerly the agentos tree) + edgeBandSize / splitLineSize instance configs + affordanceGeometry(affordance, targetRect, options) #15144 boundary (app-neutral tier) + PR #15282 RA-2 per-instance sizing policy flows into positioned geometry; the pure static helper accepts explicit options helper defaults (24 / 6) serve bare static calls; band clamps to the target rect, oversized values degrade gracefully config + method JSDoc DockPreview.spec.mjs sizing witnesses (options + instance override + clamp) + the four-anchor alias census
Neo.dashboard.DockTabSortZonedockReleaseTolerance config, releaseVoidsReorder(data), dockSourceToolbarRect snapshot PR #15282 RA-1 (the path-reorder revert repair) a release beyond the source toolbar's REAL bounds + tolerance voids the tracked within-toolbar reorder so the cross-zone drop owns the outcome fail-open: missing snapshot or non-numeric release coords never void (base behavior preserved); cancels untouched; near releases keep the base reorder member JSDoc DockTabSortZone.spec.mjs release-boundary matrix (near/far × horizontal/vertical + tolerance override + guards)
Neo.main.draggable.sensor.Base#trigger — detached-source dispatch fallback PR #15282 RA-3 (the flagship's measured 23-mousemove/0-drag:move starvation) a disconnected dispatch target routes the event to document; consumers read event.detail, never the dispatch target connected sources dispatch on the element exactly as before (bubbling unchanged) method JSDoc test/playwright/unit/main/draggable/sensor/Base.spec.mjs (connected / detached / mid-gesture branch-flip discrimination)

Acceptance Criteria

  • A real pointer drag on the workstation lights the §06 indicator menu + per-option zone preview; selection commits the exact descriptor (worker-truth topology assert).
  • Both overlays survive a committed re-projection (object permanence — the Demo-A invariant).
  • previewLanguage (shipped on the Workspace) visibly re-skins the affordances once #15206's variants apply — the side-by-side works on the flagship.
  • No new timing/color literals: the --agent-dock-preview-* domain aliases each app projects + the shared motion vocabulary tokens only (no --fm-* in the workstation tree — #15144's boundary).
  • Whitebox witness per the Fix; cross-family review.

Out of Scope

The design-language variants themselves (#15206) · multi-window/tear-out affordances (epic #15239 leaves #15244–#15248) · FM cockpit surfaces.

Related

Parent epic #15239 (re-parented from #13158 at epic graduation, 2026-07-16) · sibling #15206 (the switch + skins; its workstation-recording ambition unblocks here) · precedent #14974 (Demo-A §06 experience) · D#15204 G5 · the #15099→workstation arc.

Live latest-open sweep: latest 6 open at 2026-07-16T06:44Z; "workstation preview indicator overlay" all-states search: nearest #15171 (projection reconciler migration — disjoint). A2A: filed unassigned for self-select (the workstation is Emmy's built surface; the affordance pattern is Demo-A's — either family lifts it cleanly); no competing claim in the herd window.

Origin Session ID: c5d7cd6b-4e01-45fd-aa59-5ccbc0e5f091 Retrieval Hint: "workstation drag affordance overlay DockPreview DockDropIndicators persistent siblings"

tobiu referenced in commit da12b5c - "feat(dashboard): shared drag-affordance owner — the flagship composes it + three real-pointer repairs (#15207) (#15282) on Jul 16, 2026, 8:18 PM
tobiu closed this issue on Jul 16, 2026, 8:18 PM