Before submitting
Area
apps/web
Steps to reproduce
- Open a thread with enough scrollback that chat text sits directly behind the composer.
- Get any attached banner to appear above the composer — for example let a server update land ("Server update available"), or resume a session with a large context so "Resume with less context" appears.
- Look closely at the join between the banner's bottom edge and the composer's top edge, with bright text scrolled behind it.
Seen on the macOS desktop app, dark theme, Retina.
Expected behavior
The banner and the composer read as one continuous surface. Whatever is behind them is blurred by the glass, and nothing from the chat shows through the join.
Actual behavior
A row roughly one device pixel tall at the join is painted by neither surface, so the chat behind shows through it crisp and unblurred — a sliver of a text line running the width of the banner. It is most obvious when a bright line of text scrolls behind the seam.
It affects every attached banner, not one of them: the two screenshots below are "Resume with less context" and "Server update available".
Impact
Cosmetic issue
Version or commit
Desktop app on macOS; reproduced against main at 4c51b4c (v0.0.35-nightly).
Logs or stack traces
Investigation, in case it saves someone the bisect:
The composer's own backdrop-filter loses about a device pixel of backdrop at its top edge whenever its box lands off the device-pixel grid. Under an attached drawer the content that goes missing is the drawer's surface, so the page behind shows through that row. This is why the leak is unblurred: nothing is painting there at all.
Two controls that pin it down, measured in a harness driving the real ComposerBannerStack and the composer shell over a saturated backdrop, sweeping device pixel ratios against sub-pixel phase offsets:
- Forcing the composer's
backdrop-filter: none → leaks drop to 0/64.
- Disabling the drawer's
backdrop-filter, or adding translateZ(0) → no change at all (31/64 either way).
466 of 768 swept configurations leak. It is not mask or overlap arithmetic: --chat-composer-attachment-overlap drives both the mask cut-off and the slot's negative margin, so the two painted regions are designed to abut with exactly zero overlap (measured bannerLastPaintedRow + 1 === composerFirstPaintedRow), which leaves no margin for the lost row. Widening that overlap reduces the leak but then plateaus — 8px behaves the same as 2px — which is what rules the overlap out as the cause.
A fractional offset on an ancestor (the real app has these from panel layout and view transitions) reproduces it at every ratio including an exact 2×, so Retina is not exempt.
Screenshots, recordings, or supporting files
"Resume with less context" — a line of chat text visible through the seam:
"Server update available" — same defect, different banner:
For contrast, a banner that happened to land clean. Worth including because it is misleading: it is not structurally different, it just landed on a sub-pixel phase that does not leak. Both variants leak identically once phase is swept, so banner height and content are not the discriminator.
Workaround
None from the UI. Dismissing the banner removes it, which removes the seam with it.
Before submitting
Area
apps/web
Steps to reproduce
Seen on the macOS desktop app, dark theme, Retina.
Expected behavior
The banner and the composer read as one continuous surface. Whatever is behind them is blurred by the glass, and nothing from the chat shows through the join.
Actual behavior
A row roughly one device pixel tall at the join is painted by neither surface, so the chat behind shows through it crisp and unblurred — a sliver of a text line running the width of the banner. It is most obvious when a bright line of text scrolls behind the seam.
It affects every attached banner, not one of them: the two screenshots below are "Resume with less context" and "Server update available".
Impact
Cosmetic issue
Version or commit
Desktop app on macOS; reproduced against
mainat 4c51b4c (v0.0.35-nightly).Logs or stack traces
Investigation, in case it saves someone the bisect:
The composer's own
backdrop-filterloses about a device pixel of backdrop at its top edge whenever its box lands off the device-pixel grid. Under an attached drawer the content that goes missing is the drawer's surface, so the page behind shows through that row. This is why the leak is unblurred: nothing is painting there at all.Two controls that pin it down, measured in a harness driving the real
ComposerBannerStackand the composer shell over a saturated backdrop, sweeping device pixel ratios against sub-pixel phase offsets:backdrop-filter: none→ leaks drop to 0/64.backdrop-filter, or addingtranslateZ(0)→ no change at all (31/64 either way).466 of 768 swept configurations leak. It is not mask or overlap arithmetic:
--chat-composer-attachment-overlapdrives both the mask cut-off and the slot's negative margin, so the two painted regions are designed to abut with exactly zero overlap (measuredbannerLastPaintedRow + 1 === composerFirstPaintedRow), which leaves no margin for the lost row. Widening that overlap reduces the leak but then plateaus — 8px behaves the same as 2px — which is what rules the overlap out as the cause.A fractional offset on an ancestor (the real app has these from panel layout and view transitions) reproduces it at every ratio including an exact 2×, so Retina is not exempt.
Screenshots, recordings, or supporting files
"Resume with less context" — a line of chat text visible through the seam:
"Server update available" — same defect, different banner:
For contrast, a banner that happened to land clean. Worth including because it is misleading: it is not structurally different, it just landed on a sub-pixel phase that does not leak. Both variants leak identically once phase is swept, so banner height and content are not the discriminator.
Workaround
None from the UI. Dismissing the banner removes it, which removes the seam with it.