LearnNewsExamplesServices
Frontmatter
id18014
titleComplete the default DockLayout action rail in Workstation
stateClosed
labels
enhancementdesignaitestingarchitecturecore
assigneesneo-gpt
createdAtSep 1, 2026, 10:38 AM
updatedAtSep 1, 2026, 7:12 PM
githubUrlhttps://github.com/neomjs/neo/issues/18014
authorneo-gpt-emmy
commentsCount1
parentIssue17836
subIssues[]
subIssuesCompleted0
subIssuesTotal0
contentTrust
projected
quarantined0
signals[]
blockedBy[x] 18015 Focus-hidden toolbar actions leave a gap in the action rail
blocking[]
closedAtSep 1, 2026, 7:12 PM

Complete the default DockLayout action rail in Workstation

Closed Backlog/active-chunk-19 enhancementdesignaitestingarchitecturecore
neo-gpt-emmy
neo-gpt-emmy commented on Sep 1, 2026, 10:38 AM

Context

Epic #17836 is the greenfield DockLayouts authority. The pane-header family shipped through individually gated leaves (#17947, #17948, #17950, #17951, #17963), but the operator acceptance bar was never delivered as one product contract: every DockLayout tabs node uses inline chrome; overflow is first when active; reload · pin · pop-out · maximize occupy the focus-gated middle rail; close is persistent and last; the flagship proves every action and its visual language.

The goal-recovery matrix is recorded at Epic comment 5491147214. Euclid's cross-family convergence review is comment 5491304086. Vega independently mapped the Workstation lifecycle/cache constraints and self-selected that surface. This body folds both peer reviews into one successor rather than creating a second ticket.

Live source was revalidated at dev@bd463173f2; the relevant files are unchanged from the measured current-dev Workstation run.

The Problem

The implementation optimised every leaf for byte-identical-off adoption:

  • DockWorkspace defaults enableDockCloseAction, enableDockPinAction, enableDockReloadAction, enableDockMaximizeAction, and enableDockPopOutAction to false;
  • LayoutAdapter owns the correct frozen ordering, but projects only the subset a consumer explicitly enabled;
  • Workstation enables only close, pin, and maximize;
  • Workstation has no resolveFreshPane contract and its paneCache has no post-commit adoption seam;
  • Workstation owns a mature custom tearOutHandlers lifecycle while the base pop-out action is gated by a separate enableDockTearOutLifecycle construction path;
  • the flagship E2E asserts overflow-first and close-last, so an empty middle rail still passes.

This is the exact leaf-green/product-incomplete failure the recovery is correcting. The five action flags remain public opt-outs, but their product default must be the complete rail.

Rail round-trip acceptance correction

Operator screenshots on current Workstation state expose two product defects in the pin round-trip:

  • The reveal overlay's restore control inherits the default primary Button UI, producing an oversized blue Pin CTA inside pane chrome.
  • Railing the final live item of a tabs child inside an edge-band split leaves that empty tab container and its close action rendered. Closed #15837 removed direct empty tabs bands but explicitly preserved split bands; this is the nested tail of that exemption.

The Architectural Reality

Default rail

  • src/dashboard/dock/projection/LayoutAdapter.mjs#resolveTabConfig already owns the stable node-level action array and frozen order.
  • Neo.tab.plugin.Overflow contributes independently through projectAsAction: true; it must remain first only while overflow exists and must never enter the tab collection.
  • Middle actions inherit TabContainer's showOnFocus / reactive containsFocus contract. Stable action instances change state without replacing the array. #18015 makes focus-inactive actions occupy zero space and excludes collapsed actions from Overflow measurement. Focus may legitimately repartition direct tabs versus the overflow menu.
  • close is the deliberate exception: persistent, contextual: false, and last.
  • lock is outside the operator goal and remains opt-in.

Reload / cache ownership

  • Merged #17996 already routes reload to dockReload() when present and otherwise to the two-phase recreate transaction.
  • apps/workstation/view/Workspace.mjs#resolvePane is cache-backed and owns pane constructors plus shared Provider/Store injection.
  • Workstation's root Provider owns shared Store instances. A generic per-pane “reload the store” default would refresh multiple panes behind a pane-local affordance. Workstation therefore requires an explicit fresh-pane contract; persisted blueprint/store reload is not an honest fallback.
  • resolveFreshPane cannot update paneCache during prepare. A failed insert would leave the old pane live while the cache pointed at an uncommitted candidate.
  • Successful commit needs one post-commit acknowledgement (hook or committed-pane result): candidate is live, cache adopts that exact pane, then the predecessor retires. Refusal/throw leaves slot and cache identities unchanged.

Pop-out / lifecycle ownership

  • Workstation already owns one proven tear-out handler bundle, vessel embodiment, park owners, connection admission, and a custom onDockTearOutExit.
  • Enabling base enableDockTearOutLifecycle merely to satisfy dockPopOutActionActive would construct a second handler/listener lifecycle.
  • Pop-out capability must derive from the one effective host handler/admission bundle. A header click enters the exact same exit → terminal → retire/reintegrate path as the pointer gesture.

The Fix

1. Consume #18015's focus-geometry prerequisite

#18015 owns generic toolbar flow and collapsed-action exclusion from Overflow measurement. This ticket proves that landed behavior in Workstation; it does not duplicate the algorithm.

2. Make the five action flags default-on

Keep these public configs as explicit opt-outs, but default them to true:

  • enableDockCloseAction
  • enableDockPinAction
  • enableDockReloadAction
  • enableDockPopOutAction
  • enableDockMaximizeAction

Keep enableDockLockAction default-off.

Every DockWorkspace projects stable engine identities in this order:

overflow → reload → pin → pop-out → maximize → close

Overflow remains plugin-owned and conditional on actual overflow. Capability/policy changes state, never list membership. Close remains persistent/last; inactive middle actions occupy zero space, and focus may repartition tabs versus the overflow menu without changing action membership or the active-tab invariant.

3. Close the rail round-trip tails

  • Give the reveal overlay's pin/restore affordance a compact non-primary Button treatment through the shared component seam; do not patch only Workstation.
  • During split projection, omit child tab flows with zero live items after railing. Rebuild splitters only between surviving children; an all-empty split makes the owning edge band rail-only. The committed split/tree stays unchanged and returns intact when an item is restored.

4. Complete Workstation reload

  • Factor Workstation's cache-miss pane construction into one fresh-candidate factory that does not consult or mutate paneCache.
  • resolvePane uses it only on cache miss; resolveFreshPane always creates independently.
  • Add the narrow post-commit adoption seam needed to swap paneCache[itemId] only after the exact candidate is live.
  • Delegation retains priority where a pane implements dockReload(); contract-less panes recreate.

5. Complete Workstation pop-out

  • Make action availability derive from Workstation's existing effective handler bundle.
  • Reuse the exact current handler identity and custom exit seam; do not create another lifecycle or listener set.
  • The action measures the live pane and enters the existing pointer tear-out terminal path.

6. Close on one flagship acceptance artifact

Extend the existing Workstation acceptance surface with multiple independent real-click arms—not one order-dependent pane screenplay:

  • exact ordered vector on every projected tabs node;
  • focus reveals the stable middle rail from zero inactive extent without changing action membership; direct tabs may repartition against overflow while the active tab remains directly visible;
  • reload proves delegation and contract-less recreate on different panes;
  • pin proves rail transition and reversible reveal;
  • pop-out proves existing vessel admission and same-pane identity;
  • maximize proves measured workspace geometry and restore;
  • four Engine themes plus Workstation's custom palette produce computed-style receipts;
  • operator screenshot acceptance gates goal closure.

Contract Ledger

Target Surface Source of Authority Proposed Behavior Fallback Docs Evidence
DockWorkspace action configs Epic #17836 product goal five actions default on with explicit false opt-out; lock remains default-off consumer opt-out class/projection JSDoc default + explicit-off matrix
LayoutAdapter action vector existing frozen order stable reload · pin · pop-out · maximize · close; overflow contribution first capability/policy changes state projection JSDoc identity/order/capability arms
middle-rail focus state #17874/#17875 + #18015 inactive actions occupy zero space and are excluded from Overflow measurement; focus may repartition direct tabs/menu while preserving the active tab focus absent ⇒ inert/aria-hidden with zero extent focus + Overflow docs zero-gap + accepted-repartition witness
reveal-overlay pin control operator screenshot + shipped Button UI system compact non-primary restore affordance; no default-primary blue CTA non-restorable ⇒ disabled RevealOverlay + theme docs computed style + four-theme screenshot witness
nested split rail projection #13771 + closed #15837 tail omit zero-live-item split children and rebuild surviving geometry no live descendants ⇒ rail-only band LayoutAdapter JSDoc one-child/all-child/restore matrix
Workstation fresh factory existing cache-miss construction fresh candidate bypasses live cache/store mutation refusal keeps exact live pane/cache method JSDoc config+instance candidate matrix
recreate cache adoption #17996 two-phase commit + Workstation cache authority cache adopts exact committed pane after insert succeeds any refusal/throw leaves cache byte-identical post-commit hook/result JSDoc slot/cache identity arms
Workstation pop-out capability existing tearOutHandlers bundle header action enters same owner and exit/terminal pair no handler ⇒ action hidden/disabled lifecycle JSDoc handler identity + vessel journey
flagship product acceptance operator goal + Epic recovery comment all actions clicked; four themes/custom palette accepted no fixture-only substitution existing Workstation spec comments current-dev E2E + screenshots

Decision Record impact

aligned-with ADR 0029 §§2.1, 2.6, and 2.8 and Epic #17836's greenfield/no-compatibility authority. No persisted schema or wire change.

Acceptance Criteria

  • enableDockCloseAction, enableDockPinAction, enableDockReloadAction, enableDockPopOutAction, and enableDockMaximizeAction default to true and retain explicit false opt-out; enableDockLockAction remains default-off.
  • Every default DockWorkspace projects stable action identities ordered reload · pin · pop-out · maximize · close; overflow is the first action only while overflowing, and remains outside the tab collection.
  • Close is persistent/last. The four middle actions use showOnFocus, have zero main-axis extent while context-inactive, and reveal without replacing/reordering actions; direct tabs may repartition against overflow while the active tab stays directly visible.
  • Reload/pin/pop-out capability or item-policy changes update stable instances through state. Host action ordering and generic non-dock tab behavior remain unchanged.
  • The reveal overlay pin control uses a compact non-primary treatment in all four Engine themes and Workstation palettes; enabled and disabled states remain legible.
  • Railing the last live item from one split child removes that empty tabs shell and its orphan actions; surviving children fill the split, all-empty splits yield rail-only, and restoring an item reconstructs the committed split geometry.
  • Workstation's fresh-pane factory bypasses paneCache; resolvePane uses it only on cache miss and resolveFreshPane always creates independently.
  • Successful recreate adopts the exact committed pane in paneCache only after it is live; every refusal/throw preserves the exact predecessor, slot, cache entry, and document. Delegation retains priority.
  • Workstation pop-out uses the exact existing tearOutHandlers identity and custom exit/terminal path; no second handler/listener/vessel owner is created.
  • Header-action pop-out opens/adopts a vessel at the measured pane rect, and existing retire/reintegration behavior returns the same live pane where required. Refusal commits nothing.
  • One existing Workstation acceptance artifact asserts the ordered vector for every tabs node and independently clicks reload, pin, pop-out, and maximize through production paths.
  • That artifact proves no inactive-action gap, focus-time repartition preserves the active-tab/overflow invariants, no duplicate action owner, and no action/tab contamination.
  • All four Engine themes plus Workstation's custom light/dark palette have computed-style and screenshot evidence. Operator visual acceptance is required before the Epic goal row closes.
  • Exact-head unit, component, and targeted Workstation E2E suites are green; mutation controls prove the default vector, cache adoption, and lifecycle-owner arms red when reverted.

Out of Scope

  • Making lock part of the default engine set.
  • New action names, new action semantics, or a new focus system.
  • Generic showOnFocus flow and collapsed-action exclusion from Overflow measurement (#18015).
  • Restyling inline tabs/header actions; #17950/#17963 own the shipped chrome/value layer.
  • A second reload or tear-out lifecycle.
  • Per-pane Store topology changes.
  • Persisting reload/maximize/action state.
  • Updating external consumer repositories in this PR.

Avoided Traps

  • Delete the public flags. That is an API break not required by the operator goal; default-on plus explicit opt-out delivers the product without forcing every consumer.
  • Another per-app opt-in patch. It fixes one screenshot and leaves the framework default wrong.
  • Generic data reload. Shared Store instances turn a pane-local affordance into a multi-pane refresh.
  • Mutate paneCache during prepare. Failed commit would split live slot and cache truth.
  • Enable the base tear-out lifecycle beside Workstation's bundle. Two handlers/listener sets violate single ownership.
  • Vary action arrays per active item. Retained toolbar identity and overflow projection would race again.
  • One sequential all-action screenplay. Pin/pop-out intentionally move panes; independent arms in one flagship artifact test contracts rather than choreography order.
  • Fixture transfer. Dedicated fixtures do not prove Workstation wiring or operator-visible quality.

Related

Parent: #17836. Blocked by: #18015. Goal-recovery artifact: comment 5491147214. Peer convergence: comment 5491304086. Precedents: #13771, #15837, #17874/#17875, #17947, #17948, #17950/#17956, #17951/#17960, #17963/#17977, #17966/#17996.

Creation freshness: the initial live latest-open/A2A/KB/local sweep found no equivalent. The attempted Workstation successor was not filed; its content was folded here when the last-moment sweep surfaced peer convergence on one close target.

Origin Session ID: 309a78d7-2d95-4f23-bdfc-69d2ae393a5d

Retrieval Hint: query_raw_memories("default DockLayout action rail Workstation paneCache resolveFreshPane one tear-out lifecycle")

— Emmy (GPT-5.6 Sol Ultra, Codex), incorporating Euclid and Vega peer-role convergence.