Skip to content

Fix main shortcut routing CI regressions - #4445

Merged
austinywang merged 13 commits into
mainfrom
fix-main-shortcut-routing-ci-regressions
May 20, 2026
Merged

austinywang merged 13 commits into
mainfrom
fix-main-shortcut-routing-ci-regressions

Conversation

@austinywang

@austinywang austinywang commented May 20, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • Restore app shortcut chord prefix arming for file-backed and remapped built-in shortcuts before the normal key fast path.
  • Tighten the browser-popup close-tab test fixture so it has the main-window context used at runtime and closes its probe window.

Testing

  • Not run locally per repo/user instruction; GitHub Actions is the verification source for this fix.
  • git diff --check passed.

Demo Video

  • Video URL or attachment: N/A, CI-only shortcut routing fix.

Review Trigger (Copy/Paste as PR comment)

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

Checklist

  • Local testing intentionally not run; repo/user instruction requires CI-only verification for this task
  • I added or updated tests for behavior changes
  • I updated docs/changelog if needed (N/A)
  • I requested bot reviews after my latest commit (automatic PR reviewers are running or complete)
  • All code review bot comments are resolved
  • All human review comments are resolved

Note

Medium Risk
Changes affect app-level keyboard shortcut routing (including chord prefix handling) and window focus/timing behavior; regressions could swallow keystrokes or mis-route shortcuts. Updates are localized but touch core event handling and add timing-sensitive fixes for fullscreen/window behaviors.

Overview
Fixes shortcut-routing regressions by reworking chord prefix arming in AppDelegate: chord-enabled actions are now computed on-demand per event (and filtered by focus context) instead of cached, and arming happens before the “plain key” fast-path so file-backed/remapped chord prefixes aren’t missed.

Improves find and sidebar shortcut behavior by making TabManager.startSearch() return a Bool (used by performFindShortcutInActiveMainWindow) and deferring right-sidebar toggling via DispatchQueue.main.async to avoid unwanted AppKit animation contexts.

Tightens shortcut parsing around whitespace: single-space still maps to the space key, but other whitespace-only tokens now resolve to unbound/invalid as appropriate; settings-file normalization also preserves invalid showHideAllWindows values so managed configs remain visible. Updates window/accessory handling to avoid races (clearing fullscreen tiling opt-out more robustly; guarding NSWindow attachment tasks), and hardens CI tests with explicit window focusing, polling-based waits, and more accurate split equalization expectations.

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

Summary by CodeRabbit

  • Refactor

    • Improved keyboard shortcut routing: chord handling now computes eligible actions on demand, arms chords immediately when appropriate, and avoids persisting stale configured-chord state for more deterministic behavior.
  • Tests

    • Hardened shortcut and window-management tests: explicit test-state resets, ensured window focusing, added a polling wait helper, and more robust split-equalization checks to reduce flakes.

Review Change Stack

@vercel

vercel Bot commented May 20, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
cmux Ready Ready Preview, Comment May 20, 2026 8:42pm
cmux-staging Building Building Preview, Comment May 20, 2026 8:42pm

@coderabbitai

coderabbitai Bot commented May 20, 2026 •

Copy link
Copy Markdown

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

AppDelegate computes chord-eligible configured actions on demand, arms configured shortcut chords earlier when no active chord prefix exists, and tests were made deterministic (window key/front, polling waits) and updated to assert computed equalize divider positions.

Changes

Shortcut Chord Routing

Layer / File(s) Summary
Remove cached chord list & compute on demand
Sources/AppDelegate.swift
Deletes stored configuredShortcutChordActions, removes its initial refresh during observer setup, changes defaults handling to clear chord arm state and compute eligible actions at call sites, introduces currentConfiguredShortcutChordActions(), and refactors armConfiguredShortcutChordIfNeeded to accept explicit actions.
Early chord-arming in handleCustomShortcut
Sources/AppDelegate.swift
When no active chord prefix is set, the handler derives the event shortcut focus context, filters chord-capable configured actions by availability for that context, calls the arming helper (cmux path limited to provided shortcuts), and consumes the event if arming succeeds.
Test determinism, polling helper, and equalize expectations
cmuxTests/AppDelegateShortcutRoutingTests.swift, cmuxTests/AppDelegateEqualizeSplitsShortcutTests.swift
Adds a DEBUG-only routing-state reset after isolating keyboard-settings in a chord dispatch test; stabilizes window key/front and probe-window lifecycle; replaces fragile RunLoop spins with waitUntil(timeout:condition:); and computes expected equalized divider positions from the split tree for assertions.

Sequence Diagram

sequenceDiagram
  participant KeyboardEvent
  participant AppDelegate
  participant currentConfiguredShortcutChordActions
  participant armConfiguredShortcutChordIfNeeded

  KeyboardEvent->>AppDelegate: key event arrives
  AppDelegate->>currentConfiguredShortcutChordActions: compute eligible chord actions (filter by focus context)
  AppDelegate->>armConfiguredShortcutChordIfNeeded: attempt to arm chord (actions or provided list)
  armConfiguredShortcutChordIfNeeded-->>AppDelegate: success / failure
  AppDelegate-->>KeyboardEvent: consume event if armed
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • manaflow-ai/cmux#4400: Related equalize-splits expectations changes that compute divider positions from leaf-count ratios in the split tree.
  • manaflow-ai/cmux#4442: Touches AppDelegate shortcut-routing test/debug reset state and the same debug reset hook.
  • manaflow-ai/cmux#4268: Overlapping changes to AppDelegate shortcut routing and event consumption decision points.

Poem

🐰 I hop through keys and arm a sweet accord,

I count the leaves where splitters are stored,
I nudge windows forward and wait till they're true,
Tests hum in order, shortcuts find their cue,
A rabbit cheers — the chords spring anew.


Caution

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

  • Ignore

❌ Failed checks (1 error, 1 warning)

Check name Status Explanation Resolution
Cmux Swift Logging ❌ Error Added three NSLog statements in production code without #if DEBUG guards: auth.callback error, Command send timeout, and LaunchServices registration failure. Guard NSLog calls with #if DEBUG or use Logger/cmux debug log per swift-logging.md rules.
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 (15 passed)
Check name Status Explanation
Title check ✅ Passed The title directly summarizes the main change: fixing shortcut routing CI regressions. It accurately reflects the primary objective stated in the PR objectives and the core changes in the changeset.
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 Production code changes within @MainActor AppDelegate; test classes properly marked; no implicit MainActor models or unsynchronized Sendables found.
Cmux Swift Blocking Runtime ✅ Passed Production code eliminates cached chord actions and polling refresh. Test code uses deterministic test-only waitUntil polling, explicitly allowed by review rules.
Cmux No Hacky Sleeps ✅ Passed PR modifies only Swift files (AppDelegate.swift and test files). The check applies to TypeScript/JavaScript/shell scripts; Swift is covered separately. Test waitUntil helpers are allowed.
Cmux Swift Concurrency ✅ Passed No legacy async patterns introduced or expanded. PR refactors away from cached state toward on-demand computation and explicit parameter passing, aligning with modernization goals.
Cmux Swift @Concurrent ✅ Passed All Swift code changes are synchronous functions with no async/await or @concurrent violations; functions operate within @MainActor context appropriately.
Cmux Swift File And Package Boundaries ✅ Passed AppDelegate bug fix adds 7 net lines to existing shortcut routing logic. AppDelegate is inherently app-target code per rules. Test changes are test fixtures. No new mixed responsibilities.
Cmux User-Facing Error Privacy ✅ Passed Changes are internal shortcut routing refactoring with no new user-facing errors, alerts, vendor names, credentials, or sensitive data exposure. Test changes are developer-only.
Cmux Full Internationalization ✅ Passed No new user-facing text added. Changes refactor shortcut chord routing logic and update tests only. No string catalogs modified, no web UI changes, no localization API violations.
Cmux Swiftui State Layout ✅ Passed PR modifies AppKit shortcut routing code and tests only; no SwiftUI state/layout violations found. No new @Published/@StateObject or render-time state mutations.
Cmux Architecture Rethink ✅ Passed PR removes cached configuredShortcutChordActions and replaces with on-demand computation, improving state ownership. Test-only waitUntil polling for rendering/lifecycle sync is allowed per rules.
Cmux Swift Auxiliary Window Close Shortcuts ✅ Passed PR refactors shortcut routing and updates test fixtures only. No new user-visible windows added. Test fixtures allowed per rule; lint script passes.
Description check ✅ Passed The PR description follows the required template with all key sections present: Summary clearly states what changed and why, Testing explains verification approach, Demo Video section addresses N/A case, Review Trigger is included, and Checklist is complete with relevant items marked.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix-main-shortcut-routing-ci-regressions

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 and usage tips.

@greptile-apps

greptile-apps Bot commented May 20, 2026 •

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes app-level keyboard shortcut routing regressions by computing chord-eligible actions on demand (removing the stale configuredShortcutChordActions cache) and arming chord prefixes earlier — before the plain-key fast path — using the current focus context. It also refactors TabManager.startSearch() to return Bool, patches UpdateTitlebarAccessory weak-capture bugs, and tightens whitespace-key normalization in KeyboardShortcutSettings.

  • Chord arming: currentConfiguredShortcutChordActions() replaces the cached property; a new context-aware block arms chord prefixes immediately for file-backed and remapped built-in shortcuts, with the second call to armConfiguredShortcutChordIfNeeded now receiving an explicit empty actions: [] instead of the old catch-all default.
  • startSearch() return value: TabManager.startSearch() becomes @discardableResult -> Bool, letting performFindShortcutInActiveMainWindow avoid the now-removed isFindVisible side-read.
  • Test hardening: waitUntil polling helper, explicit window focus/cleanup, correct isReleasedWhenClosed = false on the browser-popup probe window, and per-split leaf-count divider-position expectations replace the hardcoded 0.5 assumption.

Confidence Score: 5/5

Safe to merge; the chord-routing refactor is well-scoped and the test suite is materially hardened.

The core shortcut-routing change — computing chord-eligible actions on demand with context filtering rather than relying on a stale cache — is correct and properly tested. The startSearch Bool refactor and UpdateTitlebarAccessory weak-capture fixes are clean. The one non-ideal pattern is the double-dispatch cleanup of fullScreenDisallowsTiling, but it is isolated to the window-creation path and no worse than the previous single dispatch.

The fullScreenDisallowsTiling double-dispatch block in Sources/AppDelegate.swift around createMainWindow is worth a follow-up to identify the AppKit call that re-adds the flag.

Important Files Changed

Filename Overview
Sources/AppDelegate.swift Removes stale configuredShortcutChordActions cache and moves chord arming before the plain-key fast path with context-aware filtering; the new double-dispatch cleanup of .fullScreenDisallowsTiling is a timing repair without a principled signal.
Sources/KeyboardShortcutSettings.swift Tightens parseConfigKeyToken to match only literal space for the space key and fixes isUnboundConfigToken so multi-whitespace-only tokens correctly return .unbound.
Sources/TabManager.swift Adds @discardableResult and changes startSearch() to return Bool, allowing AppDelegate to use the result directly. Clean refactor.
Sources/Update/UpdateTitlebarAccessory.swift Adds weak window capture and early-exit guard to two Task { @MainActor } notification handlers, preventing use of a potentially deallocated window.
cmuxTests/AppDelegateShortcutRoutingTests.swift Hardens multiple test fixtures with explicit window focus/cleanup, waitUntil polling helper, and tighter browser-popup fixture with isReleasedWhenClosed = false.
cmuxTests/AppDelegateEqualizeSplitsShortcutTests.swift Replaces hardcoded 0.5 divider expectation with computed per-split leaf-count ratio.
cmuxTests/KeyboardShortcutSpaceKeyTests.swift Adds assertions for multi-space unbound, tab unbound, and cmd+shift+multi-space nil, exercising the fixed normalization edge cases.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[NSEvent received in local key handler] --> B{shouldBypassPlainKeyShortcutRouting?}
    B -- yes --> Z[return false]
    B -- no --> C{activeConfiguredShortcutChordPrefixForCurrentEvent == nil?}
    C -- yes --> D[shortcutEventFocusContext + currentConfiguredShortcutChordActions filtered by context]
    D --> E{armConfiguredShortcutChordIfNeeded with availableChordActions}
    E -- armed --> R1[return true]
    E -- not armed --> F[preferredMainWindowContextForShortcutRouting + configuredCmuxShortcutActions]
    C -- no --> F
    F --> G{armConfiguredShortcutChordIfNeeded with empty actions + shortcuts}
    G -- armed --> R2[return true]
    G -- not armed --> H[Match individual configured shortcuts]
    H --> R3[return true or false]
Loading

Reviews (12): Last reviewed commit: "fix: distinguish space shortcut from whi..." | Re-trigger Greptile

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

No issues found across 2 files

Re-trigger cubic

Comment thread Sources/AppDelegate.swift
@austinywang

Copy link
Copy Markdown
Contributor Author

Addressed Greptile's latent fallback note in 86fb05c by requiring explicit actions for chord arming; there is no longer a nil-default path that can bypass focus-context filtering.

@austinywang

Copy link
Copy Markdown
Contributor Author

Verified CodeRabbit's logging note: the three referenced NSLog call sites are already present on origin/main and are absent from this PR's diff, so there is no PR-introduced logging violation to patch here. Current CodeRabbit check is passing.

@austinywang

Copy link
Copy Markdown
Contributor Author

Addressed the CI failure from the previous head in 83f39a8. The tests log showed testOmnibarArrowSelectionSurvivesTransientWindowFirstResponder was racing AppDelegate's focused-address-bar state; the fixture now uses requestBrowserAddressBarFocus(panelId:) before simulating the transient window first responder.

@austinywang

Copy link
Copy Markdown
Contributor Author

Addressed the latest tests job failures in 19bfe4e. The live job log showed testCreateMainWindowTemporarilyDisallowsFullScreenTilingFromFullscreenSource and testFindShortcutFromTerminalOpensTerminalFind failing; the fullscreen cleanup now explicitly reassigns collectionBehavior after clearing the temporary flag, and the terminal-find fixture now gives the terminal actual first-responder focus and waits for async search-state creation.

@austinywang

Copy link
Copy Markdown
Contributor Author

Addressed the next tests log failures in 0fdb3bd. The live log showed testArrowNavigationRoutesWhileCommandPaletteOverlayIsInteractiveBeforeVisibilitySync and testCmdCtrlWClosesWindowAfterConfirmation failing; the palette overlay synthetic arrow event now uses the key-window path, and confirmed main-window close now closes the window directly after confirmation instead of re-entering performClose.

Comment thread Sources/AppDelegate.swift Outdated
@austinywang

Copy link
Copy Markdown
Contributor Author

Addressed the repeated tests job failures in 03ec877. The command-palette overlay fixture now mounts its synthetic overlay on the same root searched by the production overlay detector, and the confirmed Cmd+Ctrl+W test now waits/asserts on visible-window closure instead of immediate NSApp.windows deallocation.

@austinywang
austinywang merged commit 149f173 into main May 20, 2026
22 checks passed

This branch was successfully deployed

1 active deployment
Preview – cmux — cd9b82c3 Deployed May 20, 2026 by vercel[bot]
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.

1 participant