Frontmatter
| id | 13158 |
| title | Epic: QT-parity docking polish — interactive resize, auto-hide/pin, perspectives, grouped drag |
| state | Closed |
| labels | enhancementepicaiarchitecture |
| assignees | neo-fable-clio |
| createdAt | Jun 14, 2026, 2:24 AM |
| updatedAt | Sep 15, 2026, 12:54 PM |
| githubUrl | https://github.com/neomjs/neo/issues/13158 |
| author | neo-opus-grace |
| commentsCount | 21 |
| parentIssue | 144 |
| subIssues | 13159 Add semantic resize operation for dock splits 13164 Add semantic pin state for dock items 13169 Add dock named-layout collection helpers 13206 Render dock splitters that commit resizeSplit 13213 Wire Harness dock splitter drag into resizeSplit 13247 Add a standalone docking example for the dashboard dock-zone layout system 13254 Docking auto-hide: persist collapsed item state 13308 Render dock named-perspective switcher 14423 Docking design spec: perspectives, cross-window drag, SharedWorker seam 14587 Neural Link dock-layout tools: topology readout + semantic operation execution 14589 Dock choreography showcase: animated split/tab/auto-hide demo, NL-drivable, tour-scripted 14590 Perspectives showcase: named-layout morphing + shared-heap window pop-out demo 14591 Whitebox e2e: dock-layout operations + animation assertions via the NL fixture 14638 Demo A design artifact: the dock-choreography showcase mock at the house bar 14640 NL tour-runner harness: scripted operation sequences with deterministic timing 14649 Perspective NL tools: capture_perspective + restore_perspective + list_perspectives 14650 Dock topology diff tool: structured before/after compare for tours and e2e 14651 Perspective persistence: revision migration + capture-scope fields on dockLayout.v1 14652 Perspective capture: single-window scope over the live dock document 14653 Perspective restore into unchanged topology: the happy-path round-trip 14654 Auto-hide edge-tab rail: the collapsed-item affordance (dockZone v1 seam → UI) 14660 Auto-hide reveal/dismiss interaction: hover-reveal, pointer-away dismiss, pin escape 14661 Demo A tour script: the three-scene choreography as tour-runner content 14667 Perspective capture: whole-topology scope across the multi-window workspace 14668 Perspective restore into changed topology: reconciliation + the fail-closed contract 14669 Named perspective store: JSON-first persistence + lifecycle for dockLayout v2 records 14670 CrossWindowDragTarget: the receiving-window contract implementation 14768 transferItem executor operation: atomic cross-document item transfer 14769 Dock workspace cross-window participation: source hooks + target wiring 14770 Grouped drag executor operations: moveNode + transferNode 14771 Tab overflow affordance: hidden-tab projection on heavy tabs nodes 14772 Cross-window drag showcase: the two-window transfer demo scene 14773 dockPerspective.v1 vs shipped dockLayout.v2: reconcile the schema naming 14779 Dock transition animation layer: animated split/tab/auto-hide projections 14789 Flagship fusion demo: cockpit → docked panel → OS window → share, one tour 14850 Dock tab-drag: draggable headers + within-container reorder commit 14857 Dock cross-zone tab drag: functional tab-into model move (hit-test → moveItem) 14866 Dock dockPreview.v1 producer + unit test (compute half) 14886 Wire dockPreview.v1 producer into live drag: hover-affordance render + drop-routing e2e 14929 Animated dock re-layout: FLIP transitions on every committed dockZone operation 14930 Human-drag showcase beat + dock-guide affordance polish pass 14934 Docking epic closure gate: experience-parity matrix vs the Qt-ADS interaction inventory 14945 Scale changed-topology slot assignment across live restore paths 14959 Dock drop-indicator menu: candidate-set producer extension + DockDropIndicators + the cold-open drag beat 14969 Dock-zone surfaces never load the dashboard token scope — the motion contract is invisible on both 14989 Pin DockMotion geometry witnesses to one logical item across reprojection 15056 Dock example: perspective toolbar consumes ~51% viewport height (missing flex reset) 15098 Tab-native overflow: Neo.tab.plugin.Overflow owns the hidden-tab projection 15099 Dense-workstation showcase: the ~20-tab big-screen scene, themed + toured 15137 Make preserved-identity DockFlip moves clip-safe and immediate 15144 Promote the dense workstation to a standalone app 15147 Harden DockFlip boundary oracles and reconcile the DockMotion seed 15164 Compact Workstation tourbar controls and clear story fill 15165 Make Workstation dock composition adapt to viewport width 15166 Expose Workstation splitters and unify dock pane chrome 15172 Make dock edge-band geometry host-relative on both axes 15171 Dock projection: migrate remaining consumers to the identity reconciler 15178 Dock Demo B: preserve CounterPane across changed-topology retirement 15189 Stop cross-window transfers from invalidating dockZone.v1 17211 Cockpit layout ergonomics: the grid/timeline splitter is invisible, the left rail oversizes its tabs, the right rail undersizes its panels 17241 The dock''s visual language lives in apps/, not `src/dashboard` 17242 Dashboards render unthemed: no `theme-neo-*/dashboard` layer exists 17244 Extend the dashboard theme layer to dark, light and cyberpunk 17555 Two DockOperationsNL witnesses fail on unmodified dev: moveItem and splitNode delta/read agreement 17564 Workstation headed witnesses: four pre-existing dev-red cases, one stage-bound precondition, one brain-tier-blocked file on the Fable host 17819 Splitter supports proxy-free live sibling resizing 17820 DockSplitter previews geometry live before semantic commit 17823 The live-resize readiness gate measures pixels, never frames 17863 Repair the committed-drag journey family for v13.2 mechanics 17864 Root edge chips vanish for descriptor-shaped center zones 17865 Workstation film-stage density under committed band extents 17870 Split previews paint the resulting region, not just the insertion line 17928 Dock layouts have no maximize — a first-class pane maximize for tabs nodes 17945 Engine-owned pin header action collapses a pane to its edge rail 17947 Engine-owned pop-out header action enters the tear-out lifecycle 17948 Engine-owned reload header action with a per-pane delegation contract 17949 Engine-owned lock header action protects a dock pane 17950 tab.Container ui variants: inline and standalone header chrome 17951 Tab overflow control can project as the first header action 17963 Dock pane header actions wear stock button chrome — a design pass for the four themes 17966 Default reload fallback: engine-owned recreate when a pane lacks dockReload() 17969 `detachItem` leaves a railed item `autoHidden`, contradicting ADR 0029''s stated mutual exclusion 17985 Outer DockSplitter resizes only one pane in a nested column 17990 Teardown during a pending tear-out admission orphans the host''s vessel window 18070 A rail reveal overlay overlaps its own strip on a padded dock host 18071 Dock header actions carry tooltips that follow their toggles 18074 A rail reveal enters with an 8px nudge, not a slide from its own edge 18077 Window geometry observation is armed by each app, not by the dock host 18080 The engine''s default reveal chrome vanishes on a dark ground 18084 container.Base#insert cannot park a lazy module config; a dock pane resolved lazily throws in the projection swap 18088 A composition-style dock adopter arms resize but not movement: the crossWindow example is blind to native titlebar drags 18087 A native drop into an outside iframe pane races the rail reveal''s dismissal — the pointer shield removes the frame as a drop target 18089 The reveal-pin screenshot baselines predate the inline-header trim, so DockPinCollapseNL is red on dev 18100 DockPinCollapseNL''s first arm reads the pin button by id before its header has focus, and a withdrawn action has no node since the toolbar stopped rendering it 18116 A rail reveal slides in but cuts out: dismissal applies display:none at once, so there is no exit motion 18117 Retargeting a rail reveal to another item of the same rail swaps the pane in one frame: the incoming pane should slide in, and done right the outgoing one cross-fades out 18122 Maximize fills the app viewport and stops an edge-band pane at half of it: the presentation should fill the dock host, inset by a gap, with a shadow 18732 Demo-A drop-indicator journey is red, so three parity grains have no live witness |
| subIssuesCompleted | 98 |
| subIssuesTotal | 98 |
| contentTrust | |
| projected | |
| quarantined | 0 |
| signals | [] |
| blockedBy | [] |
| blocking | [] |
| closedAt | Sep 15, 2026, 12:54 PM |
| milestone | v13.2 |
Problem scope
The QT-grade docking foundation (#13030 scoping anchor) has landed its core layer: the
neo.harness.dockZone.v1model contract, the semantic-operation executor (Neo.dashboard.DockZoneModel), the split/tab rendering adapter (Neo.dashboard.DockLayoutAdapter), and the cancelable drag-to-dock preview affordances — across neomjs/neo#13061→#13142, with layout persistence (#13147/#13153) in flight. Neo now has dock-everywhere edge zones, nested splits, tabbed slots, and drag-preview, all as worker-owned serializable JSON with multi-window object permanence.What remains, measured against a mature QT/WPF-class docking system, is the polish / parity layer — interactions an enterprise desktop-to-web migration audience treats as table stakes, which the foundation deliberately deferred:
sizes, but the adapter projects staticflexonly;HarnessDockZoneModel.md§Split Projection explicitly defers a resizable splitter that writes size changes back through a semantic operation.pinnableitem hint and four edge zones, but there is no collapsed-to-sidebar auto-hide state (show on hover/click): the single most visible QT docking affordance still absent.neo.harness.dockLayout.v1already modelslayoutId+title+revision, but there is no layout store or switcher to save and fast-switch named workspace layouts.Why an epic, not a single ticket: each gap is an independent one-PR leaf with its own contract question, but they share one convergent outcome (QT-parity on the existing model) and one guardrail set. This is the follow-up phase to the neomjs/neo#13030 foundation — sequenced after the foundation leaves (incl. persistence neomjs/neo#13147/#13153) land, and it does not touch their in-flight lanes.
Demand basis is unchanged from neomjs/neo#13030 / neomjs/neo-agent-brain#144: the enterprise desktop-to-web (QT/WPF-class ISV) migration market, treated as a market hypothesis, not single-source, with the harness operator cockpit and the Portal learning workspace as the in-repo second consumers named in the dock-zone contract's §Demand Validation. Per the neomjs/neo-agent-brain#144 partner guardrail, partner specifics stay out of this body.
Intended solution shape
One convergent direction: additive on the existing
dockZone.v1model — not a redesign, and explicitly not a coresrc/layout/Docklift (the contract's §Ownership Boundary keeps this insrc/dashboard/until a second non-dashboard consumer proves reuse). Each gap maps to an affordance the foundation already anticipated:DockLayoutAdapter-projected children, committing through a new semantic size operation onDockZoneModel(never a pointer handler mutating persistedsizes);DockPreviewoverlay;dockLayout.v1wrapper, with fail-closed restore;Neo.tab.Containeroverflow affordance.The claimer of each leaf runs
structural-pre-flight+ticket-createand settles that leaf's contract question at claim time; this body is the convergent shape, not the per-sub breakdown.Out of scope
src/layout/Dockprimitive — deferred until a second non-dashboard consumer demands it (contract §Ownership Boundary).Binding guardrails (ADR 0020 §4)
Gesture-proof guardrail (added 2026-07-05, from the neomjs/neo#14591 audit — operator-attributed planning miss): a runtime-interaction leaf (anything a pointer touches: drag, drop, resize, reveal, tour) ships its e2e gesture spec in the same PR — "live gesture rides a later leaf" is not an accepted evidence line on this epic anymore. Model-tier leaves (pure executors/validators) keep unit floors. The Grid DnD e2e family is the proven template.
DOMRect, screen coordinates,dockPreview,windowId, live components, functions, or credentials in any serialized layout (HarnessDockZoneModel.md§Serializable vs Runtime State).SortZone/DragCoordinator/Windowpipeline; preview state stays runtime-only and converts to a semantic operation on drop.Related
learn/agentos/HarnessDockZoneModel.md. Substrate:src/dashboard/DockZoneModel.mjs,src/dashboard/DockLayoutAdapter.mjs,apps/agentos/view/DockPreview.mjs.Authored by @neo-opus-grace (Grace).
Closure Gate (binding — neomjs/neo#14934)
This epic MUST NOT be resolved without an item-by-item experience-parity matrix against ADR 0029 §4.1's interaction-grain inventory (drag proxy · drop-indicator overlays · per-option preview · tab insertion cues · escape-cancel · commit animation) plus the surviving §4 capability rows. Every matrix row requires an evidence link — a recorded interaction, an e2e spec, or a live demo beat — never a bare assertion. Rationale: four independent analysis passes scored the drag experience "landed" at capability-list altitude while the standing bar (operator, 2026-07-02: "do not under-estimate QT docking — Qt-Advanced-Docking-System-class") is experience-parity; sub-issues-closed ≠ scope-met. Known-open rows at gate creation: escape-cancel (unowned gap), commit animation (#14929), affordance/proxy flagship polish (#14930).