Context
Operator report on apps/workstation (2026-08-29): the left edge splitter can be dragged left, but on drop the side pane snaps back to its initial width; dragging right does not move at all. Both symptoms reproduced first-hand with a real pointer against the dev server, and both trace to the workstation theme's edge-band bounds — with one engine-tier parity hole underneath that turns a mis-themed floor into a silent restore instead of a clamped commit.
Live latest-open sweep: checked latest 20 open issues at 2026-08-29T18:10Z; no equivalent found. A2A claim sweep over the herd window: no competing claim on this scope.
The Problem
Two defects, one theme block, and they contradict each other:
1. The right-drag freeze (dead ceiling). resources/scss/src/apps/workstation/Workspace.scss sets --dock-edge-band-left-max-inline-size: 16.25rem (260px). The committed document boots the left edge at extent: 0.20, which the projection paints as inline width: 20% — 315px in a 1576px row. CSS clamps the render to 260px, so the band boots already pinned at its own max. Neo.main.draggable.Resize#createState folds computed CSS min/max into the clamp window, giving maxSize === startSize → every rightward frame clamps to the start value → zero movement. Measured: a +228px rightward drag stops at exactly 260px.
The constants are 1280px-era: 20.3125cqi × 1280 = 260px = 16.25rem exactly — the trio was authored as a preferred-width clamp(11.25rem, 20.3125cqi, 16.25rem) for static chrome, and PR #17845 unfolded it into real min/max custom properties so the new resize contract could read them. Numerically faithful, semantically different: the clamp's upper arm meant "preferred width tops out here"; a max-inline-size means "the user may never go past here". At any dock host wider than 1300px the left band boots with zero rightward headroom. Same for the other edges: right band boots pinned at its 320px max (25% > 20rem), bottom at its 200px max (25% > 12.5rem).
2. The drop-restore (dead floor). The same theme file also carries .workstation-workspace .neo-dashboard-dock-edge-band { min-height: 0; min-width: 0 } — the classic flex min-content fix. Its physical properties out-cascade the engine's logical min-inline-size: var(..., 11.25rem) band rule (specificity 0,2,0 vs 0,1,0), so the intended 180px floor computes to 0. A decisive leftward drag previews the band down to 0px (it visually vanishes mid-gesture), the terminal reports resizeSize: 0, DockSplitter#resolveEdgeExtent yields extent 0, and Operations.resizeEdgeZone refuses it — the validation domain is the open interval (0,1). The refusal settles the main thread with restore: true, which writes back the pre-gesture inline style: the operator's "restores the initial width". Measured: far-left drag → immediate width: 0px → settled back to the pre-gesture percentage.
Moderate drags inside the live corridor commit exactly (190px → 12.0558%; 260px → 16.4975%) — the resize machinery itself (#17845 settlement + #17849 terminal parity) is healthy. The corridor is just wrong on both ends.
The Architectural Reality
resources/scss/src/apps/workstation/Workspace.scss — .neo-dashboard-dock-edge-band {min-height: 0; min-width: 0} (the floor-killer) and the --dock-edge-band-*-{max,min}-* var trio on .workstation-dock-host.
resources/scss/src/dashboard/Container.scss:422-448 — the engine band rules: min/max-inline-size (left/right) and min/max-block-size (top/bottom) read the per-edge vars with engine defaults min 8rem/6rem, max 50%. The dock host is a container-type: size container, so cqi/cqb terms resolve against it.
src/main/draggable/Resize.mjs#createState — the clamp window comes exclusively from the target's computed CSS bounds; a consumer that zeroes the floor lets the preview paint a state the model categorically refuses.
src/dashboard/dock/interaction/DockSplitter.mjs#getResizeConfig (edge branch) + #resolveEdgeExtent + Operations.resizeEdgeZone (open-interval validation) — the refusal → settleMainThreadResize(restore: true) → exact snapshot restore.
The Fix
App tier (the defect): in resources/scss/src/apps/workstation/Workspace.scss
- Replace the blanket
min-height: 0; min-width: 0 on .neo-dashboard-dock-edge-band with cross-axis-only zeroing (min-height: 0 for left/right bands, min-width: 0 for top/bottom). The drag axis then carries the engine floor vars again — a full-left drag clamps at 11.25rem and commits, instead of collapsing to 0 and being refused.
- Drop the three
--dock-edge-band-*-max-* overrides. The caps no longer serve their original purpose (boot width is governed by the document extent's inline style, not the preferred-width var); today they only limit user drags. Removing them lands on the engine default 50% cap — a container-relative bound on each individual edge, not an aggregate center reservation (opposing edges dragged to their caps can meet in the middle; the reviewer's control measures {left: 500, center: 0, right: 500} for a 1000px row with two 50% bands), unpinned at every size. (Wording corrected per PR #17858 review RA-2, 2026-08-29.)
Engine tier (the parity hole): the preview must never paint a state the semantic commit categorically refuses. The edge branch of DockSplitter#getResizeConfig gains a commit-domain floor (minSize: 1), and Resize#createState folds config.minSize into the clamp window. With this, even a consumer whose CSS zeroes the floor gets a 1px-clamped preview whose terminal commits (extent > 0), never a silent restore. layoutMax already keeps extent < 1.
Contract Ledger
(Backfilled per PR #17858 review RA-1, 2026-08-29. All surface anchors verified at PR head d75e11a279.)
| Target Surface |
Source of Authority |
Proposed Behavior |
Fallback |
Docs |
Evidence |
resizeConfig.minSize — additive optional field on the DragZone resize descriptor (worker → main) |
PR #17858; consumed in src/main/draggable/Resize.mjs#createState |
Main-thread clamp floor becomes max(CSS min bound, descriptor minSize); maxSize derivation unchanged |
Absent or non-finite → contributes 0; behavior byte-identical to pre-PR (CSS bounds alone). Every generic Neo.component.Splitter consumer omits it |
Fold-site comment in Resize.mjs; learn/guides/uibuildingblocks/DockLayouts.md commit-domain floor clause |
Unit descriptor contract + full suite 2041/2041; component mutation check (red with the fold stashed) |
DockSplitter#getResizeConfig edge branch supplies minSize: 1 |
src/dashboard/dock/interaction/DockSplitter.mjs (edge branch only) |
Every edge preview frame stays inside resizeEdgeZone's open (0,1) extent domain — the preview never paints a frame the reducer refuses |
Split-pair branch deliberately carries no minSize: the pair clamp derives from both members' CSS bounds under a constant total |
Method JSDoc + inline rationale |
Unit: edge getResizeConfig toEqual contract + zero-pixel refusal fingerprint through real Operations; component: far-inward real-pointer drag clamps at 1px and commits 1/606 |
| Workstation edge-band bounds disposition |
resources/scss/src/apps/workstation/Workspace.scss + Viewport.scss |
The three --dock-edge-band-*-max-* overrides removed → engine per-edge 50% default governs; min resets scoped to the cross axis (bands) and :not(.neo-dashboard-dock-edge-band) (tab containers) → engine rem floor vars govern the drag axis |
Engine defaults in resources/scss/src/dashboard/Container.scss:422-448 (max 50%, floors 8rem/6rem under the per-edge vars) |
SCSS comments at both edit sites state the cascade rationale |
Real-pointer receipts: rightward 315→515px commits 32.69%; far-left clamps at 180px commits 11.4213%, no snap-back |
Acceptance Criteria
Out of Scope
- Re-deriving workstation's preferred band sizes (
20.3125cqi etc.) — they are shadowed by document extents at runtime; harmless.
- Whitebox NL journey extension for edge drags (
WorkstationEdgeSplitterNL both-direction tour) — rides the #17844 journey lane; e2e runs in no CI (per the #17853 resolution), so this ticket's teeth are unit/component tier.
- Boot divergence normalization (document
extent: 0.20 vs CSS-clamped paint): removing the caps dissolves the common case; floor-pinned boot at very narrow windows commits truthfully on first drag.
Decision Record impact
aligned-with ADR 0029 (docking design): preview-commit parity — the committed vector equals the final preview by construction — is the design value the engine-tier floor completes for the refusal domain.
Related
- #17836 (epic — DockLayouts greenfield; this is a film-path polish leaf)
- PR #17845 (introduced resizable edges + unfolded the clamp; the theme constants predate interactivity)
- PR #17849 (terminal parity; the healthy commit path proven by the moderate-drag receipts)
- #17241 (dock visual-language promotion — adjacent; this ticket keeps workstation density policy in workstation)
- #17844 (journey-tier follow-up home)
Origin Session ID: c98e1ede-1a32-46f3-90ef-aaf37def487d
Retrieval Hint: "workstation edge band boot-pinned max dead floor resize agency"
Context
Operator report on
apps/workstation(2026-08-29): the left edge splitter can be dragged left, but on drop the side pane snaps back to its initial width; dragging right does not move at all. Both symptoms reproduced first-hand with a real pointer against the dev server, and both trace to the workstation theme's edge-band bounds — with one engine-tier parity hole underneath that turns a mis-themed floor into a silent restore instead of a clamped commit.Live latest-open sweep: checked latest 20 open issues at 2026-08-29T18:10Z; no equivalent found. A2A claim sweep over the herd window: no competing claim on this scope.
The Problem
Two defects, one theme block, and they contradict each other:
1. The right-drag freeze (dead ceiling).
resources/scss/src/apps/workstation/Workspace.scsssets--dock-edge-band-left-max-inline-size: 16.25rem(260px). The committed document boots the left edge atextent: 0.20, which the projection paints as inlinewidth: 20%— 315px in a 1576px row. CSS clamps the render to 260px, so the band boots already pinned at its own max.Neo.main.draggable.Resize#createStatefolds computed CSS min/max into the clamp window, givingmaxSize === startSize→ every rightward frame clamps to the start value → zero movement. Measured: a +228px rightward drag stops at exactly 260px.The constants are 1280px-era:
20.3125cqi × 1280 = 260px = 16.25remexactly — the trio was authored as a preferred-widthclamp(11.25rem, 20.3125cqi, 16.25rem)for static chrome, and PR #17845 unfolded it into realmin/maxcustom properties so the new resize contract could read them. Numerically faithful, semantically different: the clamp's upper arm meant "preferred width tops out here"; amax-inline-sizemeans "the user may never go past here". At any dock host wider than 1300px the left band boots with zero rightward headroom. Same for the other edges: right band boots pinned at its 320px max (25% > 20rem), bottom at its 200px max (25% > 12.5rem).2. The drop-restore (dead floor). The same theme file also carries
.workstation-workspace .neo-dashboard-dock-edge-band { min-height: 0; min-width: 0 }— the classic flex min-content fix. Its physical properties out-cascade the engine's logicalmin-inline-size: var(..., 11.25rem)band rule (specificity 0,2,0 vs 0,1,0), so the intended 180px floor computes to 0. A decisive leftward drag previews the band down to0px(it visually vanishes mid-gesture), the terminal reportsresizeSize: 0,DockSplitter#resolveEdgeExtentyields extent0, andOperations.resizeEdgeZonerefuses it — the validation domain is the open interval(0,1). The refusal settles the main thread withrestore: true, which writes back the pre-gesture inline style: the operator's "restores the initial width". Measured: far-left drag → immediatewidth: 0px→ settled back to the pre-gesture percentage.Moderate drags inside the live corridor commit exactly (190px →
12.0558%; 260px →16.4975%) — the resize machinery itself (#17845 settlement + #17849 terminal parity) is healthy. The corridor is just wrong on both ends.The Architectural Reality
resources/scss/src/apps/workstation/Workspace.scss—.neo-dashboard-dock-edge-band {min-height: 0; min-width: 0}(the floor-killer) and the--dock-edge-band-*-{max,min}-*var trio on.workstation-dock-host.resources/scss/src/dashboard/Container.scss:422-448— the engine band rules:min/max-inline-size(left/right) andmin/max-block-size(top/bottom) read the per-edge vars with engine defaultsmin 8rem/6rem,max 50%. The dock host is acontainer-type: sizecontainer, socqi/cqbterms resolve against it.src/main/draggable/Resize.mjs#createState— the clamp window comes exclusively from the target's computed CSS bounds; a consumer that zeroes the floor lets the preview paint a state the model categorically refuses.src/dashboard/dock/interaction/DockSplitter.mjs#getResizeConfig(edge branch) +#resolveEdgeExtent+Operations.resizeEdgeZone(open-interval validation) — the refusal →settleMainThreadResize(restore: true)→ exact snapshot restore.The Fix
App tier (the defect): in
resources/scss/src/apps/workstation/Workspace.scssmin-height: 0; min-width: 0on.neo-dashboard-dock-edge-bandwith cross-axis-only zeroing (min-height: 0for left/right bands,min-width: 0for top/bottom). The drag axis then carries the engine floor vars again — a full-left drag clamps at 11.25rem and commits, instead of collapsing to 0 and being refused.--dock-edge-band-*-max-*overrides. The caps no longer serve their original purpose (boot width is governed by the document extent's inline style, not the preferred-width var); today they only limit user drags. Removing them lands on the engine default50%cap — a container-relative bound on each individual edge, not an aggregate center reservation (opposing edges dragged to their caps can meet in the middle; the reviewer's control measures{left: 500, center: 0, right: 500}for a 1000px row with two 50% bands), unpinned at every size. (Wording corrected per PR #17858 review RA-2, 2026-08-29.)Engine tier (the parity hole): the preview must never paint a state the semantic commit categorically refuses. The edge branch of
DockSplitter#getResizeConfiggains a commit-domain floor (minSize: 1), andResize#createStatefoldsconfig.minSizeinto the clamp window. With this, even a consumer whose CSS zeroes the floor gets a 1px-clamped preview whose terminal commits (extent > 0), never a silent restore.layoutMaxalready keepsextent < 1.Contract Ledger
(Backfilled per PR #17858 review RA-1, 2026-08-29. All surface anchors verified at PR head
d75e11a279.)resizeConfig.minSize— additive optional field on the DragZone resize descriptor (worker → main)src/main/draggable/Resize.mjs#createStatemax(CSS min bound, descriptor minSize);maxSizederivation unchanged0; behavior byte-identical to pre-PR (CSS bounds alone). Every genericNeo.component.Splitterconsumer omits itResize.mjs;learn/guides/uibuildingblocks/DockLayouts.mdcommit-domain floor clauseDockSplitter#getResizeConfigedge branch suppliesminSize: 1src/dashboard/dock/interaction/DockSplitter.mjs(edge branch only)resizeEdgeZone's open(0,1)extent domain — the preview never paints a frame the reducer refusesminSize: the pair clamp derives from both members' CSS bounds under a constant totalgetResizeConfigtoEqualcontract + zero-pixel refusal fingerprint through realOperations; component: far-inward real-pointer drag clamps at 1px and commits1/606resources/scss/src/apps/workstation/Workspace.scss+Viewport.scss--dock-edge-band-*-max-*overrides removed → engine per-edge50%default governs; min resets scoped to the cross axis (bands) and:not(.neo-dashboard-dock-edge-band)(tab containers) → engine rem floor vars govern the drag axisresources/scss/src/dashboard/Container.scss:422-448(max 50%, floors8rem/6remunder the per-edge vars)32.69%; far-left clamps at 180px commits11.4213%, no snap-backAcceptance Criteria
resizeEdgeZonecommit in workstation.minSize: 1alongsideawaitWorkerSettlement: true.restore: truesettle).Out of Scope
20.3125cqietc.) — they are shadowed by document extents at runtime; harmless.WorkstationEdgeSplitterNLboth-direction tour) — rides the #17844 journey lane; e2e runs in no CI (per the #17853 resolution), so this ticket's teeth are unit/component tier.extent: 0.20vs CSS-clamped paint): removing the caps dissolves the common case; floor-pinned boot at very narrow windows commits truthfully on first drag.Decision Record impact
aligned-with ADR 0029 (docking design): preview-commit parity — the committed vector equals the final preview by construction — is the design value the engine-tier floor completes for the refusal domain.
Related
Origin Session ID: c98e1ede-1a32-46f3-90ef-aaf37def487d Retrieval Hint: "workstation edge band boot-pinned max dead floor resize agency"