Context
Found in manual testing of apps/workstation on dev (2026-10-22). After a reload, the restored layout shows panes below the bottom edge rail (Selection Inspector): "Audit | Resident Activity Timeline" and "Live Event Stream" sit underneath it, and the left rail stops part-way down the window. A screenshot follows in a comment.
Product decision (@tobiu, 2026-10-22): keep the DockPanel wrap from #18421: a drop at the window edge wraps the whole arrangement, and docking order decides the corners. But rails are window chrome: they must always sit at the outermost window edge.
Measurements: the restored document, read live over the Neural Link (read-only)
root: "split-root-0"
split-root-0 = split vertical [ "root" (the edge-zone), "split-tabs-feed-0-0" ]
root (edge-zone) = { center: split-main, left: left-tabs, right: right-bottom-tabs, bottom: bottom-tabs }
bottom-tabs = { items: ["inspector"] } ← autoHidden only → the bottom rail
split-tabs-feed-0-0 = split vertical [ tabs-audit-0 (audit, activity), tabs-feed-0 (feed) ]A root-edge drop wrapped the edge-zone root in a split, which is the documented behavior since #18426. The edge-zone's rails moved with it. They now project at the edge-zone's own boundary, which is no longer the window's.
The Problem
Rails are projected per edge-zone band, at that band's position. That is correct while the edge-zone is the root, because its boundary is the window's. Under the DockPanel wrap the edge-zone becomes a split child: its bottom rail ends up between panes, and its left and right rails stop where the edge-zone stops.
Design authority:
DragAffordances#guardEmptyWrap: "A root-edge drop wraps the whole arrangement". Decision (B) of #18421 / #18426 made it the operator's DockPanel rule.
WorkspaceDocument calls the edge-zone root "window chrome".
- The operator's ruling above settles the conflict between the two: the wrap stays, and the chrome stays outermost.
The Architectural Reality
src/dashboard/dock/projection/LayoutAdapter.mjs: collectAutoHiddenItems and the rail strip per edge band. WorkspaceDocument#findOwningEdge already resolves a nested-edge contest to the outermost edge, but only among edge-zones.
src/dashboard/dock/interaction/DragAffordances.mjs: resolveDockableRoot / guardEmptyWrap, the root-edge wrap.
learn/agentos/DockZoneModel.md: edge-zone is a "root or nested edge container", so the document shape stays legal.
The Fix
Rails are projected as window chrome. The auto-hidden items of every band in the root-path edge-zone, the edge-zone the root wraps, render as rail strips at the dock host's outer edges, outside the whole arrangement, at any nesting depth. The wrapped arrangement lays out inside the rail frame.
- Projection-level, preferred. The document keeps its legal shape, so layouts already persisted in this form (the operator's browser has one) render correctly with no migration, and the DockPanel wrap is unchanged.
- Reveal overlays open from the rail's new position and size against the arrangement inside the frame.
- Trap: a band holding visible panes and auto-hidden items. Its visible panes stay in the band, and only its rail moves outward.
Acceptance Criteria
Out of Scope
- Changing the DockPanel wrap itself. Ruled to stay.
- #19991, the grid hang. This wrapped layout came out of the session that crashed, and whether a wrapped edge-zone root removes the grid's size constraint is a candidate trigger tracked there.
Related
- #18421 / #18426: the DockPanel decision and the declared dockable root.
- #19991, the hang, and its suspected trigger.
- #19982–#19991: the same testing pass.
Live latest-open sweep: checked latest 20 open issues at 2026-10-22T10:45:22Z; no equivalent found.
Keyword sweep (10:41Z): "root edge drop wraps", "edge-zone root split", "pane below rail", "guardEmptyWrap"; closed adjacent only (#18421/#18426, #17864, #19521).
A2A claim sweep: no overlapping lane-claim.
MC sweep: "root edge drop wraps the whole arrangement around the edge-zone root…", 5 results; prior decision found (#18421 decision B, DockPanel), kept per the operator's ruling.
Own-assignment sweep: none overlapping.
Origin Session ID: 70e59a84-efd6-4e7a-9262-c5478bd314ff
Retrieval Hint: "rails are window chrome outermost edge, DockPanel root-edge wrap nests the edge-zone root, panes below the bottom rail"
Context
Found in manual testing of
apps/workstationondev(2026-10-22). After a reload, the restored layout shows panes below the bottom edge rail (Selection Inspector): "Audit | Resident Activity Timeline" and "Live Event Stream" sit underneath it, and the left rail stops part-way down the window. A screenshot follows in a comment.Product decision (@tobiu, 2026-10-22): keep the DockPanel wrap from #18421: a drop at the window edge wraps the whole arrangement, and docking order decides the corners. But rails are window chrome: they must always sit at the outermost window edge.
Measurements: the restored document, read live over the Neural Link (read-only)
root: "split-root-0" split-root-0 = split vertical [ "root" (the edge-zone), "split-tabs-feed-0-0" ] root (edge-zone) = { center: split-main, left: left-tabs, right: right-bottom-tabs, bottom: bottom-tabs } bottom-tabs = { items: ["inspector"] } ← autoHidden only → the bottom rail split-tabs-feed-0-0 = split vertical [ tabs-audit-0 (audit, activity), tabs-feed-0 (feed) ]A root-edge drop wrapped the edge-zone root in a split, which is the documented behavior since #18426. The edge-zone's rails moved with it. They now project at the edge-zone's own boundary, which is no longer the window's.
The Problem
Rails are projected per edge-zone band, at that band's position. That is correct while the edge-zone is the root, because its boundary is the window's. Under the DockPanel wrap the edge-zone becomes a split child: its bottom rail ends up between panes, and its left and right rails stop where the edge-zone stops.
Design authority:
DragAffordances#guardEmptyWrap: "A root-edge drop wraps the whole arrangement". Decision (B) of #18421 / #18426 made it the operator's DockPanel rule.WorkspaceDocumentcalls the edge-zone root "window chrome".The Architectural Reality
src/dashboard/dock/projection/LayoutAdapter.mjs:collectAutoHiddenItemsand the rail strip per edge band.WorkspaceDocument#findOwningEdgealready resolves a nested-edge contest to the outermost edge, but only among edge-zones.src/dashboard/dock/interaction/DragAffordances.mjs:resolveDockableRoot/guardEmptyWrap, the root-edge wrap.learn/agentos/DockZoneModel.md:edge-zoneis a "root or nested edge container", so the document shape stays legal.The Fix
Rails are projected as window chrome. The auto-hidden items of every band in the root-path edge-zone, the edge-zone the root wraps, render as rail strips at the dock host's outer edges, outside the whole arrangement, at any nesting depth. The wrapped arrangement lays out inside the rail frame.
Acceptance Criteria
WorkstationRootEdgeCornerNL(#18426) stays green.test/playwright/e2e/workstation/WorkstationRailsOutermostNL.spec.mjs. It produces the wrap with a real root-edge drop (a tab dropped on the bottom root-edge chip) and asserts the rail and pane geometry above. It must be red ondev(the bottom rail sits above the dropped pane) and green with the fix, and it joins the hosted Workstation NL tier (#19655).Out of Scope
Related
Live latest-open sweep: checked latest 20 open issues at 2026-10-22T10:45:22Z; no equivalent found. Keyword sweep (10:41Z): "root edge drop wraps", "edge-zone root split", "pane below rail", "guardEmptyWrap"; closed adjacent only (#18421/#18426, #17864, #19521). A2A claim sweep: no overlapping lane-claim. MC sweep: "root edge drop wraps the whole arrangement around the edge-zone root…", 5 results; prior decision found (#18421 decision B, DockPanel), kept per the operator's ruling. Own-assignment sweep: none overlapping.
Origin Session ID: 70e59a84-efd6-4e7a-9262-c5478bd314ff Retrieval Hint: "rails are window chrome outermost edge, DockPanel root-edge wrap nests the edge-zone root, panes below the bottom rail"