LearnNewsExamplesServices
Frontmatter
id19220
titleThe film's capture mode births 146 px wide vessels and the compose beat never converts
stateClosed
labels
bugaidashboard
assigneesneo-fable
createdAtSep 25, 2026, 3:42 PM
updatedAtSep 25, 2026, 8:55 PM
githubUrlhttps://github.com/neomjs/neo/issues/19220
authorneo-fable
commentsCount1
parentIssue15252
subIssues[]
subIssuesCompleted0
subIssuesTotal0
contentTrust
projected
quarantined0
signals[]
blockedBy[]
blocking[]
closedAtSep 25, 2026, 8:55 PM

The film's capture mode births 146 px wide vessels and the compose beat never converts

neo-fable
neo-fable commented on Sep 25, 2026, 3:42 PM

Context

The take arm of the flagship film runs without Playwright viewport emulation: test/playwright/e2e/utils/filmStage.mjs#pinToCaptureDisplay asserts page.viewportSize() is null before and after staging the main window at NEO_FILM_DISPLAY_BOUNDS, so the recording captures a real window. In that mode the film's second-window beat reds every time; under the tour's emulated 1280×800 viewport the same script is green.

Measured 2026-09-25 on the external display (3360×1890, pin 2632,100,1320,920) at dev@f9a776c50c with the per-window sampler (a scratch spec; receipts kept in test-results/dock-wow-demo/glitch-probe/2026-09-25/capture-mode/), one run — the same red twice earlier today at dev@8c54e51132, receipts not kept:

  • main window inner 1320×833, outer 1320×920: the pin is honoured.
  • both vessels (the tear-out's and the conversion's): outer 146×239, inner 146×172, from their first sample (47 ms and 180 ms after creation) to their last; the provisional chrome fills each at 100 %, one tab strip each, no stand-in.
  • lastVesselParkReceipt stayed null for the whole run: no park was ever proposed.
  • tour receipt: film-second-window[1] host step settlement failed: convert-while-dragging: target vessel did not reach one parked semantic + rendered claim.
  • emulated mode today, ten runs: vessels 320×240, the park lands in one attempt, the beat is green.

The Problem

Observation and inference kept apart. Observed: a born width of 146 against a request the app floors at 320 (VesselWorkspace#openTearOutVessel: width = max(round(proxyRect.width || 480), 320), height = max(…, 240)); the height came out 239 outer, so the request reached the platform, and the conversion sensor never proposed a park. Inferred: with a 146 px wide source dragged over a 146 px wide target, the pointer's grab offset inside the source moves the source rect off the target by a large fraction of the smaller extent, so VesselConversion's composed ratio (overlap over the smaller extent per axis, min(rx, ry)) never reaches convertThreshold 0.55 and the sensor never proposes. Which layer narrows the width to 146 — Blink's feature parsing, Chrome's window placement on this display, or the popout boot resizing itself — is unmeasured.

The Architectural Reality

  • apps/workstation/view/VesselWorkspace.mjs#openTearOutVessel (~:1130): the windowFeatures string height=…,left=…,top=…,width=… with the 320×240 floor; tearOutVesselDims and lastVesselOpen record the request.
  • src/dashboard/dock/window/VesselConversion.mjs#sample / axisRatio: overlap divided by the smaller extent per axis, composeRatios = min(rx, ry), entry at 0.55.
  • apps/workstation/tour/NativeGestureDriver.mjs#executeCrossWindowDockStep: the pointer goes to the target's inner centre and waits for remoteSnapshot.ready for attempts frames.
  • test/playwright/e2e/utils/filmStage.mjs: pinToCaptureDisplay (no emulation, the take) vs placeNativeWindow (the tour's emulated placement).

The Fix

Restated 2026-09-25 ~14:20Z by the assignee with the layer named (AC-1) and the scope cut to it; the compose beat's remaining cause moved to its own ticket.

The layer (measured, bare window.open from the pinned main window, one run in each mode): in capture mode a popup opened with height=240,left=3956,top=687,width=320 is born 320×239 inner / 320×306 outer — the platform honours the request. Read synchronously right after window.open(), the newborn answers innerWidth 320, innerHeight 239, outerWidth 0, outerHeight 0: it has no frame yet. Main#windowOpen's useTotalHeight branch resizes it at exactly that moment with resizeTo(outerWidth, innerHeight) → resizeTo(0, 239), and Chrome lands the width on its minimum: 146×239 outer, 146×172 inner — the film's vessels. Under the tour's emulation the same read answers 320×306 at once, so the resize yields 320×240 and the defect never shows. The resize itself is intentional (the window takes the size of the widget it replaces, the content a little smaller); its input was the unlaid frame instead of the request.

The change: Main#windowOpen derives the total size from the feature string (Main.parseWindowFeatureSize: width/height or their inner* spellings, both positive, else no resize) and calls resizeTo(width, height) with the requested numbers. Emulated and real windows now agree: 320×240 outer, the content below the title bar. No caller changes; a request that names no size is left as the platform made it.

Not in this ticket: with the size right, the capture-mode compose beat still reports target vessel did not reach one parked semantic + rendered claim — the target claims the pointer (claimCount: 1) but the conversion never proposes (converted: false, no park receipt). The born vessel's content sits one title bar (67 px) below where the pointer-follow assumes it, so the two inner rects overlap too little on the y axis for the 0.55 threshold. That is the follow's origin, not the size; it has its own ticket (see Related).

Acceptance Criteria

  • AC-1 The layer that narrows the vessel to 146 px is named with a receipt: Main#windowOpen's total-height resize reading the newborn's outerWidth 0; the request-vs-born table is in the comment trail.
  • AC-2 In capture mode on the film-stage display both vessels are born at the requested total size (320×240 outer, 320×173 inner); one headed run at the PR head, per the operator's one-run rule.
  • AC-3 The tracked film arm under emulation reports no new error before its native-return beat (headless refuses that beat by construction), 3/3 headless at the PR head.
  • AC-4 A unit arm drives Main#windowOpen with a newborn that reports no frame and asserts the resize carries the request; red on dev, green with the fix.

Out of Scope

The z-order of a parked vessel (#19186); the film's screenplay, pacing and voice.

Related

#15252 (the film epic, parent), #19225 (the follow origin: the compose beat's remaining capture-mode cause), PR #19224 (this fix), #19186, #19210 (the provisional chrome the born vessels now show), #19070 (the film tour), the docking design record's multi-window amendment.

Live latest-open sweep: checked the latest 20 open issues at 2026-09-25T13:37:06Z; no equivalent. A2A in-flight sweep (the 30 most recent messages, all read states) at 13:38Z: no claim on it. Memory Core sweep: my own defect-note 4e5d523c803d6cac (broadcast 9568e65e, 11:0xZ today) is the only record. Own-assignment sweep: #19186, #19101, #15252 — none covers it.

Retrieval Hint: query_raw_memories("film capture mode vessel born 146 wide compose beat never converts")

Origin Session ID: 4c0a5550-17ba-4752-9852-846afa537c86

tobiu referenced in commit 9a30bc2 - "fix(main): a popup's total size comes from the request, not from its unlaid frame (#19220) (#19224) on Sep 25, 2026, 8:55 PM
tobiu closed this issue on Sep 25, 2026, 8:55 PM