Demo prep for 2026-09-03 (operator-observed, 2026-09-02): the engine header actions on every DockLayouts tabs node are icon-only buttons with no tooltip, so a pointer user gets no name for a glyph — and the demo walks through lock, reload, unpin, pop-out, maximize and close on real panes. Filed as one of the dock-polish leaves of Epic #13158 (sibling today: #18070, reveal-preview geometry).
The Problem
src/dashboard/dock/projection/LayoutAdapter.mjs:1103-1180 projects the six engine actions; none carries a tooltip. Accessible names are uneven: lock and pin set aria-label explicitly (lock/unlock, unpin), the reveal overlay's pin control says Pin (src/dashboard/dock/interaction/RevealOverlay.mjs:160), while reload, pop-out, maximize and close fall back to the name toolbar.Base#createActionItemConfig derives from the action key (reload, pop out, maximize, close). One of them drifts: Workspace#syncDockMaximizeActionIcon (src/dashboard/dock/Workspace.mjs:2858-2863) swaps the glyph to dockMinimizeIconCls on maximize but leaves aria-label: maximize in place, so the restore glyph is announced as "maximize". Lock already flips icon and label together in syncDockLockAction (Workspace.mjs:1466-1500) — the pattern the rest should follow.
The Architectural Reality
component.Base#tooltip_ (src/component/Base.mjs:286-296): a string or config; without ownInstance the component joins the per-app shared tooltip singleton (neo-uses-shared-tooltip), which copies target._tooltip on hover (tooltip.Base.applySingletonTargetConfig, showDelay 200 ms). The config is reactive — afterSetTooltip rebuilds on change — so a text set on the retained instance is live for the next hover. createActionItemConfig spreads the action config onto the button, so a tooltip key on an action config reaches the instance untouched.
Engine action chrome is projected from the workspace context (Workspace.mjs:3262-3290 carries dockLockIconCls, dockMaximizeIconCls, dockPopOutIconCls …) — the seam a tooltip text travels through, and the precedent for consumer-overridable engine chrome.
Per-item runtime state rides the ONE retained action instance (syncDock*Action; the stable-instance rule the adapter documents at LayoutAdapter.mjs:1120-1127). A tooltip that follows a toggle is set on that instance, never by re-projecting the actions array.
The reveal overlay's pin control is its own TabHeaderToolbar action (RevealOverlay.mjs:150-160), bound by Rail#bindRevealOverlay; it needs the same text by the same discipline.
A withdrawn action has no DOM node (#18042, PR #18069), so it has no tooltip target — the focus gate is untouched by this work.
The Fix
One consumer-overridable map on Workspace:dockActionTooltips, engine defaults keyed by action state — lock, unlock, reload, unpin, popOut, maximize, restore, close, revealPin — beside the icon configs (Workspace.mjs:147-230). A consumer changes wording or language in one place; a missing key means no tooltip for that action, never a broken button.
Projection: the adapter reads the map from the context and stamps tooltip on each engine action config, choosing lock/unlock the way it chooses the icon.
Toggles on the retained instance:syncDockLockAction adds tooltip to its batched changes; the maximize sync flips icon, aria-label and tooltip together (maximize ↔ restore), closing the announced-name drift.
Reveal overlay: the overlay gains a tooltip config for its pin control, fed from the map at the seam where the workspace instantiates the overlay.
JSDoc on the map and both syncs; the styling-guide slot stays with #18036.
one map, engine defaults, per-key consumer override
absent key → whatever the projection stamped; an explicit null → no tooltip for that action, and on a toggle it clears the tooltip in the state that key names while the other half restores its own
Decision Record impact: aligned-with ADR 0029 — presentation on the retained action instances; no model, operation or wire change.
Acceptance Criteria
Each engine header action (lock, reload, pin, pop-out, maximize, close) and the reveal overlay's pin control shows an engine tooltip on hover whose text names the action; a component witness hovers each on a revealed rail and reads the shared tooltip's text.
Lock ↔ unlock and maximize ↔ restore flip tooltip, icon and aria-label together on the retained instance (no actions-array rebuild); the maximize action reads aria-label: restore while the restore glyph shows.
The texts live in one Workspace config map with engine defaults; a consumer override reaches the projected action, and an absent key yields no tooltip rather than an error.
Focus gating is unchanged: a withdrawn action has no node and no tooltip; a revealed one keeps its tooltip.
The existing dock witnesses (DockLock, DockMaximize, DockPopOut, DockReload) and the tab header unit suite stay green.
Out of Scope
Tooltips on consumer hostActions (consumer-owned) and on the rail's strip tabs (their titles are visible text).
Tooltip theming, geometry and delays (tooltip.Base owns them).
An i18n mechanism beyond the map.
Avoided Traps
Native title attributes: the browser tooltip ignores the theme and its own delays, and title beside aria-label double-announces in some assistive tech; the engine tooltip is the one already themed and delegated.
Re-projecting the actions array to change text breaks the stable-instance contract every syncDock*Action relies on.
Nine dockXTooltip configs: one map is one knob; the icon configs stay as they are because they predate the map.
#18014 (default action rail), #17949 (lock), #18042 / PR #18069 (withdrawn = no node), #18036 (styling and action-chrome guide slot).
Live latest-open sweep: checked the latest 20 open Engine issues at 2026-09-02T10:52Z; nearest are #18036 (the doc slot) and #18070 (L3 geometry), no equivalent. Local corpus and Knowledge Base sweeps: no tooltip ticket on the dock action chrome. A2A latest all-status sweep: L3 claimed by @neo-opus-ada (#18070, 10:51Z), no claim on the tooltips leaf. Agent OS structure-map gate: N/A (Engine dock presentation).
Context
Demo prep for 2026-09-03 (operator-observed, 2026-09-02): the engine header actions on every DockLayouts tabs node are icon-only buttons with no tooltip, so a pointer user gets no name for a glyph — and the demo walks through lock, reload, unpin, pop-out, maximize and close on real panes. Filed as one of the dock-polish leaves of Epic #13158 (sibling today: #18070, reveal-preview geometry).
The Problem
src/dashboard/dock/projection/LayoutAdapter.mjs:1103-1180projects the six engine actions; none carries atooltip. Accessible names are uneven: lock and pin setaria-labelexplicitly (lock/unlock,unpin), the reveal overlay's pin control saysPin(src/dashboard/dock/interaction/RevealOverlay.mjs:160), while reload, pop-out, maximize and close fall back to the nametoolbar.Base#createActionItemConfigderives from the action key (reload,pop out,maximize,close). One of them drifts:Workspace#syncDockMaximizeActionIcon(src/dashboard/dock/Workspace.mjs:2858-2863) swaps the glyph todockMinimizeIconClson maximize but leavesaria-label: maximizein place, so the restore glyph is announced as "maximize". Lock already flips icon and label together insyncDockLockAction(Workspace.mjs:1466-1500) — the pattern the rest should follow.The Architectural Reality
component.Base#tooltip_(src/component/Base.mjs:286-296): a string or config; withoutownInstancethe component joins the per-app shared tooltip singleton (neo-uses-shared-tooltip), which copiestarget._tooltipon hover (tooltip.Base.applySingletonTargetConfig, showDelay 200 ms). The config is reactive —afterSetTooltiprebuilds on change — so a text set on the retained instance is live for the next hover.createActionItemConfigspreads the action config onto the button, so atooltipkey on an action config reaches the instance untouched.Workspace.mjs:3262-3290carriesdockLockIconCls,dockMaximizeIconCls,dockPopOutIconCls…) — the seam a tooltip text travels through, and the precedent for consumer-overridable engine chrome.syncDock*Action; the stable-instance rule the adapter documents atLayoutAdapter.mjs:1120-1127). A tooltip that follows a toggle is set on that instance, never by re-projecting the actions array.TabHeaderToolbaraction (RevealOverlay.mjs:150-160), bound byRail#bindRevealOverlay; it needs the same text by the same discipline.The Fix
Workspace:dockActionTooltips, engine defaults keyed by action state —lock,unlock,reload,unpin,popOut,maximize,restore,close,revealPin— beside the icon configs (Workspace.mjs:147-230). A consumer changes wording or language in one place; a missing key means no tooltip for that action, never a broken button.tooltipon each engine action config, choosinglock/unlockthe way it chooses the icon.syncDockLockActionaddstooltipto its batched changes; the maximize sync flips icon,aria-labeland tooltip together (maximize↔restore), closing the announced-name drift.Contract Ledger
Workspace#dockActionTooltips(new config)dockLockIconCls/dockMaximizeIconCls(Workspace.mjs:147-230)null→ no tooltip for that action, and on a toggle it clears the tooltip in the state that key names while the other half restores its ownLayoutAdapter.mjs:1103-1180)tooltipfrom the map; lock/unlock chosen with the iconWorkspace#syncDockLockAction, the maximize syncaria-labelon the retained instance; maximize gains the label flipRevealOverlay.mjs:150-160)revealPinDecision Record impact: aligned-with ADR 0029 — presentation on the retained action instances; no model, operation or wire change.
Acceptance Criteria
aria-labeltogether on the retained instance (no actions-array rebuild); the maximize action readsaria-label: restorewhile the restore glyph shows.Workspaceconfig map with engine defaults; a consumer override reaches the projected action, and an absent key yields no tooltip rather than an error.Out of Scope
hostActions(consumer-owned) and on the rail's strip tabs (their titles are visible text).tooltip.Baseowns them).Avoided Traps
titleattributes: the browser tooltip ignores the theme and its own delays, andtitlebesidearia-labeldouble-announces in some assistive tech; the engine tooltip is the one already themed and delegated.syncDock*Actionrelies on.dockXTooltipconfigs: one map is one knob; the icon configs stay as they are because they predate the map.Related
Live latest-open sweep: checked the latest 20 open Engine issues at 2026-09-02T10:52Z; nearest are #18036 (the doc slot) and #18070 (L3 geometry), no equivalent. Local corpus and Knowledge Base sweeps: no tooltip ticket on the dock action chrome. A2A latest all-status sweep: L3 claimed by @neo-opus-ada (#18070, 10:51Z), no claim on the tooltips leaf. Agent OS structure-map gate: N/A (Engine dock presentation).
Origin Session ID: 37bbc610-f0cd-4abb-95c2-eb70336a86f3
Retrieval Hint:
query_raw_memories("dock header action tooltips dockActionTooltips maximize restore aria-label sync reveal pin")🪢 Mnemosyne (Claude Fable 5.1, Claude Code)