Skip to content

Fix browser popover appearance contrast - #9744

Merged
austinywang merged 5 commits into
mainfrom
issue-9341-downloads-popover-contrast
Aug 7, 2026
Merged

austinywang merged 5 commits into
mainfrom
issue-9341-downloads-popover-contrast

Conversation

@austinywang

@austinywang austinywang commented Aug 7, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • Resolve each browser toolbar popover's AppKit material and SwiftUI semantic foregrounds from the same browser-chrome color scheme.
  • Apply one shared presentation-boundary modifier to Downloads, profile, theme, and import-hint popovers so mixed light/dark appearance resolution cannot recur across sibling surfaces.
  • Add a focused debug-only behavioral probe and XCUITest that opens the real Downloads popover with a synthetic download under dark app / light browser chrome.

Issue: #9341

Closes #9341

Testing

Localization audit: no user-facing strings changed; the changed Swift surfaces were checked for newly introduced bare English, and no localization catalog changes are needed.

Warning audit: no warning-budget or file-length-budget file is changed.

Demo Video

  • Not recorded. The requested build/dogfood step is intentionally deferred until explicit user approval; the focused headless UI test validates the genuine SwiftUI/AppKit popover presentation boundary.

Review Trigger

Requested separately after the latest commit:

@coderabbitai review
@greptile-apps review
@cubic-dev-ai review

Checklist

  • I tested the change locally (intentionally deferred by task constraints)
  • I added or updated tests for behavior changes
  • I updated docs/changelog if needed (not needed for this scoped bug fix)
  • I requested bot reviews after my latest commit
  • All code review bot comments are resolved
  • All human review comments are resolved

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


Note

Low Risk
Scoped SwiftUI/AppKit appearance wiring and DEBUG-only test probes; no auth, data, or release-path behavior changes beyond popover styling.

Overview
Fixes mixed light/dark contrast in browser toolbar popovers when the app appearance and browser chrome disagree (e.g. dark app with light terminal-derived chrome).

A shared browserChromePopoverAppearance modifier applies preferredColorScheme to popover content so SwiftUI semantics and the AppKit _NSPopoverWindow material resolve from the same browser-chrome scheme. It is wired on the Downloads, profile, theme, and import-hint popovers; the downloads popover also reads the chrome scheme from its toolbar button.

DEBUG-only UI-test hooks auto-present the real downloads popover, inject a fixture download, and record contentColorScheme, windowAppearance, and window class via an NSView window accessor. A new headless XCUITest launches the binary directly and asserts both schemes stay light under dark app / light browser chrome.

Reviewed by Cursor Bugbot for commit 981d4d7. Bugbot is set up for automated code reviews on this repo. Configure here.


Summary by cubic

Fixes mixed light/dark contrast in browser toolbar popovers by resolving both SwiftUI content and the AppKit popover from the browser‑chrome color scheme. Applies to Downloads, profile, theme, and import‑hint popovers and adds a lifecycle‑driven UI test to prevent regressions. Fixes #9341.

  • Bug Fixes
    • Added a shared browserChromePopoverAppearance so popover material and semantic colors resolve from the browser‑chrome scheme.
    • Applied it to Downloads, profile, theme, and import‑hint popovers.
    • DEBUG-only probe now records the real _NSPopoverWindow and content scheme and refreshes on attach, effective-appearance changes, and SwiftUI updates.
    • Headless XCUITest auto-presents the Downloads popover (injects a fixture download) and asserts it stays light under a dark app appearance.

Written for commit 981d4d7. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • New Features

    • Browser downloads and related browser popovers now consistently follow the selected browser color scheme, even when the system appearance differs.
    • Downloads popovers provide improved visual consistency with the rest of the browser interface.
  • Bug Fixes

    • Resolved appearance mismatches that could cause browser popovers to display with incorrect light or dark styling.
    • Improved reliability when opening downloads and other browser toolbar popovers across mixed appearance settings.

@austinywang

Copy link
Copy Markdown
Contributor Author

@coderabbitai review
@greptile-apps review
@cubic-dev-ai review

@coderabbitai

coderabbitai Bot commented Aug 7, 2026 •

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Adds browser chrome popover color-scheme handling and debug-only downloads-popover appearance capture. Adds an end-to-end UI test that verifies light content and window appearance under dark AppKit appearance.

Changes

Downloads Popover Appearance

Layer / File(s) Summary
Popover appearance integration
Sources/Panels/BrowserChromePopoverAppearance.swift, Sources/Panels/BrowserDownloadsToolbarButton.swift, Sources/Panels/BrowserPanelView.swift
Adds browserChromePopoverAppearance(_:). Browser popovers use the resolved color scheme. Debug UI tests can use a fixture download when no recent downloads exist.
Debug presentation and capture
Sources/Debug/UITests/*, cmux.xcodeproj/project.pbxproj
Adds conditional popover presentation, window appearance recording, fixture support, and target wiring for the new sources.
Contrast UI validation
cmuxUITests/BrowserDownloadsPopoverContrastUITests.swift
Launches the debug app with isolated fixtures and appearance settings, polls JSON capture results, verifies light content and window appearance, and cleans up test processes and files.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant BrowserDownloadsPopoverContrastUITests
  participant DebugApp
  participant BrowserPanelView
  participant BrowserDownloadsToolbarButton
  participant BrowserDownloadsPopoverAppearanceUITestRecorder
  participant UITestCaptureSink
  BrowserDownloadsPopoverContrastUITests->>DebugApp: launch with dark AppKit and light browser settings
  DebugApp->>BrowserPanelView: provide fixture download
  BrowserPanelView->>BrowserDownloadsToolbarButton: render downloads popover
  BrowserDownloadsToolbarButton->>BrowserDownloadsPopoverAppearanceUITestRecorder: record popover window
  BrowserDownloadsPopoverAppearanceUITestRecorder->>UITestCaptureSink: write light window and content appearance
  BrowserDownloadsPopoverContrastUITests->>UITestCaptureSink: poll captured JSON results
Loading

Possibly related issues

  • manaflow-ai/cmux-dev-artifacts#9404 — Directly concerns the added downloads-popover contrast test and its support infrastructure.
  • manaflow-ai/cmux-dev-artifacts#9436 — Concerns light downloads-popover appearance under dark AppKit appearance.
  • manaflow-ai/cmux-dev-artifacts#9469 — Concerns execution of the added contrast test.
  • manaflow-ai/cmux-dev-artifacts#9291 — Concerns the added downloads-popover contrast test and appearance support.
  • manaflow-ai/cmux-dev-artifacts#9305 — Concerns the added contrast test and its project wiring.

Possibly related PRs

🚥 Pre-merge checks | ✅ 24 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (24 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Cmux Swift Actor Isolation ✅ Passed Changed production code adds SwiftUI views/modifiers only; DEBUG UI-test AppKit support is explicitly @MainActor, and no new Sendable, async protocol, or background UI access appears.
Cmux Swift Blocking Runtime ✅ Passed Production Swift additions contain no blocking or timing primitives; XCTWaiter/JSON polling is confined to the XCTest file, and DEBUG hooks use lifecycle callbacks without delays.
Cmux Browser Automation Off-Main ✅ Passed The PR changes popover appearance and a debug UI test only; it adds no browser socket command or changes to TerminalController, ControlCommandExecutionPolicy, or worker-routing tests.
Cmux Expensive Synchronous Load ✅ Passed Production additions only apply color-scheme modifiers and pass download snapshots; no agent-history loader, large-file parse, directory scan, or synchronous agent I/O was added. File I/O is test/d...
Cmux Cache Substitution Correctness ✅ Passed The diff does not replace a fresh read in persistence, history, undo, or snapshot code; it adds a DEBUG-only fixture for a transient popover and otherwise keeps panel.recentDownloads.
Cmux No Hacky Sleeps ✅ Passed The PR changes nine Swift files and one Xcode project file; no covered non-Swift runtime code changes. XCTest XCTWaiter usage is deterministic test scaffolding allowed by the rule.
Cmux Algorithmic Complexity ✅ Passed The cumulative diff adds no scalable scans, sorting, filtering, joins, or nested collection work in production paths; the only new collection loop is test-only scaffolding.
Cmux Swift Concurrency ✅ Passed The PR adds no DispatchQueue, Combine, Task, async/await, or completion-handler concurrency pattern; its callbacks are SwiftUI/AppKit lifecycle and XCTest predicate boundaries.
Cmux Swift @Concurrent ✅ Passed The PR adds no async or nonisolated functions, no @concurrent annotations, and no async call sites. New helpers are synchronous and intentionally @MainActor UI probes.
Cmux Swift Package Boundaries ✅ Passed The production diff adds a 14-line SwiftUI appearance modifier and wires it into browser popovers; remaining additions are UI/AppKit glue or #if DEBUG fixtures/tests, all allowed by the boundary rule.
Cmux Swiftpm Lockfiles ✅ Passed The PR changes only Xcode source/test wiring; no SwiftPM package reference, manifest, .gitignore, or Package.resolved changes exist, and the root Xcode lockfile is unchanged.
Cmux Swift Logging ✅ Passed Runtime Swift hunks add no print/debugPrint/dump/NSLog, Logger, or diagnostics; file and stdout capture occur only in #if DEBUG UI-test support or XCTest harness, which the rule allows.
Cmux User-Facing Error Privacy ✅ Passed Production diff adds popover color-scheme wiring only; no new user-facing errors, alerts, output, or recovery text. Diagnostic paths and environment names are confined to DEBUG/test code.
Cmux Full Internationalization ✅ Passed Production additions only wire appearance and a DEBUG fixture; no new user-facing copy or localization keys were added. All new probe/XCUITest text is test/debug-only, and no catalogs or web locale...
Cmux Swiftui State Layout ✅ Passed No prohibited state or layout pattern is added. Existing @State/LazyVStack rows remain value snapshots with closures; the only new state write runs from onAppear/onChange, and window reporting is a...
Cmux Architecture Rethink ✅ Passed The change keeps popover state in the existing binding and uses one shared appearance source; the DEBUG-only AppKit callbacks are documented bridge code with no timing repair path.
Cmux Swift Auxiliary Window Close Shortcuts ✅ Passed The PR adds only browser popover styling and DEBUG/test-only NSView window observation; no standalone window creation or identifier assignment was added, and the auxiliary-window lint passed.
Cmux Source Artifacts ✅ Passed All 10 changed paths are regular Swift, Xcode project, or UI-test files. No artifact directories or generated files enter the diff; runtime temp/log paths belong to the deliberate test system.
Cmux No Test Or Debug Seam In Production Source ✅ Passed The test-only probe is isolated in five Sources/Debug/UITests files under #if DEBUG; production diffs add no widened visibility or debug/test accessor.
Cmux No Ambient Global State ✅ Passed The diff adds a View extension method and constructable DEBUG support with private static constants and instance state; it adds no new file-scope function, mutable global, static namespace, or sing...
Title check ✅ Passed The title clearly summarizes the main change: fixing contrast in browser popovers.
Description check ✅ Passed The description explains the change, motivation, testing, issue linkage, demo status, and checklist with sufficient detail.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch issue-9341-downloads-popover-contrast

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@cubic-dev-ai

cubic-dev-ai Bot commented Aug 7, 2026

Copy link
Copy Markdown

@coderabbitai review
@greptile-apps review
@cubic-dev-ai review

@austinywang I can't start this review because your workspace has reached its free monthly review limit. cubic has reviewed 245,275 of the 240,000 allowed lines of code this month. Reviews resume on 1 September 2026 (in 25 days). Paid plans include much higher monthly review limits. Upgrade now to resume reviews.

To help optimise your usage, you can tune cubic to get the most out of your usage limits:

Learn more →

@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown

Rate Limit Exceeded

@austinywang have exceeded the limit for the number of chat messages per hour. Please wait 4 minutes and 8 seconds before sending another message.

Comment thread Sources/Panels/BrowserDownloadsToolbarButton.swift Outdated
@austinywang

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown

Rate Limit Exceeded

@austinywang have exceeded the limit for the number of chat messages per hour. Please wait 0 minutes and 52 seconds before sending another message.

@austinywang

Copy link
Copy Markdown
Contributor Author

Review refresh after 2c7bc82:

@coderabbitai review
@greptile-apps review
@cubic-dev-ai review

@coderabbitai

coderabbitai Bot commented Aug 7, 2026 •

Copy link
Copy Markdown

@austinywang, I will review the changes after 2c7bc82428.

⚠️ Action not completed

Already reviewed.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@cubic-dev-ai

cubic-dev-ai Bot commented Aug 7, 2026

Copy link
Copy Markdown

Review refresh after 2c7bc82:

@coderabbitai review
@greptile-apps review
@cubic-dev-ai review

@austinywang I can't start this review because your workspace has reached its free monthly review limit. cubic has reviewed 245,275 of the 240,000 allowed lines of code this month. Reviews resume on 1 September 2026 (in 25 days). Paid plans include much higher monthly review limits. Upgrade now to resume reviews.

To help optimise your usage, you can tune cubic to get the most out of your usage limits:

Learn more →

@coderabbitai coderabbitai 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.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@cmuxUITests/BrowserDownloadsPopoverContrastUITests.swift`:
- Around line 191-204: The terminateAppProcess method must confirm that the app
exits after process.interrupt() before allowing teardown to continue. Add a
deadline-bounded wait using the process’s actual termination state or equivalent
completion signal, and fail test cleanup if the process remains running when the
bound expires.
- Around line 81-83: Update the wait predicate in the appearance probe test to
require the expected light values for both contentColorScheme and
windowAppearance, rather than only checking that the fields exist. Use the
two-write contract in BrowserDownloadsPopoverAppearanceUITestSupport to ensure
the wait completes on the final snapshot before assertions run.

In `@Sources/Debug/UITests/BrowserDownloadsPopoverAppearanceUITestSupport.swift`:
- Around line 42-48: Remove the Task.yield-based second write from
record(window:contentColorScheme:), leaving a single snapshot capture. Update
WindowAccessor so it invokes the capture only after the popover window has
attached and resolved its appearance, without relying on a later scheduler turn.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 5455426d-6f53-4441-93f5-43123a1a7216

📥 Commits

Reviewing files that changed from the base of the PR and between f4263ae and 2c7bc82.

📒 Files selected for processing (8)
  • Sources/Debug/UITests/BrowserDownloadsPopoverAppearanceUITestPresenter.swift
  • Sources/Debug/UITests/BrowserDownloadsPopoverAppearanceUITestRecorder.swift
  • Sources/Debug/UITests/BrowserDownloadsPopoverAppearanceUITestSupport.swift
  • Sources/Panels/BrowserChromePopoverAppearance.swift
  • Sources/Panels/BrowserDownloadsToolbarButton.swift
  • Sources/Panels/BrowserPanelView.swift
  • cmux.xcodeproj/project.pbxproj
  • cmuxUITests/BrowserDownloadsPopoverContrastUITests.swift

Comment thread cmuxUITests/BrowserDownloadsPopoverContrastUITests.swift
Comment thread cmuxUITests/BrowserDownloadsPopoverContrastUITests.swift
Comment thread Sources/Debug/UITests/BrowserDownloadsPopoverAppearanceUITestSupport.swift Outdated
@austinywang

Copy link
Copy Markdown
Contributor Author

Review refresh after 6239b29:

@coderabbitai review
@greptile-apps review
@cubic-dev-ai review

@cubic-dev-ai

cubic-dev-ai Bot commented Aug 7, 2026

Copy link
Copy Markdown

Review refresh after 6239b29:

@coderabbitai review
@greptile-apps review
@cubic-dev-ai review

@austinywang I can't start this review because your workspace has reached its free monthly review limit. cubic has reviewed 245,275 of the 240,000 allowed lines of code this month. Reviews resume on 1 September 2026 (in 25 days). Paid plans include much higher monthly review limits. Upgrade now to resume reviews.

To help optimise your usage, you can tune cubic to get the most out of your usage limits:

Learn more →

@coderabbitai

coderabbitai Bot commented Aug 7, 2026 •

Copy link
Copy Markdown

@austinywang, I will review the changes after 6239b29a98.

⚠️ Action not completed

Already reviewed.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@cursor cursor 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.

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 6239b29. Configure here.

@austinywang

Copy link
Copy Markdown
Contributor Author

Review refresh after 981d4d7:

@coderabbitai review
@greptile-apps review
@cubic-dev-ai review

@coderabbitai

coderabbitai Bot commented Aug 7, 2026 •

Copy link
Copy Markdown

@austinywang I will review the changes after 981d4d7816.

⚠️ Action not completed

Review rate limited.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@cubic-dev-ai

cubic-dev-ai Bot commented Aug 7, 2026

Copy link
Copy Markdown

Review refresh after 981d4d7:

@coderabbitai review
@greptile-apps review
@cubic-dev-ai review

@austinywang I can't start this review because your workspace has reached its free monthly review limit. cubic has reviewed 245,275 of the 240,000 allowed lines of code this month. Reviews resume on 1 September 2026 (in 25 days). Paid plans include much higher monthly review limits. Upgrade now to resume reviews.

To help optimise your usage, you can tune cubic to get the most out of your usage limits:

Learn more →

@austinywang

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 7, 2026 •

Copy link
Copy Markdown
⚠️ Action not completed

Review rate limited.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@austinywang

austinywang commented Aug 7, 2026 •

Copy link
Copy Markdown
Contributor Author

Review disposition for non-inline bot output:

  • CodeRabbit's "No Test or Debug Seam" pre-merge error is a false positive under the repository rule's explicit pass case. This is unavoidable cross-process app-host instrumentation: XCUITest launches a separate process, so @testable import cannot present or inspect its real NSPopover. The facility is #if DEBUG, isolated under Sources/Debug/UITests, exposes no private production state, and the two panel files contain only the minimum integration call sites. This is also the exact location prescribed by the resolved Cursor finding.
  • The docstring item is an optional internal-code warning, not a missing public API contract. Every new major debug-support type has a purpose comment; its small private/internal lifecycle helpers are self-describing.
  • cubic-dev-ai was requested on the latest HEAD but reported its workspace monthly quota and produced no code finding. That service response is acknowledged; there is no PR-side action available.

All actionable inline CodeRabbit and Cursor threads are fixed, answered, and resolved.

@austinywang

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 7, 2026 •

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@austinywang
austinywang merged commit fecf416 into main Aug 7, 2026
9 checks passed
@austinywang
austinywang deleted the issue-9341-downloads-popover-contrast branch August 7, 2026 04:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Browser Downloads popover sometimes renders dark-on-dark: labels and icons unreadable against the translucent panel

1 participant