Skip to content

test(next): glass is never opaque, natively and in webviews; the open pane sidebar is glass - #23366

Merged
teamleaderleo merged 2 commits into
feat-cmux-nextfrom
cmux/glass-never-opaque
Oct 21, 2026
Merged

teamleaderleo merged 2 commits into
feat-cmux-nextfrom
cmux/glass-never-opaque

Conversation

@teamleaderleo

@teamleaderleo teamleaderleo commented Oct 21, 2026 •

Copy link
Copy Markdown
Collaborator

The rule: glass is never opaque (Leo 2026-10-20: "we want a lot of glass... I hate opaque"). A surface that blurs what is behind it, or is declared glass, must let that backdrop show. Reduce Transparency is the one place glass turns solid. This PR adds one guard with a native side and a web side, modeled on the pane toolbar's no-raw-accent-lit-glyph (an ast-grep rule plus a webviews test). It also fixes the one existing violation the guard found.

The guard

  • Native: scripts/cmux-next/lint/ast-grep-rules/no-opaque-glass.yml. The pinned ast-grep rules run in scripts/cmux-next/prepush-gate.py (pre-push hook) and in CI as the step "Pushed commits add no violations" of the cmux-next checks job (.github/workflows/cmux-next.yml). It flags:

    • an opaque tintColor or layer fill on a view named glass or visual effect. Opaque means Palette.popupSurface, alpha 1 (withAlphaComponent(1), alpha: 1), or a solid system color.
    • isOpaque = true, or var isOpaque: Bool { true }, in a subclass of NSVisualEffectView, NSGlassEffectView or GlassPanelView.
    • an opaque .background(...) right before or after .glassEffect(...) in SwiftUI.

    The Reduce Transparency paths draw a separate plain view (OverlaySurface's .opaque material view, the shortcut chip's fill), so the rule doesn't match them. The reviewed escape is // glass-opaque-allow: <why>, added to the gate's ESCAPES.

  • Web: webviews/test/glass-never-opaque.test.ts, with the logic in webviews/scripts/check-glass-never-opaque.ts. CI runs it in the step "Test webviews" of web / react-apps-check (N) (ci-web.yml, via ci.yml on PRs and cmux-next-web.yml on feat-cmux-next pushes). A plain expect, so it fails the job. It scans every CSS file under webviews/src, skipping rules under @media (prefers-reduced-transparency: reduce) or [data-reduce-transparency] (not (...) and :not([...]) are still checked). It flags:

    • a rule with an active backdrop-filter, or a class named glass, whose background resolves opaque.
    • a --*glass* token set to an opaque color or a 100% share.

    "Opaque" counts only what the scan can prove: a literal color with no alpha, Canvas, a token whose every definition is opaque (the host's --cmux-*solid* and --cmux-popup-surface count), or a color-mix of two opaque colors. Anything it can't resolve passes, so a solid card that sets no blur (.ui-card) is never flagged. The escape is /* glass-opaque-allow: <why> */ on the line before. A second test runs the scan over a fixture, so it can't pass by finding nothing.

This complements #23133, which renders gallery stages in Chromium and catches computed opaque glass at runtime. This guard is static: it covers Swift, and CSS states the gallery doesn't render (the open sidebar below is one). The two PRs share no files.

Violations fixed

Where Before After
webviews/src/agent-session/acpmux/styles.css:5, .acpmux-shell[data-sidebar=open] .acpmux-sidebar (the narrow pane's open session sidebar, over the transcript) background: var(--acpmux-base) under backdrop-filter: var(--surface-blur): an opaque fill, so the blur never showed background: color-mix(in srgb, var(--acpmux-base) var(--surface-text-min, 92%), transparent): the text floor desktop.css sets for translucent surfaces that carry text. Under Reduce Transparency, desktop.css makes it 100% and the blur none, so it is solid again

The native scan of Packages/macOS/CmuxNext/Sources finds nothing today, so no Swift file changes.

#23000's toast (CmuxNextFloating/ChiefPet/ChiefPetBubble.swift, which another session is reworking) isn't flagged and isn't touched, so it needs no exclusion.

Red, then green

Commit 1 (6a9d0a2) adds the guard only. Commit 2 (c3ac1f8) adds the fix.

$ (cd webviews && bun scripts/check-glass-never-opaque.ts)   # at commit 1
glass is never opaque: agent-session/acpmux/styles.css:5: .acpmux-shell[data-sidebar=open] .acpmux-sidebar { background: var(--acpmux-base) }
exit=1

$ (cd webviews && bun scripts/check-glass-never-opaque.ts)   # at commit 2
Glass fills checked: none opaque.
exit=0
$ ast-grep scan -c scripts/cmux-next/lint/sgconfig.yml --filter no-opaque-glass Packages/macOS/CmuxNext/Sources
exit=0   (no matches, on both commits)

On a scratch Swift file, the native rule matched all 9 intended cases, including the escaped one (the gate drops that one through ESCAPES). It did not match Palette.glassTint, withAlphaComponent(min(a, 1)), (materialView as? GlassPanelView)?.tintColor = look?.veil..., a translucent fill on an effect view, fill.layer?.backgroundColor = Palette.popupSurface (not a glass view), materialView?.layer?.backgroundColor = Palette.popupSurface (the .opaque path), isOpaque in a plain NSView subclass, or .glassEffect().background(.ultraThinMaterial).

Changelog

  • Fixed: The agent pane's session sidebar, opened over a narrow chat, is frosted glass again instead of an opaque panel.

Observed / Not run

  • Observed: bun scripts/check-glass-never-opaque.ts red on commit 1 and green on commit 2 (above). The fixture cases match the test's expected list, checked by running the same fixture through the script. The ast-grep scan of the real sources and of the scratch file is as described above. python3 scripts/cmux-next/prepush-gate.py: "no new violations". scripts/web-lint.sh: passed.
  • Not run: bun test test/glass-never-opaque.test.ts locally (this host's guard refuses bun test), so CI's "Test webviews" step is its first run. No Swift build or test, since no Swift changed.

No capture: the only visible change is one CSS declaration in a webview (the narrow pane's open session sidebar fill goes from opaque --acpmux-base to the shared 92% --surface-text-min mix under its existing blur, and back to solid under Reduce Transparency). No gallery stage renders that open-sidebar state, and the Swift rule changes no app code.

Agent session: cosmic-gray

🤖 Generated with Claude Code


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need.


Summary by cubic

Enforces the standing rule that glass is never opaque, natively and in webviews, and fixes the one violation the new guard finds.

Old behavior: the agent pane's open session sidebar blurred the transcript underneath an opaque base fill, so the blur never showed. New behavior: the fill is a 92% translucent color-mix, so the backdrop shows through the blur; Reduce Transparency still makes it solid.

The guard has two sides, both wired into CI:

  • Native: an ast-grep rule (no-opaque-glass) in the pre-push gate and the cmux-next checks job flags opaque tints/fills or isOpaque on glass views, and opaque .background next to .glassEffect. A reviewed escape is // glass-opaque-allow: <why>.
  • Web: check-glass-never-opaque.ts scans every CSS file under webviews/src and flags an opaque fill on a blurred or glass-named surface, or an opaque --*glass* token, outside Reduce Transparency contexts. A fixture test ensures the scan can't pass vacuously. Escapes are /* glass-opaque-allow: <why> */.

Reduce Transparency paths are exempt on both sides since that's the one place glass is allowed to go solid.

Written for commit c3ac1f8. Summary will update on new commits.

View guided diff Turn on auto-fix

teamleaderleo and others added 2 commits October 21, 2026 04:53
A guard for the standing rule (Leo 2026-10-20: "we want a lot of glass...
I hate opaque"). Native: the ast-grep rule no-opaque-glass (prepush gate and
the cmux-next checks job) flags an opaque tint or fill on a glass or visual
effect view, isOpaque in a glass subclass, and an opaque background next to
.glassEffect; `// glass-opaque-allow: <why>` is the reviewed escape. Web:
webviews/test/glass-never-opaque.test.ts (scripts/check-glass-never-opaque.ts)
flags a blurred surface, glass class or glass token whose fill resolves
opaque outside Reduce Transparency.

It fails on base: the open acpmux sidebar blurs under the opaque base color.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15bf1-fdc6-7623-8ee3-fa94b3900ccd&host=cosmic-gray
The narrow pane's open session sidebar blurred the transcript under the
opaque base color, so the blur never showed. It now takes the base at the
text floor (--surface-text-min, 92%) under the same blur; Reduce
Transparency makes that 100% and the blur none (desktop.css tokens).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15bf1-fdc6-7623-8ee3-fa94b3900ccd&host=cosmic-gray
@teamleaderleo teamleaderleo added the risk:normal Risk tier (docs/ci/risk-tiers.md) label Oct 21, 2026
@cursor

cursor Bot commented Oct 21, 2026

Copy link
Copy Markdown

Bugbot needs on-demand usage enabled

Bugbot uses usage-based billing for this team and requires on-demand usage to be enabled.

A team admin can enable on-demand usage in the Cursor dashboard.

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Owned by palette-audit on cosmic-gray · session

@github-actions

github-actions Bot commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

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

Review c3ac1f8: 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=pr23366 -f ref=cmux/glass-never-opaque -f platform=macos -f backend_mode=local

Gallery before/after for c3ac1f8: 16 states rendered, 4 images differ, 732 more touched states not rendered. Images are in the run's artifact, not on this public PR.

gh run download 39595495814 -R manaflow-ai/cmux -n gallery-advisory-23366-c3ac1f8f5eeee68ca8baf04372e2fd92a8c064de (then read gallery-review.json)

States
State Theme Status Diff Picked by
agent-pane.add-project-panel/environment Apple System Colors Light unchanged 0% own styles.css
agent-pane.add-project-panel/environment Apple System Colors unchanged 0% own styles.css
agent-pane.add-project-panel/sources Apple System Colors Light unchanged 0% own styles.css
agent-pane.add-project-panel/sources Apple System Colors unchanged 0% own styles.css
agent-pane.add-project-panel/directory Apple System Colors Light unchanged 0% own styles.css
agent-pane.add-project-panel/directory Apple System Colors unchanged 0% own styles.css
agent-pane.add-project-panel/keyboard Apple System Colors Light unchanged 0% own styles.css
agent-pane.add-project-panel/keyboard Apple System Colors unchanged 0% own styles.css
agent-pane.changes-file-menu/closed Apple System Colors Light unchanged 0% own styles.css
agent-pane.changes-file-menu/closed Apple System Colors unchanged 0% own styles.css
agent-pane.changes-file-menu/open Apple System Colors Light unchanged 0% own styles.css
agent-pane.changes-file-menu/open Apple System Colors unchanged 0% own styles.css
agent-pane.changes-file-menu/keyboard Apple System Colors Light unchanged 0% own styles.css
agent-pane.changes-file-menu/keyboard Apple System Colors unchanged 0% own styles.css
agent-pane.changes-git-actions/toolbar Apple System Colors Light unchanged 0% own styles.css
agent-pane.changes-git-actions/toolbar Apple System Colors unchanged 0% own styles.css
agent-pane.changes-git-actions/commit-form Apple System Colors Light unchanged 0% own styles.css
agent-pane.changes-git-actions/commit-form Apple System Colors unchanged 0% own styles.css
agent-pane.changes-git-actions/include-new Apple System Colors Light unchanged 0% own styles.css
agent-pane.changes-git-actions/include-new Apple System Colors unchanged 0% own styles.css
agent-pane.changes-git-actions/keyboard Apple System Colors Light unchanged 0% own styles.css
agent-pane.changes-git-actions/keyboard Apple System Colors unchanged 0% own styles.css
agent-pane.changes-git-actions/busy Apple System Colors Light unchanged 0% own styles.css
agent-pane.changes-git-actions/busy Apple System Colors unchanged 0% own styles.css
agent-pane.changes-git-actions/push-refused Apple System Colors Light unchanged 0% own styles.css
agent-pane.changes-git-actions/push-refused Apple System Colors unchanged 0% own styles.css
agent-pane.changes-options-menu/closed Apple System Colors Light unchanged 0% own styles.css
agent-pane.changes-options-menu/closed Apple System Colors unchanged 0% own styles.css
agent-pane.changes-options-menu/open Apple System Colors Light changed 0% own styles.css
agent-pane.changes-options-menu/open Apple System Colors changed 0% own styles.css
agent-pane.changes-options-menu/keyboard Apple System Colors Light changed 0% own styles.css
agent-pane.changes-options-menu/keyboard Apple System Colors changed 0% own styles.css

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

red: cmux-next checks (god files, concurrency, crash safety, l10n); no finished base run on 76f7e42 to compare; do not merge until green; see lane-rules

@blacksmith-sh

blacksmith-sh Bot commented Oct 21, 2026

Copy link
Copy Markdown

Found 5 test failures on Blacksmith runners:

Failures

Test View Logs
/tmp/tmp85ty234x/summary-fail.json (live):/summary-fail.json (live): View Logs
/tmp/tmpjkzs5r4j/summary-missing.json (live):/summary-missing.json (live): View Logs
test_a_pull_request_that_changes_the_shortcut_inputs_still_rewrites_them (main.Sett
ingsOnlyArtifactLeavesTheActionFollowers.test_a_pull_request_that_changes_the_shortcut_
inputs_still_rewrites_them) (job='autofix')/
test_a_pull_request_that_changes_the_shortcut_inputs_still_rewrites_them (main.Sett
ingsOnlyArtifactLeavesTheActionFollowers.test_a_pull_request_that_changes_the_shortcut_
inputs_still_rewrites_them) (job='autofix')
View Logs
test_regenerated_action_exports_bring_the_followers (main.SettingsOnlyArtifactLeave
sTheActionFollowers.test_regenerated_action_exports_bring_the_followers) (job='autofix'
)/
test_regenerated_action_exports_bring_the_followers (main.SettingsOnlyArtifactLeave
sTheActionFollowers.test_regenerated_action_exports_bring_the_followers) (job='autofix'
)
View Logs
test_settings_exports_alone (main.SettingsOnlyArtifactLeavesTheActionFollowers.test
_settings_exports_alone) (job='autofix')/
test_settings_exports_alone (main.SettingsOnlyArtifactLeavesTheActionFollowers.test
_settings_exports_alone) (job='autofix')
View Logs

Fix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need.

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Bead cx-uvr3l created for this PR by the cmux coordinator.

@teamleaderleo
teamleaderleo merged commit 0d7d9cb into feat-cmux-next Oct 21, 2026
@teamleaderleo
teamleaderleo deleted the cmux/glass-never-opaque branch October 21, 2026 12:04
teamleaderleo added a commit that referenced this pull request Oct 21, 2026
…heck

--glass-surface is what --glass-tint mixes from at 40-60%, never a fill;
it says so for webviews/scripts/check-glass-never-opaque.ts (#23366).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15c40-f08c-79b2-95af-689409622600&host=cmux16
@github-actions

github-actions Bot commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

teamleaderleo added a commit that referenced this pull request Oct 21, 2026
* plans(cmux-next): liquid glass lens design

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

* feat(cmux-next): liquid glass lens primitive and Glass setting

One shared glass surface for every web page and the agent pane:
webviews/src/ui/glass/ adds the .ui-glass class, its tokens
(--glass-tint, --glass-blur, --glass-frost, --glass-refraction,
--glass-rim, --glass-dispersion) and a WebGL lens that bends the
host's wallpaper still at each glass rim. WKWebView can't refract a
backdrop, so the host sends the still through cmuxTheme.backdrop.

Settings > Appearance > Glass: Lens (default), Plain Glass (the blur
glass from before) and Spectrum (lens plus a chromatic rim). Reduce
Transparency and Low Power Mode fall back to Plain.

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

* fix(cmux-next glass): review fixes for the lens and backdrop feed

- A context-lost event from a canvas stop() dropped no longer turns
  off the lens that started after it.
- The page decodes the wallpaper still only once glass is on screen.
- The backdrop blur is sent in CSS px (divided by the page zoom).
- Localizable.xcstrings keeps base's order; only the five Glass keys
  are added.

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

* fix(cmux-next glass): lens stays inert in a DOM without observers

A unit test's light DOM has no MutationObserver, and every page that
loads the desktop layer crashed there (whats-new-by-area and others).
The lens now leaves such a document to CSS glass. Linux WebKit's
headless compositor leaves WebGL out of screenshots, so there the lens
test checks the lens's state instead of pixels.

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

* chore(next): PR autofix (settings exports for appearance.glass)

Applied from the cmux-next PR autofix artifact of run 39555592062
(its push job was skipped).

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

* chore(next): generated settings exports follow the base

GitHub can't run the cmux-generated-v1 merge driver, so every base
regeneration of these exports marked #22815 conflicting. The base
autofix regenerates them for appearance.glass after the merge.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15c40-f08c-79b2-95af-689409622600&host=cmux16

* fix(cmux-next glass): the tint's mix source passes the never-opaque check

--glass-surface is what --glass-tint mixes from at 40-60%, never a fill;
it says so for webviews/scripts/check-glass-never-opaque.ts (#23366).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15c40-f08c-79b2-95af-689409622600&host=cmux16

* test(cmux-next glass): no void operator in the Linux WebKit skip

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15c40-f08c-79b2-95af-689409622600&host=cmux16

* fix(cmux-next glass): WebGL1 lens reads an explicit mip level where it can

texture2D(tex, uv, x) in a WebGL1 fragment shader takes x as a bias over
the automatic level, not a level. With EXT_shader_texture_lod the lens
now uses texture2DLodEXT; plain WebGL1 keeps the biased read. A browser
test compiles and links every dialect (webgl2, webgl1-lod, webgl1) in
Chromium and WebKit. Raised by a cross-family review relayed by
gallery-perf.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15c40-f08c-79b2-95af-689409622600&host=cmux16

* fix(cmux-next glass): the lens engine loads after the page, out of its eager budget

The editor page's eager JS went to 507,735 bytes against its 500,000 budget
with lens.ts imported statically. desktop.ts now installs only the backdrop
fallback (so an early host still is kept) and imports the engine lazily;
the editor page is back to 491,770 bytes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15c40-f08c-79b2-95af-689409622600&host=cmux16

* chore(next): settings exports regenerated for the Glass setting

Written by scripts/measure/export-settings-artifacts.sh on the fleet
(cmux-ci step 113430d28f44b66f1766cc2f, aws-m4pro-7, at 9e6fe02), as
defaults_guard.py check-stamp asks; the PR autofix could not regenerate
them (base test-compile red, fixed by #23436, then a GitHub rate limit
and a runner setup failure). The defaults snapshot stays the bot's.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15c40-f08c-79b2-95af-689409622600&host=cmux16

* chore(next): settings exports regenerated for the Glass setting after the base merge

Written by scripts/measure/export-settings-artifacts.sh on the fleet
(cmux-ci step e00798fd080a9afce64acaee, aws-m4pro-2, at 5159222).
check-stamp passes; the defaults snapshot stays the bot's.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15c40-f08c-79b2-95af-689409622600&host=cmux16

* chore(next): settings exports regenerated for the Glass setting after the base merge

Written by scripts/measure/export-settings-artifacts.sh on the fleet
(cmux-ci step 488cb6a08483a6ed97777436, aws-m4pro-6, at 89078c9).
check-stamp passes; the defaults snapshot stays the bot's.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15c40-f08c-79b2-95af-689409622600&host=cmux16

* cmux-next glass: the lens is an opt-in toggle; Plain Glass stays the default

Leo 2026-10-21: "the lens thing we just need to see and feel... we can put
it as a toggle and later promote to default". appearance.glass now
defaults to plain, the glass from before the lens, so nobody's look
changes. Lens and Spectrum stay in Settings > Appearance > Glass, and the
palette's Toggle Liquid Glass Lens (appearance.glass.lens.toggle, CLI
`settings toggle-glass-lens`) flips Plain and Lens live and writes the
setting. Pages draw Plain before the host sends its mode.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15c40-f08c-79b2-95af-689409622600&host=cmux16

* feat(next): Liquid Glass lens is a Debug toggle, off by default

Leo 2026-10-21: the lens is something to see and feel before it is the
default. It moves out of the settings schema: the Debug Settings choice
`glass.lens` (Glass and Overlays > Liquid Glass; DEV and NIGHTLY) picks
Plain Glass (the default), Lens or Spectrum, and Toggle Liquid Glass Lens
in the palette or the Debug menu flips it live. Release never activates
Debug Settings, so today's glass is unchanged. The Settings > Appearance >
Glass row and its exports are gone until the lens is promoted.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15c40-f08c-79b2-95af-689409622600&host=cmux16

* chore(next): action surfaces regenerated for the Debug Liquid Glass toggle

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15c40-f08c-79b2-95af-689409622600&host=cmux16

* chore(next): action surfaces regenerated after the base merge

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15c40-f08c-79b2-95af-689409622600&host=cmux16

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
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