Context
test/playwright/e2e/workstation/WorkstationNL.spec.mjs — "the real tour keeps density, data, Canvas output, themes, rails, and identities live" — reds deterministically at :1294: expect(darkDockActive.horizontal.active, 'the real dark-mode splitter owns the active pointer target').toBe(true) receives false. Three sightings, one run each, all 8/9 with this sole red: PR #19083's head 4cae0c08bc (01:27Z), clean dev@a186e92cfa (01:29Z), and the review-response head of the same PR (02:51Z). Found while running the film tour's dense-tour control (#19070 AC-4); the film PR touches neither this spec, the dense screenplay, the splitter nor the theme.
The Problem
The light-mode arm at :1164 reads the same probe — readDockChrome (:364) returns element.matches(':active') for .neo-dashboard-dock-split-horizontal > .neo-dashboard-dock-splitter-horizontal — after the same mouse.move + mouse.down, and passes. The dark arm at :1294, later in the same test, fails. The engine's active paint contract (resources/scss/src/dashboard/Container.scss:456: &:active background, ring and handle tokens) is therefore not the difference; something about the second press is. Until it is classified, every Workstation whitebox run carries one red, and #19070's AC-4 can only be stated as baseline parity.
The Architectural Reality
- The probe reads the UA pseudo-class, not an engine class:
:active holds only while the pressed pointer's target chain includes the splitter. The press at :1286–1290 aims at dragSplitterBox, measured at :1260 after the dark toggle at :1172; the same test installs a MutationObserver on the root's class list just before the press (:1273–1283).
DockSplitter#onDragStart (src/dashboard/dock/interaction/DockSplitter.mjs:534) projects the splitter's paint onto a drag proxy that mounts outside the splitter, and the main-thread DragDrop addon owns the mousedown → release bracket. If the proxy or a preview surface takes the pointer target on the second press, :active leaves the splitter while its background may still differ from hover — the assertion order would report exactly this red.
- #17889 (drag sensors → Pointer Events with pointer capture) changes that bracket; a fix here must not pre-empt it.
Classification (2026-09-23, instrumented runs 08:48–09:13Z on the seat's own bridge per #19066)
(b) target taken — by the theme toggle's view transition, not a drag proxy. At the dark press, document.elementsFromPoint(x, y) at the splitter's centre returned only <html> while the splitter was connected with its box exactly where it was measured (live = measured); the pressed chain was [html]. Workspace#toggleWorkspaceTheme (apps/workstation/view/Workspace.mjs:685) runs DomAccess.startViewTransition with a 100 ms capture window and a 500 ms circular reveal (src/main/DomAccess.mjs:1143, src/main/DomUtils.mjs:82), and while the transition runs its ::view-transition pseudo-tree owns hit-testing: at the press the ::view-transition-group/old/new(root) animations stood at t = 100 ms, and the splitter became hit-testable 394–415 ms later. So :active never reached the splitter and the drag never started — the later the user drag commits a semantic resizeSplit document change assertion read a delta of 0. The light arm passed only because its unrelated 1.2 s listener-readiness wait outlasts the reveal. The proxy hypothesis was falsified: no [class*="proxy"] element existed at either press.
Once the press landed, the tour ran further than it had in weeks and unmasked three more layers, each classified: (2) the monitor counted every .neo-tab-header-toolbar under the root (8), but each rail's RevealOverlay composes a runtime-only tab.header.Toolbar (idle-hidden, zero rect, in the DOM from boot) — a test premise, fixed by scoping to the containers' own headers; (3) one sampled frame during splitNode(security → below scale) shows two visible overflow controls, the newborn single-tab Security container's beside the heavy group's — deterministic, engine, filed as #19094; (4) dark splitter active feedback is distinct from hover red 1 in 3 because the splitter's background-color transitions over --dock-transition-duration-fast (120 ms, Container.scss:395) and both reads could catch the colour being left — fixed by settling the four hover/active reads on getAnimations().length === 0; (5) the Canvas receipt (the exact scale Canvas changes after its worker receives new data) reds in 5 of 9 runs with the App-worker values changed and the same, still-transferred canvas node never repainting — captured as a defect-note (09:14Z), mechanism unknown, falsified as unrelated to a held press.
The Fix
Both presses wait until a hit test at the splitter's centre returns the splitter (expectSplitterUnderPointer), so the dark arm keeps its honest :active read; the four hover/active colour reads settle first (readSettledDockChrome); the tour monitor tracks .neo-tab-container > .neo-tab-header-toolbar; the duplicate-overflow sample names a control's real toolbar via closest() (the control is the toolbar's own action contribution). Test-only; no engine change.
Acceptance Criteria
Out of Scope
- #17889's sensor migration.
- The film tour (#19070 / PR #19083), which only reports this red as its control's baseline.
- #19094 (the newborn container's one-frame overflow control) and the Canvas receipt flake — unmasked here, owned elsewhere.
Related
#19070 (its AC-4 names this ticket as the owner of the control's red) · PR #19083 · #17889 · #19084 (tonight's unrelated unit flake, same CI archaeology)
Sweeps: live latest-20 open at 2026-09-23T02:52:44Z — none equivalent (#17889 is the sensor migration, not this symptom); A2A claims in the last 60 min — none on this surface; query_raw_memories on the symptom — no prior decision (nearest hit: an unrelated 08-30 overlay measurement); own open assignments (#19070, #19055, #15252) — none. Title searches "splitter active" and "dark-mode splitter": no open match.
Origin Session ID: 610d2189-0b28-46e2-89f3-3c42eae5de21
Retrieval Hint: query_raw_memories("WorkstationNL dark splitter :active held pointer dense control red readDockChrome")
Ownership: self-assigned — mine after PR #19083 lands; the dock group may take it earlier by reassigning with a note here.
🪢 Mnemosyne (Claude Fable 5.1 · Claude Code) · session 610d2189-0b28-46e2-89f3-3c42eae5de21 · classification and fix in session 522f6841-f568-4800-bff8-7ee8e1f99dd3
Context
test/playwright/e2e/workstation/WorkstationNL.spec.mjs— "the real tour keeps density, data, Canvas output, themes, rails, and identities live" — reds deterministically at:1294:expect(darkDockActive.horizontal.active, 'the real dark-mode splitter owns the active pointer target').toBe(true)receivesfalse. Three sightings, one run each, all 8/9 with this sole red: PR #19083's head4cae0c08bc(01:27Z), cleandev@a186e92cfa(01:29Z), and the review-response head of the same PR (02:51Z). Found while running the film tour's dense-tour control (#19070 AC-4); the film PR touches neither this spec, the dense screenplay, the splitter nor the theme.The Problem
The light-mode arm at
:1164reads the same probe —readDockChrome(:364) returnselement.matches(':active')for.neo-dashboard-dock-split-horizontal > .neo-dashboard-dock-splitter-horizontal— after the samemouse.move+mouse.down, and passes. The dark arm at:1294, later in the same test, fails. The engine's active paint contract (resources/scss/src/dashboard/Container.scss:456:&:activebackground, ring and handle tokens) is therefore not the difference; something about the second press is. Until it is classified, every Workstation whitebox run carries one red, and #19070's AC-4 can only be stated as baseline parity.The Architectural Reality
:activeholds only while the pressed pointer's target chain includes the splitter. The press at:1286–1290aims atdragSplitterBox, measured at:1260after the dark toggle at:1172; the same test installs aMutationObserveron the root's class list just before the press (:1273–1283).DockSplitter#onDragStart(src/dashboard/dock/interaction/DockSplitter.mjs:534) projects the splitter's paint onto a drag proxy that mounts outside the splitter, and the main-threadDragDropaddon owns the mousedown → release bracket. If the proxy or a preview surface takes the pointer target on the second press,:activeleaves the splitter while its background may still differ from hover — the assertion order would report exactly this red.Classification (2026-09-23, instrumented runs 08:48–09:13Z on the seat's own bridge per #19066)
(b) target taken — by the theme toggle's view transition, not a drag proxy. At the dark press,
document.elementsFromPoint(x, y)at the splitter's centre returned only<html>while the splitter was connected with its box exactly where it was measured (live=measured); the pressed chain was[html].Workspace#toggleWorkspaceTheme(apps/workstation/view/Workspace.mjs:685) runsDomAccess.startViewTransitionwith a 100 ms capture window and a 500 ms circular reveal (src/main/DomAccess.mjs:1143,src/main/DomUtils.mjs:82), and while the transition runs its::view-transitionpseudo-tree owns hit-testing: at the press the::view-transition-group/old/new(root)animations stood at t = 100 ms, and the splitter became hit-testable 394–415 ms later. So:activenever reached the splitter and the drag never started — the laterthe user drag commits a semantic resizeSplit document changeassertion read a delta of 0. The light arm passed only because its unrelated 1.2 s listener-readiness wait outlasts the reveal. The proxy hypothesis was falsified: no[class*="proxy"]element existed at either press.Once the press landed, the tour ran further than it had in weeks and unmasked three more layers, each classified: (2) the monitor counted every
.neo-tab-header-toolbarunder the root (8), but each rail'sRevealOverlaycomposes a runtime-onlytab.header.Toolbar(idle-hidden, zero rect, in the DOM from boot) — a test premise, fixed by scoping to the containers' own headers; (3) one sampled frame duringsplitNode(security → below scale)shows two visible overflow controls, the newborn single-tab Security container's beside the heavy group's — deterministic, engine, filed as #19094; (4)dark splitter active feedback is distinct from hoverred 1 in 3 because the splitter'sbackground-colortransitions over--dock-transition-duration-fast(120 ms,Container.scss:395) and both reads could catch the colour being left — fixed by settling the four hover/active reads ongetAnimations().length === 0; (5) the Canvas receipt (the exact scale Canvas changes after its worker receives new data) reds in 5 of 9 runs with the App-workervalueschanged and the same, still-transferred canvas node never repainting — captured as a defect-note (09:14Z), mechanism unknown, falsified as unrelated to a held press.The Fix
Both presses wait until a hit test at the splitter's centre returns the splitter (
expectSplitterUnderPointer), so the dark arm keeps its honest:activeread; the four hover/active colour reads settle first (readSettledDockChrome); the tour monitor tracks.neo-tab-container > .neo-tab-header-toolbar; the duplicate-overflow sample names a control's real toolbar viaclosest()(the control is the toolbar's own action contribution). Test-only; no engine change.Acceptance Criteria
resizeSplitdocument change — the arm's:activeread and its active-vs-hover colour read pass in three consecutive runs ondev. Restated 2026-09-23 after classification: the original 9/9 target is blocked by two reds this fix unmasked, #19094 (deterministic, engine) and the Canvas receipt flake (defect-note), both classified with owners and not this ticket's.Out of Scope
Related
#19070 (its AC-4 names this ticket as the owner of the control's red) · PR #19083 · #17889 · #19084 (tonight's unrelated unit flake, same CI archaeology)
Sweeps: live latest-20 open at 2026-09-23T02:52:44Z — none equivalent (#17889 is the sensor migration, not this symptom); A2A claims in the last 60 min — none on this surface;
query_raw_memorieson the symptom — no prior decision (nearest hit: an unrelated 08-30 overlay measurement); own open assignments (#19070, #19055, #15252) — none. Title searches "splitter active" and "dark-mode splitter": no open match.Origin Session ID: 610d2189-0b28-46e2-89f3-3c42eae5de21 Retrieval Hint:
query_raw_memories("WorkstationNL dark splitter :active held pointer dense control red readDockChrome")Ownership: self-assigned — mine after PR #19083 lands; the dock group may take it earlier by reassigning with a note here.
🪢 Mnemosyne (Claude Fable 5.1 · Claude Code) · session 610d2189-0b28-46e2-89f3-3c42eae5de21 · classification and fix in session 522f6841-f568-4800-bff8-7ee8e1f99dd3