Skip to content

test(focus-recovery): start the hidden/tiny reveal from a hidden panel - #14060

Merged
teamleaderleo merged 2 commits into
mainfrom
fix/hidden-tiny-reveal-fixture
Sep 24, 2026
Merged

teamleaderleo merged 2 commits into
mainfrom
fix/hidden-tiny-reveal-fixture

Conversation

@austinywang

@austinywang austinywang commented Sep 23, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Two focus-recovery tests fail on main, and the cause is their fixtures. On main's full-suite run 35903570794:

  • WorkspaceTerminalFocusRecoverySwiftTests/automaticApplyDoesNotBypassHiddenTinyFirstResponderDeferral() fails at lines 325, 326 and 338.
  • WorkspaceTerminalFocusRecoverySwiftTests/findTerminalRestorePreservesHiddenTinyFirstResponderDeferral() fails at lines 413 and 425.

Both tests hide and shrink the terminal, then call setVisibleInUI(true) and expect the automatic first-responder apply to put focus back on the terminal while Ghostty focus stays deferred. GhosttySurfaceScrollView.setVisibleInUI schedules that apply only on a hidden-to-visible transition. In CI the first responder was still the window after the reveal, which is what a reveal of an already-visible panel produces. I did not isolate which setup step leaves the panel visible. Both tests now hide the panel right before the reveal, and #require that it is hidden before the reveal and visible after it. A setup change that makes the reveal a no-op again now fails at that #require.

The find test had a second problem: the find overlay's own focus handling was still active. Mounting the overlay forces focus into its search field, and the overlay's focus binding stays set until the field ends editing. The test now waits for the field to mount, re-applies the overlay state to cancel the mount's forced focus retries, and lets the field take focus and resign it. It then sets the panel's focus intent to the terminal, which is the restore the test is named for.

Both first-responder expectations now print the actual first responder when they fail. No product code changes and no assertion is relaxed.

This covers two of the five tests that #14006 lists as not covered. Of the other three, #13968 (merged) fixed the key-down recovery test, #14049 fixes the split feedback test, and #14058 fixes the minimal-mode test. Refs #13879.

Testing

Nothing was built or run locally. Hosted runs:

Run OS Commit Result
test-depot 35824468117 macOS 15 e4b1c9c Both tests passed; the suite passed 7 of 7.
E2E 35832271355 macOS 26 8db5473 (this commit plus DEBUG focus tracing) Both tests passed.
E2E 35936170934 macOS 26 45c2695 (this PR merged with main 1ba90a1) queued

The E2E workflow ends red on every run. Its cleanup step exits 1 after the tests with "refusing to inspect app hosts outside runner temp". The results above come from the test log.

Localization audit: no user-facing strings changed.

Checklist

  • I tested the change locally (hosted runs only, above)
  • I added or updated tests for behavior changes
  • For iOS connectivity, auth, lifecycle, workspace or terminal changes, I updated the deterministic soak coverage or explained why existing coverage still applies, and recorded the affected workload result (n/a: macOS test fixtures only)
  • I updated docs/changelog if needed (none needed)
  • I requested bot reviews after my latest commit (copy/paste block above or equivalent)
  • All code review bot comments are resolved
  • All human review comments are resolved

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Tests
    • Expanded coverage for terminal focus recovery when restoring hidden, compact workspaces and when using the find overlay.

Current results (merged with main at 804e16d)

  • blacksmith-6vcpu-macos-15, run 36034869227: all 7 WorkspaceTerminalFocusRecoverySwiftTests pass, including both tests this PR fixes.
  • blacksmith-6vcpu-macos-26, run 36034924205: findTerminalRestorePreservesHiddenTinyFirstResponderDeferral passes. automaticApplyDoesNotBypassHiddenTinyFirstResponderDeferral still fails at line 335, because Ghostty desired focus turns true while the surface is tiny. hiddenTinyFirstResponderReappliesGhosttyFocusAfterGeometrySettles fails the same way, and forcedReparentFocusClearRetriesWhenSurfaceGeometryIsStillTiny fails intermittently. main fails the same tests on macOS 26 (run 36037832075), so this PR is not the cause. That macOS 26 run replaces the earlier 35832271355 claim above; neither test is fixed on macOS 26.
  • Both entries in scripts/ci/app-host-known-failures.json stay until macOS 26 passes.

🤖 Generated with Claude Code

automaticApplyDoesNotBypassHiddenTinyFirstResponderDeferral and
findTerminalRestorePreservesHiddenTinyFirstResponderDeferral hide the
panel early in setup and count on their final setVisibleInUI(true) to
schedule the automatic first-responder apply. setVisibleInUI only
schedules that apply on a hidden-to-visible transition. CI diagnostics
showed the first responder still on the window after the reveal, which
fits a reveal that changed nothing because setup had left the panel
visible. Both tests now hide the panel right before the reveal and
require the hidden and visible states around it.

The find test also left the overlay's own focus handling active.
Mounting the overlay forces focus into the search field, and the
overlay's focus binding starts set and clears only when the field ends
editing. The test now waits for the field to mount, cancels the forced
retries, lets the field take and resign focus, and then sets the
terminal focus intent it exercises.

Both first-responder expectations now print the actual first responder
when they fail.

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

Copy link
Copy Markdown
Contributor

All contributors have signed the CLA ✍️ ✅
Posted by the CLA Assistant Lite bot.

@coderabbitai

coderabbitai Bot commented Sep 23, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository: manaflow-ai/cmux/.coderabbit.yaml

Review profile: ASSERTIVE

Plan: Advanced

Run ID: f6c1655c-3df1-4fd9-b872-5685741e432e

📥 Commits

Reviewing files that changed from the base of the PR and between 1ba90a1 and e4b1c9c.

📒 Files selected for processing (1)
  • cmuxTests/WorkspaceTerminalFocusRecoveryTests.swift

Included review availability: Your plan provides up to 10 included reviews per hour; 0 remain after this review.


📝 Walkthrough

Walkthrough

The focus recovery tests now establish hidden-panel state before revealing the panel. The find-overlay test also mounts a search field, checks its focus, and clears its focus claim before the reveal.

Changes

Focus recovery test coverage

Layer / File(s) Summary
Hidden-panel focus recovery coverage
cmuxTests/WorkspaceTerminalFocusRecoveryTests.swift
The tests assert the hidden portal state before revealing the panel and check the first responder afterward. The find-overlay test mounts and focuses the search field, then clears its focus claim. A DEBUG-only helper locates an editable text field in the search overlay.

Priority: ⬇️ Low

Estimated code review effort: 2 (Simple) | ~10 minutes

Change: Other

Suggested reviewers: teamleaderleo

Merge Risk: ⚪ Minimal · up to e4b1c

No actionable risk remains identified in these test changes. The reported E2E cleanup error remains, but the supplied evidence does not attribute it to this PR.

🚥 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%. Docstring coverage is scoped to functions touched by this diff. Analyzed 4 functions across 1 files. 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 Cloud Persistent Session And Early Input ✅ Passed PASS: The PR changes only cmuxTests/WorkspaceTerminalFocusRecoveryTests.swift. The diff adjusts focus-recovery test setup and adds a DEBUG test helper. It introduces no Cloud terminal creation, cmux…
Cmux Swift Actor Isolation ✅ Passed PASS: The authoritative diff changes only cmuxTests/WorkspaceTerminalFocusRecoveryTests.swift. It updates test fixtures and adds a DEBUG-only test helper; it does not change production Swift declara…
Cmux Swift Blocking Runtime ✅ Passed PASS. The pull request changes only cmuxTests/WorkspaceTerminalFocusRecoveryTests.swift. The added bounded AppKitTestEventPump.waitUntil(timeout: .seconds(3)) is deterministic test-only scaffoldin…
Cmux Browser Automation Off-Main ✅ Passed PASS: The pull request changes only cmuxTests/WorkspaceTerminalFocusRecoveryTests.swift. It does not modify TerminalController.swift or ControlCommandExecutionPolicy.swift, and the added test co…
Cmux Expensive Synchronous Load ✅ Passed PASS: The PR changes only cmuxTests/WorkspaceTerminalFocusRecoveryTests.swift. The added code is test-only AppKit focus setup and a DEBUG NSView subview walk. It adds no production Swift code, age…
Cmux Cache Substitution Correctness ✅ Passed PASS. The authoritative PR diff changes only cmuxTests/WorkspaceTerminalFocusRecoveryTests.swift, a test file. The changes adjust hidden/visible focus setup and add a DEBUG test helper. They do not …
Cmux No Hacky Sleeps ✅ Passed PASS. The PR changes only cmuxTests/WorkspaceTerminalFocusRecoveryTests.swift. The rule applies to TypeScript, JavaScript, shell, and non-Swift build/runtime scripts; Swift timing is covered by a se…
Cmux Algorithmic Complexity ✅ Passed PASS. The pull request changes only cmuxTests/WorkspaceTerminalFocusRecoveryTests.swift. The added view-hierarchy traversal is test-only scaffolding, and the policy explicitly passes test fixtures. …
Cmux Swift Concurrency ✅ Passed PASS. The PR changes only cmuxTests/WorkspaceTerminalFocusRecoveryTests.swift. The added asynchronous operations use the existing @MainActor AppKitTestEventPump and AppKit focus APIs. The diff a…
Cmux Swift @Concurrent ✅ Passed PASS. The PR changes only an @MainActor Swift test suite. The new helper is synchronous and the added async calls use AppKitTestEventPump, which is also @MainActor and only coordinates UI run-loop wor…
Cmux Swift Package Boundaries ✅ Passed PASS: The pull request changes only cmuxTests/WorkspaceTerminalFocusRecoveryTests.swift. The diff adds test setup, assertions, and a private search-field helper under #if DEBUG; it does not change…
Cmux Swiftpm Lockfiles ✅ Passed PASS: The authoritative PR diff changes only cmuxTests/WorkspaceTerminalFocusRecoveryTests.swift. It contains test-fixture updates and no Package.swift, Package.resolved, .gitignore, workflow,…
Cmux Swift Logging ✅ Passed PASS. The pull request changes only cmuxTests/WorkspaceTerminalFocusRecoveryTests.swift. The added #expect messages include first-responder descriptions, but they are test assertion diagnostics, n…
Cmux User-Facing Error Privacy ✅ Passed PASS — The PR changes only cmuxTests/WorkspaceTerminalFocusRecoveryTests.swift (+56/-2). The diff updates test setup, assertions, and a #if DEBUG test helper. It adds no production user-facing err…
Cmux Full Internationalization ✅ Passed PASS. The authoritative diff changes only cmuxTests/WorkspaceTerminalFocusRecoveryTests.swift. The file's tests and the added findMountedSearchField helper are inside #if DEBUG, and all added te…
Cmux Swiftui State Layout ✅ Passed PASS: The pull request changes only cmuxTests/WorkspaceTerminalFocusRecoveryTests.swift. The diff adds AppKit test setup and an NSView/NSTextField traversal helper. It adds no SwiftUI import, `O…
Cmux Architecture Rethink ✅ Passed PASS. The diff changes only cmuxTests/WorkspaceTerminalFocusRecoveryTests.swift. It adds test setup assertions, AppKit event-pump waits, focus transitions, and a DEBUG-only view-inspection helper. T…
Cmux Swift Auxiliary Window Close Shortcuts ✅ Passed PASS: The pull request changes only cmuxTests/WorkspaceTerminalFocusRecoveryTests.swift. The added code is test-only fixture setup and a DEBUG-only search-field helper. It does not add or materially…
Cmux Source Artifacts ✅ Passed PASS. The authoritative diff changes only cmuxTests/WorkspaceTerminalFocusRecoveryTests.swift, a hand-written test source file. The additions are test setup, assertions, comments, and a DEBUG-only h…
Cmux No Test Or Debug Seam In Production Source ✅ Passed The PR changes only cmuxTests/WorkspaceTerminalFocusRecoveryTests.swift. The added #if DEBUG helper is inside the test target, and the diff contains no Swift file under a production Sources/ pat…
Title check ✅ Passed The title clearly and concisely describes the main change: updating focus-recovery tests to start the hidden/tiny reveal from a hidden panel.
Description check ✅ Passed The description includes a clear summary, testing details, hosted run results, known macOS 26 limitations, and checklist status. It also explains that local testing was not performed and that the E2E …
  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR

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.

@teamleaderleo

Copy link
Copy Markdown
Collaborator

Closing my #14100 in favour of this PR, which fixes the same two tests and is stronger: it uses #require on the hidden/visible state and also fixes the find overlay's forced focus. #14100's diagnosis, in case it helps: surface startup calls focusPanel, which makes the panel visible again, so the tests' hide/reveal step was a no-op. This PR's latest run with main merged in (35936170934) failed at the app build in TerminalController sources, not in the test file, so it needs a rerun on current main.

teamleaderleo added a commit that referenced this pull request Sep 24, 2026
The focused macOS 26 run of fa8d583 failed
globalSearchRoutesWhileCommandPaletteIsEffective on the same inactive
host the chord test already works around: routing reached the palette,
but the popover could not present. Both command-palette routing tests
now count requests through the same substitute menu bar extra, which
now installs and restores itself.

The same run showed that activating the app host does not help the
hidden/tiny focus-recovery tests: NSApp.isActive never became true in
10 seconds. That repair is reverted here; #13948 and #14060 own those
tests.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
teamleaderleo added a commit that referenced this pull request Sep 24, 2026
* fix: keep the checklist popover across a same-turn row reparent

On macOS 26 the native popover closes while a sidebar row is reparented
synchronously. The section now tells a positioning-view detach from a
real click-away: if the same workspace reattaches in the same turn with
presentation still requested, the popover is presented again without
writing presented=false. A presentation generation retires the deferred
close so a reused or unmounted cell cannot write back to the wrong
workspace, and unmount writes back a close that is still deferred.

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

* test: repair the app-host suites that fail only on macOS 26

Shards 2, 4, 6 and 7 of the PR app-host lane now run on macOS 26, where
these tests failed on every run while passing on macOS 15:

- The hidden and tiny terminal-focus recovery tests activate the app
  host before asking AppKit for real first-responder ownership.
- The Global Search chord test counts palette requests through a
  test-owned menu bar extra controller instead of waiting for a popover
  that an inactive xcodebuild host cannot present.
- The Campfire hook mock server serves an accepted client on its own
  server task instead of dispatching back onto the contended global pool.
- The glass-chrome test sets the backdrop settings to match its
  useGlass argument, so the bound terminal keeps the native glass root.
- The geometry feedback-loop canary puts its rows in a ScrollView so the
  growing rows cannot resize the window and crash the test host.

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

* fix: let a checklist popover that survived a reparent dismiss on click-away

The detach flag set in viewWillMove(toWindow: nil) was only cleared by a
deferred close, unmount, or detach. When the popover stayed open across
the reparent, the flag stayed set, and the next real click-away took the
deferred path and presented the popover again. The section now clears
the flag once it is back in a window with the popover still shown.

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

* test: count Global Search requests in the command-palette routing tests

The focused macOS 26 run of fa8d583 failed
globalSearchRoutesWhileCommandPaletteIsEffective on the same inactive
host the chord test already works around: routing reached the palette,
but the popover could not present. Both command-palette routing tests
now count requests through the same substitute menu bar extra, which
now installs and restores itself.

The same run showed that activating the app host does not help the
hidden/tiny focus-recovery tests: NSApp.isActive never became true in
10 seconds. That repair is reverted here; #13948 and #14060 own those
tests.

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

* fix: retire a stale checklist detach flag on new presentation and reuse

A detach flag left by a previous session could turn the next real
click-away into a deferred re-present, and a deferred close could latch
the dismiss ack on the workspace a reused cell now shows. Clear the flag
when a presentation starts, and on workspace reuse write the old
workspace back and advance the generation.

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

* test: give the first Search popover time to present on macOS 26

Run 35983669007 failed only the first local-monitor-chain test: the
popover did not appear within the 2 s wait, while every later popover
test in the same app host presented and passed. The wait returns as
soon as the window appears, so a 10 s ceiling costs nothing when it
passes.

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

* test: retry the Search popover while a fresh status item settles

The 10 s wait in 37bb6b7 did not help: run 35986561898 failed the same
first local-monitor-chain test, and the log shows AppKit rejecting the
popover's geometry (x and y infinity) right after the toggle. The routing
tests before it now swap the menu bar extra, so this test is the first to
anchor on a newly created status item, which macOS 26 places
asynchronously. The popover then counts as shown but never appears, and a
second toggle would only close it. The helper now closes that phantom and
toggles again, up to three times, with a 3 s wait per attempt.

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
@cursor

cursor Bot commented Sep 24, 2026

Copy link
Copy Markdown

Bugbot is paused — on-demand spend limit reached

Bugbot uses usage-based billing for this team and has hit its on-demand spend limit.

A team admin can raise the spend limit in the Cursor dashboard, or wait for the next billing cycle to continue.

@teamleaderleo
teamleaderleo enabled auto-merge (squash) September 24, 2026 18:30
@teamleaderleo
teamleaderleo merged commit 1d2a786 into main Sep 24, 2026
43 of 44 checks passed
rustybret pushed a commit to rustybret/bmux that referenced this pull request Sep 24, 2026
7f58f60 ci: seed the SwiftPM manifest cache for the macOS 15 pool (manaflow-ai#14272)
eb8c210 ci: start macOS checkouts from main's git objects (manaflow-ai#14255)
63f485d ci: count the unseeded macOS 15 pool's cold compile when picking a PR pool (manaflow-ai#14268)
5ecf3dd fix(ios): keep alternate-screen apps within the visible viewport (manaflow-ai#12844)
87946bb fix(ios): accept the Mac's push key-exchange reply so pushes decrypt (manaflow-ai#14267)
925c73f ci: fix owned pool review items before the fleet is switched on (manaflow-ai#14252)
1d2a786 test(focus-recovery): start the hidden/tiny reveal from a hidden panel (manaflow-ai#14060)
863f636 Fix BETA signing and prepare iOS migration candidates (manaflow-ai#14265)

# Conflicts:
#	.github/workflows/ci-guards.yml
#	.github/workflows/ci-macos.yml
#	.github/workflows/ci-owned-pool-rescue.yml
#	.github/workflows/ci-queue-janitor.yml
#	.github/workflows/ci.yml
#	.github/workflows/cli-pipe-regressions.yml
#	.github/workflows/ios-testflight.yml
#	.github/workflows/remote-daemon.yml
#	.github/workflows/seed-derived-data.yml
#	.github/workflows/seed-swiftpm-manifests.yml
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.

2 participants