Skip to content

Summary popover: real blur under the glass in see-through windows - #30302

Merged
teamleaderleo merged 8 commits into
feat-cmux-nextfrom
lane/summary-popover-native-glass
Nov 1, 2026
Merged

teamleaderleo merged 8 commits into
feat-cmux-nextfrom
lane/summary-popover-native-glass

Conversation

@teamleaderleo

@teamleaderleo teamleaderleo commented Nov 1, 2026 •

Copy link
Copy Markdown
Collaborator

Leo, on the Summary popover in a translucent window: "I don't like the non-glassness"

Spec: design/overlay-surfaces.md (legibility comes from blur, tint and contrast, never from an opaque fill; Reduce Transparency keeps its system fallback).

The defect

In a see-through window (opacity below 1, or a painting behind the chat), the narrow-pane Summary popover (Session Info, placement="overlay") was a tint with no blur. The transcript under it stayed sharp and ran into the popover's own rows. The cause is Chromium: it draws a backdrop-filter's blurred copy over the page's own pixels, not in their place, so on a clear page the sharp text shows through. The existing stopgap (a 70% theme underlay) only dimmed it. WebKit replaces in place, and an opaque window's backdrop already covers what is under it.

The fix

The page blurs itself under the glass (webviews/src/ui/glass/seeThroughBlur.ts). While a floating glass surface is open in a see-through Chromium page, each element it covers gets filter: url(#…), an SVG filter that:

  • blurs that element's own pixels inside the surface's rounded rect (feGaussianBlur with a primitive subregion, at the surface's own backdrop blur radius);
  • mixes blurred and sharp by the surface's opacity, so it fades in and out with the popover;
  • cuts to the rounded rect and leaves everything outside it untouched.

Then the surface drops its underlay (--glass-underlay: 0%), so no opaque fill is involved. glass.css applies the filter only in a see-through Chromium page, outside the lens and Reduce Transparency. Opaque windows, WebKit and Reduce Transparency behave exactly as before.

Wired into Session Info's overlay popover and the floating Summary card. Both cover the chat stage's blocks (chatUnderGlass.ts), never the composer: a filter there would re-anchor the composer's fixed menus. Edge cases:

  • Over the composer (a short pane's Session Info), the surface keeps its underlay.
  • While CSS hides the Summary card (Find, wherever its bar is; review; inspect), its blocks carry data-glass-under="summary", and summary.css switches their filters off under the same rules.
  • A hidden surface covers nothing.
  • A test DOM without CSS.supports or the observers gets nothing attached.

Other options I tried and rejected:

  • An alpha-boosting backdrop filter: either opaque, or it still leaves sharp text, with banding.
  • Native glass under the CEF view: it cannot blur the page's own transcript.
  • A CEF compositor patch: out of scope.

Cost and cleanup. Nothing in WebKit. In Chromium, while a surface is open, there is:

  • one hidden <svg> with one filter per covered block;
  • a ResizeObserver on the surface, its parent and the covered blocks;
  • a MutationObserver on the blocks' parent (direct children only, never the subtree, so no per-token work);
  • a requestAnimationFrame follow loop that reads every rect first, writes only changes, and stops after 3 unchanged frames. Resize, transition and animation events restart it.

Closing the surface (React layout-effect cleanup) disconnects the observer, removes the listeners, cancels the frame, and removes the attributes, filters and svg.

Limit. In a window set to no blur, the desktop or painting behind the window is not blurred under the popover, because the page cannot see it. The transcript, which is what collided with the popover's text, is blurred. Native blur under the popover's rect is a possible follow-up.

Before / after

Fresh HOME, fake harness, the striped backdrop window, the chat narrowed by a browser on its right.

Translucent window (opacity 0.55, no blur). Before: "Add retries with backoff…", "View changes" and "+29 −0" read through the popover. After: the transcript under it is blurred away and the stripes read as colour.

Light Dark
Before before light before dark
After after light after dark

Painting behind the chat.

Light Dark
Before before light before dark
After after light after dark

Opaque window (unchanged path, for regression):

Light Dark
after light after dark

I viewed the after images in all three states, in light and dark, including zoomed crops of the popover. The captures are at 392db36. Later commits change only the Find/review/inspect, composer-overlap and test-DOM cases, none of which these scenes draw.

Tests

webviews/test/see-through-blur.test.ts (browser lane):

  • Real Chromium pixels: the bars under the popover lose more than 92% of their contrast, the bars outside are unchanged, and detach restores everything.
  • The underlay goes from 70% to 0%.
  • An opaque page gets no filter.
  • A surface hidden by a :has() rule releases its filters and gets them back.
  • The Summary's filters go off when a Find bar opens deep inside the transcript.
  • The underlay comes back over the composer.
  • WebKit attaches nothing.
  • Geometry unit tests.

Also run on the fleet: the glass suites (chromium-glass-underlay, glass-never-opaque, glass-lens, popup-page-root-glass), the overlay-glass and glass-never-opaque lints, tsc, lint, fmt, browser-lane and effect-cleanup checks.

Risk: low to medium. Rendering only, Chromium see-through pages only. The filter is scoped to the covered blocks while a floating glass is open.

🤖 Generated with Claude Code

Agent session: agent session

… see-through Chromium page

Leo: "I don't like the non-glassness". Over a translucent window or a painting,
Chromium drew the popover's backdrop blur over the page's own pixels, so the
chat under it stayed sharp and read through the tint. The covered siblings
now blur their own pixels inside the popover's rounded rect (an SVG filter
per element, ui/glass/seeThroughBlur.ts), and the popover drops the
Chromium underlay it no longer needs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Owned by an agent session · session

@github-actions github-actions Bot added the risk:normal Risk tier (docs/ci/risk-tiers.md) label Nov 1, 2026
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…s blocks

The narrow pane's Summary popover is Session Info floating over the chat
(acpmux-session-info, overlay). It sits beside the chat column, so it names
what it covers: the stage's own blocks (chatUnderGlass.ts), never the whole
column with the composer.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-140531107322b17b78f0
@teamleaderleo
teamleaderleo marked this pull request as ready for review November 1, 2026 07:48
@teamleaderleo teamleaderleo changed the title cmux NEXT glass: the chat blurs itself under the Summary popover over a translucent window Summary popover: real blur under the glass in see-through windows Nov 1, 2026

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 issues found across 6 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="webviews/src/ui/glass/seeThroughBlur.ts">

<violation number="1" location="webviews/src/ui/glass/seeThroughBlur.ts:175">
P2: `release` clears `data-glass-under` and `--glass-under-filter` on a covered element even when another open surface now owns that element. Two surfaces covering the same block will therefore drop each other's blur when one closes. Only remove the attribute and property if the current value still points to this surface's filter id.</violation>

<violation number="2" location="webviews/src/ui/glass/seeThroughBlur.ts:236">
P2: The hole is only recomputed on resize, transition, or animation events, so scrolling that moves a covered element without resizing the surface leaves the blur misplaced. Listen for scroll events in capture phase on the document and call `kick` for them, and remove that listener in the detach function.</violation>
</file>

Reply with feedback, questions, or to request a fix.

View guided diff | Turn on auto-fix | Re-trigger cubic

resize.observe(parent);
surface.addEventListener("transitionrun", kick);
surface.addEventListener("animationstart", kick);
view.addEventListener("resize", kick);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: The hole is only recomputed on resize, transition, or animation events, so scrolling that moves a covered element without resizing the surface leaves the blur misplaced. Listen for scroll events in capture phase on the document and call kick for them, and remove that listener in the detach function.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At webviews/src/ui/glass/seeThroughBlur.ts, line 236:

<comment>The hole is only recomputed on resize, transition, or animation events, so scrolling that moves a covered element without resizing the surface leaves the blur misplaced. Listen for scroll events in capture phase on the document and call `kick` for them, and remove that listener in the detach function.</comment>

<file context>
@@ -0,0 +1,262 @@
+  resize.observe(parent);
+  surface.addEventListener("transitionrun", kick);
+  surface.addEventListener("animationstart", kick);
+  view.addEventListener("resize", kick);
+  return () => {
+    if (frame) view.cancelAnimationFrame(frame);
</file context>

if (!entry) return;
entry.filter.remove();
target.removeAttribute(UNDER_ATTRIBUTE);
target.style.removeProperty(UNDER_FILTER_PROPERTY);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: release clears data-glass-under and --glass-under-filter on a covered element even when another open surface now owns that element. Two surfaces covering the same block will therefore drop each other's blur when one closes. Only remove the attribute and property if the current value still points to this surface's filter id.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At webviews/src/ui/glass/seeThroughBlur.ts, line 175:

<comment>`release` clears `data-glass-under` and `--glass-under-filter` on a covered element even when another open surface now owns that element. Two surfaces covering the same block will therefore drop each other's blur when one closes. Only remove the attribute and property if the current value still points to this surface's filter id.</comment>

<file context>
@@ -0,0 +1,262 @@
+    if (!entry) return;
+    entry.filter.remove();
+    target.removeAttribute(UNDER_ATTRIBUTE);
+    target.style.removeProperty(UNDER_FILTER_PROPERTY);
+    covered.delete(target);
+  };
</file context>

Comment thread webviews/src/ui/glass/seeThroughBlur.ts Resolved
…low the covered blocks

- A window without CSS.supports, ResizeObserver, MutationObserver or animation frames (a test
  DOM) attaches nothing.
- A surface hidden by CSS (the Summary card under Find) covers nothing, so the Find bar and the
  transcript are not blurred under an invisible card.
- The loop also restarts when a covered block resizes or its parent's children change (a banner
  or Find bar coming in), not only on the surface and its parent.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-140531107322b17b78f0
@github-actions

github-actions Bot commented Nov 1, 2026 •

Copy link
Copy Markdown
Contributor

cmux status (one comment, edited in place; each line is updated by the job that owns it)

Review 274f172: HQ feed card · gallery before/after runs · checks

App of this head (app.zip, kept 1 day)

gh workflow run reload-build.yml -R manaflow-ai/cmux --ref feat-cmux-next -f tag=pr30302 -f ref=lane/summary-popover-native-glass -f platform=macos -f backend_mode=local

Stale: these images are of 0fa9e04; the head is now 274f172 and a new capture is running.

Gallery before/after for 0fa9e04: 16 states rendered, 11 images differ, 2314 more touched states not rendered. Images are in the run's artifact, not on this public PR; the independent review of this head reads them on its own, so the PR needs no hand-made screenshots of these states.

gh run download 41286261458 -R manaflow-ai/cmux -n gallery-advisory-30302-0fa9e04cd78c7f97c7f52bd4172636411f3f9d97 (then read gallery-review.json)

States
State Theme Status Diff Picked by
agent-pane.chat-inspector/full Apple System Colors Light unchanged 0% own SessionInfo.tsx
agent-pane.chat-inspector/full Apple System Colors unchanged 0% own SessionInfo.tsx
agent-pane.chat-inspector/workflow-running Apple System Colors Light changed 0.0042% own SessionInfo.tsx
agent-pane.chat-inspector/workflow-running Apple System Colors changed 0.0036% own SessionInfo.tsx
agent-pane.chat-inspector/workflow-finished Apple System Colors Light unchanged 0% own SessionInfo.tsx
agent-pane.chat-inspector/workflow-finished Apple System Colors unchanged 0% own SessionInfo.tsx
agent-pane.chat-inspector/workflow-agent-row-compact Apple System Colors Light changed 0.0044% own SessionInfo.tsx
agent-pane.chat-inspector/workflow-agent-row-compact Apple System Colors changed 0.0039% own SessionInfo.tsx
agent-pane.chat-inspector/workflow-agent-row-detail Apple System Colors Light changed 0.0047% own SessionInfo.tsx
agent-pane.chat-inspector/workflow-agent-row-detail Apple System Colors changed 0.0042% own SessionInfo.tsx
agent-pane.chat-inspector/workflow-agent-row-grid Apple System Colors Light changed 0.0044% own SessionInfo.tsx
agent-pane.chat-inspector/workflow-agent-row-grid Apple System Colors changed 0.0042% own SessionInfo.tsx
agent-pane.chat-inspector/workflow-agent-row-narrow Apple System Colors Light changed 0.0043% own SessionInfo.tsx
agent-pane.chat-inspector/workflow-agent-row-narrow Apple System Colors changed 0.0043% own SessionInfo.tsx
agent-pane.chat-inspector/reorder-dragging Apple System Colors Light changed 0% own SessionInfo.tsx
agent-pane.chat-inspector/reorder-dragging Apple System Colors unchanged 0% own SessionInfo.tsx
agent-pane.chat-inspector-surfaces/transcript Apple System Colors Light unchanged 0% own SessionInfo.tsx
agent-pane.chat-inspector-surfaces/transcript Apple System Colors unchanged 0% own SessionInfo.tsx
agent-pane.chat-inspector-surfaces/diff-in-place Apple System Colors Light unchanged 0% own SessionInfo.tsx
agent-pane.chat-inspector-surfaces/diff-in-place Apple System Colors unchanged 0% own SessionInfo.tsx
agent-pane.chat-inspector-surfaces/document-beside Apple System Colors Light unchanged 0% own SessionInfo.tsx
agent-pane.chat-inspector-surfaces/document-beside Apple System Colors unchanged 0% own SessionInfo.tsx
agent-pane.chat-inspector-surfaces/diff-closed Apple System Colors Light unchanged 0% own SessionInfo.tsx
agent-pane.chat-inspector-surfaces/diff-closed Apple System Colors unchanged 0% own SessionInfo.tsx
agent-pane.computer-use-preview/running Apple System Colors Light unchanged 0% own glass.css
agent-pane.computer-use-preview/running Apple System Colors unchanged 0% own glass.css
agent-pane.computer-use-preview/done Apple System Colors Light unchanged 0% own glass.css
agent-pane.computer-use-preview/done Apple System Colors unchanged 0% own glass.css
agent-pane.computer-use-preview/done-no-icon Apple System Colors Light unchanged 0% own glass.css
agent-pane.computer-use-preview/done-no-icon Apple System Colors unchanged 0% own glass.css
agent-pane.computer-use-preview/beside-chat Apple System Colors Light unchanged 0% own glass.css
agent-pane.computer-use-preview/beside-chat Apple System Colors unchanged 0% own glass.css

Pick other states with a Gallery: entry.id, entry.id/variant line in the PR body.

Shipped in:

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 2 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="webviews/src/ui/glass/seeThroughBlur.ts">

<violation number="1" location="webviews/src/ui/glass/seeThroughBlur.ts:191">
P2: `watched` retains every candidate and parent for the entire attachment, but `measure` never unobserves elements that leave `candidates`; repeated block replacement accumulates observer targets and detached DOM references until close. Track the current candidate/parent set and unobserve stale targets during measurement.</violation>
</file>

Reply with feedback, questions, or to request a fix.

View guided diff | Turn on auto-fix | Re-trigger cubic

const watched = new Set<Element>();
const watch = (element: Element, children: boolean) => {
if (watched.has(element)) return;
watched.add(element);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: watched retains every candidate and parent for the entire attachment, but measure never unobserves elements that leave candidates; repeated block replacement accumulates observer targets and detached DOM references until close. Track the current candidate/parent set and unobserve stale targets during measurement.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At webviews/src/ui/glass/seeThroughBlur.ts, line 191:

<comment>`watched` retains every candidate and parent for the entire attachment, but `measure` never unobserves elements that leave `candidates`; repeated block replacement accumulates observer targets and detached DOM references until close. Track the current candidate/parent set and unobserve stale targets during measurement.</comment>

<file context>
@@ -166,6 +179,19 @@ export function attachSeeThroughBlur(surface: HTMLElement, candidates: CoveredCa
+  const watched = new Set<Element>();
+  const watch = (element: Element, children: boolean) => {
+    if (watched.has(element)) return;
+    watched.add(element);
+    resize.observe(element);
+    if (children) mutations.observe(element, { childList: true });
</file context>

Comment thread webviews/src/ui/glass/seeThroughBlur.ts Resolved
… underlay over the composer

- The Summary popover tags what it covers data-glass-under="summary"; summary.css switches those
  filters off under the same rules that hide the card (Find, wherever its bar is; review; inspect),
  with no observer needed to see it.
- The composer never takes a filter (it would re-anchor its fixed menus), so a surface over it (a
  short pane's Session Info) keeps its underlay.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-140531107322b17b78f0

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

4 issues found across 6 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="webviews/test/see-through-blur.test.ts">

<violation number="1" location="webviews/test/see-through-blur.test.ts:148">
P2: This test uses `.dock` as the composer stand-in, but `attach` passes all siblings as candidates, so `.dock` is blurred when it overlaps the popover. The test never checks that, so the composer-no-filter rule is untested. Exclude the dock from the candidates in the helper so the stand-in matches the composer's role.</violation>
</file>

<file name="webviews/src/ui/glass/seeThroughBlur.ts">

<violation number="1" location="webviews/src/ui/glass/seeThroughBlur.ts:242">
P2: The composer-overlap decision is not re-measured when the dock changes size or children. Observe each `keepUnderlayOver` element (and its child mutations) so `data-glass-over` is restored whenever the composer stack grows or shrinks.</violation>

<violation number="2" location="webviews/src/ui/glass/seeThroughBlur.ts:243">
P2: This overlap test reads zero rects for `display: contents` elements. Outside float mode (reviewing, inspecting, fresh view, diff), `.acpmux-dock` has no box, so an overlay over the in-flow composer never restores its underlay. The keepUnderlayOver target needs elements that have a box, such as the dock's children, or the caller's selector needs changing.</violation>

<violation number="3" location="webviews/src/ui/glass/seeThroughBlur.ts:299">
P3: `options` is now a `useLayoutEffect` dependency, so an inline object literal would re-attach the blur on every render. Document that `options` must be stable too, as `candidates` already is.</violation>
</file>

Reply with feedback, questions, or to request a fix.

View guided diff | Turn on auto-fix | Re-trigger cubic

Comment thread webviews/test/see-through-blur.test.ts Outdated
detach?: () => void;
};
const popover = document.getElementById("popover")!;
target.detach = target.attachSeeThroughBlur(popover, (e) => e.parentElement!.children, {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: This test uses .dock as the composer stand-in, but attach passes all siblings as candidates, so .dock is blurred when it overlaps the popover. The test never checks that, so the composer-no-filter rule is untested. Exclude the dock from the candidates in the helper so the stand-in matches the composer's role.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At webviews/test/see-through-blur.test.ts, line 148:

<comment>This test uses `.dock` as the composer stand-in, but `attach` passes all siblings as candidates, so `.dock` is blurred when it overlaps the popover. The test never checks that, so the composer-no-filter rule is untested. Exclude the dock from the candidates in the helper so the stand-in matches the composer's role.</comment>

<file context>
@@ -133,11 +133,23 @@ await requireBrowserLane("see-through-blur.test.ts", async () => {
+        detach?: () => void;
+      };
+      const popover = document.getElementById("popover")!;
+      target.detach = target.attachSeeThroughBlur(popover, (e) => e.parentElement!.children, {
+        owner,
+        keepUnderlayOver: dock ? () => document.querySelectorAll(".dock") : undefined,
</file context>
Suggested change
target.detach = target.attachSeeThroughBlur(popover, (e) => e.parentElement!.children, {
target.detach = target.attachSeeThroughBlur(popover, (e) => [...e.parentElement!.children].filter((c) => !c.classList.contains("dock")), {

let unblurrable = false;
if (shown && keepUnderlayOver)
for (const element of keepUnderlayOver(surface))
if (overlaps(rect, element.getBoundingClientRect())) unblurrable = true;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: This overlap test reads zero rects for display: contents elements. Outside float mode (reviewing, inspecting, fresh view, diff), .acpmux-dock has no box, so an overlay over the in-flow composer never restores its underlay. The keepUnderlayOver target needs elements that have a box, such as the dock's children, or the caller's selector needs changing.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At webviews/src/ui/glass/seeThroughBlur.ts, line 243:

<comment>This overlap test reads zero rects for `display: contents` elements. Outside float mode (reviewing, inspecting, fresh view, diff), `.acpmux-dock` has no box, so an overlay over the in-flow composer never restores its underlay. The keepUnderlayOver target needs elements that have a box, such as the dock's children, or the caller's selector needs changing.</comment>

<file context>
@@ -225,6 +237,11 @@ export function attachSeeThroughBlur(surface: HTMLElement, candidates: CoveredCa
+    let unblurrable = false;
+    if (shown && keepUnderlayOver)
+      for (const element of keepUnderlayOver(surface))
+        if (overlaps(rect, element.getBoundingClientRect())) unblurrable = true;
+    surface.toggleAttribute(OVER_ATTRIBUTE, !unblurrable);
     const keep = new Set(under.map((entry) => entry.target));
</file context>

Comment thread webviews/src/ui/glass/seeThroughBlur.ts Outdated
}
let unblurrable = false;
if (shown && keepUnderlayOver)
for (const element of keepUnderlayOver(surface))

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: The composer-overlap decision is not re-measured when the dock changes size or children. Observe each keepUnderlayOver element (and its child mutations) so data-glass-over is restored whenever the composer stack grows or shrinks.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At webviews/src/ui/glass/seeThroughBlur.ts, line 242:

<comment>The composer-overlap decision is not re-measured when the dock changes size or children. Observe each `keepUnderlayOver` element (and its child mutations) so `data-glass-over` is restored whenever the composer stack grows or shrinks.</comment>

<file context>
@@ -225,6 +237,11 @@ export function attachSeeThroughBlur(surface: HTMLElement, candidates: CoveredCa
     }
+    let unblurrable = false;
+    if (shown && keepUnderlayOver)
+      for (const element of keepUnderlayOver(surface))
+        if (overlaps(rect, element.getBoundingClientRect())) unblurrable = true;
+    surface.toggleAttribute(OVER_ATTRIBUTE, !unblurrable);
</file context>

}

/** attachSeeThroughBlur for a React surface: attached while `active` and mounted. `candidates` must be
* stable (module-level constants). */

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3: options is now a useLayoutEffect dependency, so an inline object literal would re-attach the blur on every render. Document that options must be stable too, as candidates already is.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At webviews/src/ui/glass/seeThroughBlur.ts, line 299:

<comment>`options` is now a `useLayoutEffect` dependency, so an inline object literal would re-attach the blur on every render. Document that `options` must be stable too, as `candidates` already is.</comment>

<file context>
@@ -279,15 +296,16 @@ export function attachSeeThroughBlur(surface: HTMLElement, candidates: CoveredCa
 
 /** attachSeeThroughBlur for a React surface: attached while `active` and mounted. `candidates` must be
- * stable (a module-level function). */
+ * stable (module-level constants). */
 export function useSeeThroughBlur(
   surface: RefObject<HTMLElement | null>,
</file context>
Suggested change
* stable (module-level constants). */
* stable, and so must `options` (module-level constants). */

…mposer's size

- A surface hidden with visibility keeps its holes, so the Summary's blur is back the moment Find
  closes with no event needed; summary.css switches its filters off meanwhile.
- The elements a surface keeps its underlay over (the composer) are observed too, so the overlap
  follows the composer growing.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-140531107322b17b78f0

This branch was previously deployed

1 inactive deployment
ci-routing-agent — 274f172d Deployed Nov 1, 2026 by teamleaderleo via cmux-tui tree preflight #95458
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

risk:normal Risk tier (docs/ci/risk-tiers.md)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant