LearnNewsExamplesServices
Frontmatter
id15933
titleShowcase beat: one in-window drag across multiple live dock dropzones
stateClosed
labels
enhancementaitesting
assigneesneo-gpt-emmy
createdAtJul 25, 2026, 8:53 PM
updatedAtJul 26, 2026, 3:06 AM
githubUrlhttps://github.com/neomjs/neo/issues/15933
authorneo-fable
commentsCount1
parentIssuenull
subIssues[]
subIssuesCompleted0
subIssuesTotal0
contentTrust
projected
quarantined0
signals[]
blockedBy[]
blocking[]
closedAtJul 26, 2026, 3:06 AM

Showcase beat: one in-window drag across multiple live dock dropzones

Closed Backlog/active-chunk-9 enhancementaitesting
neo-fable
neo-fable commented on Jul 25, 2026, 8:53 PM

Context

Film v1 lane 4 from the operator-endorsed claim round. The operator's v0 verdict named the missing beat directly: "we do not show the 'good parts' yet like moving one drag proxy over multiple valid target dropzones and visual hover effects." This is the beat the dock-affordance system exists to earn, and the v0 cut never shows it.

The Problem

The v0 journey exercises resizeSplit, theme flips, and the tear-out, but never the in-window cross-zone grammar: dragging one live item across a workspace while each candidate target answers with indicators and a placement preview. No journey executor drives it, no tour scene plays it, and no take has recorded it. The good parts are not missing from the product; they are missing from the choreography.

The Architectural Reality

Verified against the live source and focused headed E2E path:

  • apps/workstation/view/Workspace.mjs composes Neo.dashboard.DockPreview and Neo.dashboard.DockDropIndicators as persistent siblings of the projection child, then gives them to the app-neutral Neo.dashboard.DockDragAffordances controller.
  • Workspace#projectDockModel routes onDockCrossZoneDragMove into dragAffordances.onDragMove(...) and onDockCrossZoneDrop into dragAffordances.onDrop(...). Candidate state and the eventual descriptor therefore come from the shipped gesture owner, not a screenplay-side geometry re-derivation.
  • Workspace#executeTearOutStep is the sibling executor pattern: real InteractionService pointer input with film-pace tunables and observable terminal receipts.
  • PR #15926 is merged; its synthetic film cursor can ride this executor's own coordinate stream.
  • The original ticket premise that a margin from the window edge prevents tear-out was falsified. Neo.draggable.container.SortZone#checkWindowBoundary measures the drag proxy against boundaryContainerRect, and the projected dock sort zone receives the source tab toolbar as that boundary. Any valid cross-zone gesture must leave that strip. The choreography must therefore suppress only enableProxyToPopup for its gesture and restore the exact prior value on every terminal. The window-edge inset remains a visual-stage safety rule, not the grammar-isolation mechanism.
  • Once a sort arms, the dense toolbar can replace the source button's DOM identity. The native mouse sensor is document-global at that point, so post-arm simulated moves and terminals must use a stable document/document.body event carrier; the sensor still derives hover truth with elementFromPoint.

The Fix

Choreography only, across three surfaces:

  1. Add Workspace#executeCrossZoneShowcaseStep beside executeTearOutStep. It arms a real drag on a named live tab, temporarily disables popup conversion, walks a film-paceable path through at least two foreign zones and two placement kinds, and then settles as either:
    • commit: release at the final active candidate and prove the committed document equals that preview's exact operation applied to pre-gesture truth;
    • cancel: dispatch Escape plus release, wait for the sort zone's observable idle contract, and prove byte-identical document truth plus retired overlays.
  2. Add a cross-zone-showcase cue to apps/workstation/tour/denseWorkstation.mjs so demo playback, tests, and film takes consume one screenplay.
  3. Add a focused leg to test/playwright/e2e/workstation/WorkstationFiveBeatNL.spec.mjs: default mode uses fast pacing; film mode uses the same assertions with D-010 pacing and visible dwells.

Contract Ledger

Target Surface Source of Authority Proposed Behavior Fallback / Edge Case Docs Evidence
New Workstation.view.Workspace#executeCrossZoneShowcaseStep(step, options) #15933; shipped DockDragAffordances move/drop contract Drive one native-event drag through at least two distinct foreign zones and placement kinds; beat-log the controller's active previews; commit exactly the final preview or cancel with zero document mutation. Reject malformed source/dwells/terminal; cancel on runtime failure; restore the exact prior enableProxyToPopup value and destroy the film cursor in finally. Full JSDoc on the new method and options. WorkstationFiveBeatNL.spec.mjs: two fresh boots, cancel + commit per boot, exact descriptor/document equality, overlay retirement, pane identity, heartbeat, and identical semantic logs.
Existing Workstation.view.Workspace#executeCue(cue) Existing tour surface; #15933 Route type: 'cross-zone-showcase' to the new executor with the cue's own options. Existing unknown-cue error remains unchanged. Existing method remains the routing anchor; tour script documents the cue. denseWorkstation.spec.mjs cue vocabulary + visible-tour E2E receipt.
Existing workstationTourScript in apps/workstation/tour/denseWorkstation.mjs #15252 film spine; #15933 choreography Add one pause cue that moves audit from right-top-tabs, dwells on scale-tabs edge-bottom and right-bottom-tabs tab-into, then commits the center merge. No direct reducer operation is added to the document-tier operation list; failures surface through the cue receipt. Script summary/caption updated. Unit script contract plus WorkstationNL.spec.mjs visible-tour document and cue receipts.
Existing SortZone.enableProxyToPopup config consumed by the executor src/draggable/container/SortZone.mjs; live projected dock config Set false only for the active showcase gesture so leaving the source toolbar cannot enter popup conversion; restore the captured value in finally. Every return, cancel, commit, and exception restores the prior value. Window-edge margin remains presentation-only. Inline rationale at the mutation seam. Focused E2E traverses foreign zones with tear-out enabled on the workstation and proves both terminals; source lookup anchors boundary semantics.
Existing Workspace#cancelTearOutGesture(button, release, options) internal helper SortZone#processDragEnd async cleanup contract; #15933 Optionally accept the active sort zone and stable terminal target, then poll observable zone-idle facts before reporting settled: true. Existing callers that omit options retain their prior behavior. Bounded poll returns settled: false; the showcase terminal treats that as residue. JSDoc for optional sortZone and targetId. Cancel followed immediately by a second gesture in each focused E2E run; no transient-layout sample or stale sensor ownership.

Acceptance Criteria

  • One executor-driven in-window drag dwells on at least two distinct foreign zones and two distinct placement kinds, with each active placement captured from the affordance session.
  • Two consecutive default-mode runs produce byte-identical semantic beat logs.
  • Commit terminal: the post-drop document equals the pre-drop document with exactly the previewed operation applied. Cancel terminal: byte-identical document, idle sort zone, and retired overlays.
  • Film mode rides the existing filmPace block with cursor and dwell pacing; the assertion set is identical to default mode.
  • Popup conversion is disabled only for the showcase gesture and the exact prior enableProxyToPopup value is restored for every terminal. The pointer path also retains a window-edge visual safety inset.
  • The post-arm move/release stream survives replacement of the dragged source button's DOM node by using the document-global native sensor path.
  • The visible tour consumes the same cue and ends with audit in right-bottom-tabs, while preserving live pane/chrome identity.

Out of Scope

  • Cross-window traverse and conversion — #15906 stage B.
  • Changes to DockDragAffordances, DockPreview, DockDropIndicators, or DockLayoutAdapter; this ticket consumes the shipped grammar.
  • Sibling v1 lanes: #15923 (vessel theming), #15927 (one-frame blanks), and #15924/PR #15926 (stage + cursor).

Avoided Traps

  • Confusing window margin with tear-out isolation: the tear-out boundary is the source toolbar. Executor-scoped config suppression/restoration is the isolation contract; the margin is visual only.
  • A second source of truth: the beat log reads the affordance session's candidate state, never a parallel DOM/geometry inference.
  • Stale source-node dispatch: after arming, the dense toolbar can replace the dragged button DOM. The stable document carrier preserves the real native sensor stream.
  • Fake gestures: no direct document mutation dressed as a drag; simulateEvent drives the native mouse path end-to-end and the shipped controller owns every preview/drop.
  • Premature cancel claims: Escape dispatch is not settlement. The receipt waits for the sort zone's observable idle facts before allowing a successor gesture.

Related

#15252 (film) · #15924 / PR #15926 (stage + cursor) · #15923 · #15927 · #15906 (cross-window sibling)

Decision Record impact: none — consumes the shipped affordance grammar and adds app-owned choreography plus executable evidence.

Live latest-open sweep: checked latest 20 open issues at 2026-07-25T18:52Z; no equivalent (nearest neighbors #15924/#15926 = stage + cursor, #15906 = cross-window).

Origin Session ID: db73adaf-4f37-4d7b-9db7-f13477f2f92e

Retrieval Hint: query_raw_memories("in-window cross-zone showcase beat DockDragAffordances indicators preview dwell")

Originally authored by Mnemosyne (@neo-fable, Fable 5, Claude Code); intake correction and Contract Ledger by Emmy (@neo-gpt-emmy).