LearnNewsExamplesServices
Frontmatter
id13158
titleEpic: QT-parity docking polish — interactive resize, auto-hide/pin, perspectives, grouped drag
stateClosed
labels
enhancementepicaiarchitecture
assigneesneo-fable-clio
createdAtJun 14, 2026, 2:24 AM
updatedAtSep 15, 2026, 12:54 PM
githubUrlhttps://github.com/neomjs/neo/issues/13158
authorneo-opus-grace
commentsCount21
parentIssue144
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
subIssuesCompleted98
subIssuesTotal98
contentTrust
projected
quarantined0
signals[]
blockedBy[]
blocking[]
closedAtSep 15, 2026, 12:54 PM
milestonev13.2

Epic: QT-parity docking polish — interactive resize, auto-hide/pin, perspectives, grouped drag

Closed Backlog/active-chunk-2 enhancementepicaiarchitecture
neo-opus-grace
neo-opus-grace commented on Jun 14, 2026, 2:24 AM

Problem scope

The QT-grade docking foundation (#13030 scoping anchor) has landed its core layer: the neo.harness.dockZone.v1 model 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:

  • Interactive splitter resize — the model persists split sizes, but the adapter projects static flex only; HarnessDockZoneModel.md §Split Projection explicitly defers a resizable splitter that writes size changes back through a semantic operation.
  • Auto-hide / pin sidebars — the model reserves a pinnable item 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.
  • Named perspectives — the persistence wrapper neo.harness.dockLayout.v1 already models layoutId + title + revision, but there is no layout store or switcher to save and fast-switch named workspace layouts.
  • Grouped tab-drag + tab overflow menu — operations move one item at a time; dragging a whole tab group, and an overflow menu for many-tabbed slots, are unscoped.

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.v1 model — not a redesign, and explicitly not a core src/layout/Dock lift (the contract's §Ownership Boundary keeps this in src/dashboard/ until a second non-dashboard consumer proves reuse). Each gap maps to an affordance the foundation already anticipated:

  • splitter resize → a resize affordance rendered between DockLayoutAdapter-projected children, committing through a new semantic size operation on DockZoneModel (never a pointer handler mutating persisted sizes);
  • auto-hide/pin → a collapsed edge-zone state + pin/auto-hide operations + a pin affordance on the existing DockPreview overlay;
  • perspectives → a named-layout store + switcher over the existing dockLayout.v1 wrapper, with fail-closed restore;
  • grouped drag / overflow → a multi-item move operation + a tab-group drag source feeding the existing preview→operation path, plus a Neo.tab.Container overflow affordance.

The claimer of each leaf runs structural-pre-flight + ticket-create and settles that leaf's contract question at claim time; this body is the convergent shape, not the per-sub breakdown.

Out of scope

  • The neomjs/neo#13030 foundation leaves (model / preview / adapter / persistence) — already owned and landing; this epic starts after them.
  • Cross-window choreography: popup terminal drop (#13025) and OS-window drag reintegration (#13028) — window-manager leaves, not in-window docking polish.
  • A core src/layout/Dock primitive — deferred until a second non-dashboard consumer demands it (contract §Ownership Boundary).
  • Partner-specific layout presets — partner-private overlay only, never here.

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.

  • No public performance claims before the Harness Endurance Benchmark (#13032) — architecture-shaped hypothesis phrasing until measured.
  • JSON-first persistence — no DOMRect, screen coordinates, dockPreview, windowId, live components, functions, or credentials in any serialized layout (HarnessDockZoneModel.md §Serializable vs Runtime State).
  • No parallel drag system — every new interaction rides the existing SortZone / DragCoordinator / Window pipeline; preview state stays runtime-only and converts to a semantic operation on drop.

Related

  • Parent: Epic neomjs/neo-agent-brain#144 (Agent Harness). Foundation predecessor: neomjs/neo#13030 (QT-grade docking scoping anchor). Milestone target: M3 (dashboard composition). Board: Project 13.
  • Contract: 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).

tobiu referenced in commit 8861059 - "docs(roadmap): scope the v13.1 release section (#13391) (#13393) on Jun 16, 2026, 2:07 PM
tobiu referenced in commit 4b7ff64 - "refactor(dashboard): dock operation vocabulary becomes ONE exported SSOT (#14813) on Jul 5, 2026, 6:06 AM
tobiu added parent issue #144 on Aug 26, 2026, 5:23 PM
tobiu cross-referenced by PR #17960 on Aug 31, 2026, 7:12 PM
tobiu referenced in commit fabb61f - "feat(dock): the reveal overlay carries a discoverability floor on any ground (#18080) (#18085) on Sep 2, 2026, 3:50 PM