Skip to content

test(ime): install option-as-alt right before the dead-key dispatch - #14800

Merged
teamleaderleo merged 2 commits into
mainfrom
fix/deadkey-option-state-leak
Sep 26, 2026
Merged

teamleaderleo merged 2 commits into
mainfrom
fix/deadkey-option-state-leak

Conversation

@teamleaderleo

@teamleaderleo teamleaderleo commented Sep 26, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

DeadKeyCompositionRegressionTests.testOptionDeadKeyUsesGhosttyTranslationInsteadOfStartingComposition failed on #14789 with "An explicitly claimed Option side must show AppKit Ghostty's translated event": Option was still set on the interpreted events.

Root cause

The test did three things in order:

  1. Swapped a macos-option-as-alt = true config into GhosttyApp.shared.
  2. Created its TerminalSurface.
  3. Pumped the run loop for up to 5 s waiting for the native surface.

swapConfigForTesting does not propagate to surfaces, so the surface takes whatever app config is current when it is created. A configuration reload queued earlier in the shared test host can run during that pump; appearance sync, theme and settings changes all queue one, and reloads wait at a font-work barrier. The reload replaces the app config with a freshly loaded one that has no option-as-alt.

The failing log shows exactly that. Between the test starting and the surface's io thread spawning /usr/bin/login, the app reads themes/Apple System Colors Light and the user config.ghostty, then finalizes a new config. The surface was created from that reloaded config, so ghostty_surface_key_translation_mods kept Option.

Change

The test now installs the config after the surface exists, immediately before the synchronous keyDown dispatch, with no run-loop turn in between:

  • It installs the config on both the app, which KeyboardLayout.textInputEvent reads, and the live surface via ghostty_surface_update_config, inside suppressGhosttyReloadActions.
  • It restores both right after the dispatch.

Test-only; no production change.

Test plan

  • CI app-host: DeadKeyCompositionRegressionTests green

🤖 Generated with Claude Code


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


Summary by cubic

Fixes a flaky IME dead-key regression test by installing macos-option-as-alt after the surface exists instead of before creating it. The config swap previously happened during a run-loop pump where a queued configuration reload from the shared test host could overwrite the app config, leaving the surface without option-as-alt. The test now updates both the app and the live surface config immediately before the synchronous key dispatch and restores both right after, while the surface is still alive (liveSurface is a raw pointer).

Test-only; no production change.

Written for commit 009eca7. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • Tests
    • Expanded regression coverage for dead-key input involving the Option key, including configurable Option-as-Alt behavior and preservation of expected text.

testOptionDeadKeyUsesGhosttyTranslationInsteadOfStartingComposition swapped
a macos-option-as-alt = true config into GhosttyApp before creating its
surface, then pumped the run loop for up to 5 s waiting for the surface. A
configuration reload queued earlier in the shared test host (appearance
sync, theme, settings) could run during that pump: #14789's failing log
reads the theme and user config files mid-test, before the surface's io
starts. The reload replaced the app config, so the surface was created
without option-as-alt, Option was never stripped, and the assertion saw
Option set.

The config is now installed after the surface exists, on both the app and
the live surface, with no run-loop turn before the synchronous keyDown
dispatch, and restored right after it.

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

coderabbitai Bot commented Sep 26, 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: 8ae68ab9-7514-4930-9042-1fc4457819be

📥 Commits

Reviewing files that changed from the base of the PR and between b92d99c and 009eca7.

📒 Files selected for processing (2)
  • cmuxTests/CJKIMEInputTests+DeadKeyComposition.swift
  • cmuxTests/CJKIMEInputTests.swift

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


📝 Walkthrough

Walkthrough

The dead-key input test helper now supports temporarily applying an Option-as-Alt configuration to a live surface. The regression test calls the helper directly and retains its existing expected results.

Changes

Dead-Key Input Tests

Layer / File(s) Summary
Configure and restore the live surface
cmuxTests/CJKIMEInputTests+DeadKeyComposition.swift, cmuxTests/CJKIMEInputTests.swift
exerciseDeadKeyInput accepts an optional Option-as-Alt value. The helper applies the cloned configuration to the app and supplied live surface, then restores the original configuration after event dispatch. The regression test no longer sets and restores the configuration separately.

Priority: ⬇️ Low

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

Change: Other

Merge Risk: ⚪ Minimal · up to 009ec

This change is confined to regression-test configuration setup and restoration; no concrete test-workflow or product regression is established. It is ready for normal checks.

🚥 Pre-merge checks | ✅ 24 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 66.67% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 3 functions across 2 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 pull request changes only two IME regression-test files. The diff updates dead-key test configuration setup and restoration; it does not change Cloud terminal creation, transport, cmux-tui c…
Cmux Swift Actor Isolation ✅ Passed The pull request changes only cmuxTests/CJKIMEInputTests+DeadKeyComposition.swift and cmuxTests/CJKIMEInputTests.swift, both included in the cmuxTests target. The changed extension and test clas…
Cmux Swift Blocking Runtime ✅ Passed PASS. The authoritative diff changes only cmuxTests/CJKIMEInputTests+DeadKeyComposition.swift and cmuxTests/CJKIMEInputTests.swift. These are test-only files. The added configuration update and re…
Cmux Browser Automation Off-Main ✅ Passed PASS: The pull request changes only IME regression tests in cmuxTests/CJKIMEInputTests+DeadKeyComposition.swift and cmuxTests/CJKIMEInputTests.swift. The diff adds no browser.* socket commands, …
Cmux Expensive Synchronous Load ✅ Passed PASS: The authoritative diff changes only cmuxTests/CJKIMEInputTests+DeadKeyComposition.swift and cmuxTests/CJKIMEInputTests.swift. The changes update test setup and configuration restoration; the…
Cmux Cache Substitution Correctness ✅ Passed PASS: The authoritative PR diff changes only cmuxTests/CJKIMEInputTests+DeadKeyComposition.swift and cmuxTests/CJKIMEInputTests.swift. These are test files, not production Swift, TypeScript, or Ja…
Cmux No Hacky Sleeps ✅ Passed PASS. The PR changes only two Swift test files: cmuxTests/CJKIMEInputTests+DeadKeyComposition.swift and cmuxTests/CJKIMEInputTests.swift. The applicable rule scopes this check to TypeScript, JavaS…
Cmux Algorithmic Complexity ✅ Passed PASS. The diff changes only cmuxTests files, so the production-code complexity rule does not apply. The added collection operations process a fixed five-event dead-key list in test scaffolding. No s…
Cmux Swift Concurrency ✅ Passed The diff changes only XCTest helper configuration timing and a synchronous restoration closure. It adds no DispatchQueue, DispatchGroup, Combine, Task, completion-handler async API, or fire-and-forget…
Cmux Swift @Concurrent ✅ Passed PASS: The diff changes only test code. exerciseDeadKeyInput remains an @MainActor async method and performs UI-bound surface setup, event dispatch, and AppKitTestEventPump coordination. `install…
Cmux Swift Package Boundaries ✅ Passed PASS. The authoritative diff changes only cmuxTests/CJKIMEInputTests+DeadKeyComposition.swift and cmuxTests/CJKIMEInputTests.swift. The changes are XCTest fixtures and AppKit/Ghostty test glue. Th…
Cmux Swiftpm Lockfiles ✅ Passed PASS: The pull request changes only two test files under cmuxTests/. The diff contains no Package.swift, Package.resolved, Xcode project/workspace, .gitignore, workflow, or dependency changes.…
Cmux Swift Logging ✅ Passed PASS: The pull request changes only cmuxTests/CJKIMEInputTests+DeadKeyComposition.swift and cmuxTests/CJKIMEInputTests.swift. The diff adds configuration and surface-update test logic, comments, a…
Cmux User-Facing Error Privacy ✅ Passed PASS: The pull request changes only cmuxTests/CJKIMEInputTests+DeadKeyComposition.swift and cmuxTests/CJKIMEInputTests.swift. The added XCTFail text, comments, and macos-option-as-alt referenc…
Cmux Full Internationalization ✅ Passed The diff changes only cmuxTests/CJKIMEInputTests+DeadKeyComposition.swift and cmuxTests/CJKIMEInputTests.swift. The added text is test documentation and XCTest failure text. The full-international…
Cmux Swiftui State Layout ✅ Passed PASS. The PR changes only AppKit/Ghostty XCTest helpers and a dead-key test. The diff adds no SwiftUI view, ObservableObject/@published state, GeometryReader, lazy/list row store reference, or render-…
Cmux Architecture Rethink ✅ Passed PASS. The PR changes only two test files. It moves the existing configuration setup to immediately before synchronous key dispatch and adds live-surface configuration updates plus restoration. The dif…
Cmux Swift Auxiliary Window Close Shortcuts ✅ Passed PASS. The PR changes only cmuxTests/CJKIMEInputTests+DeadKeyComposition.swift and cmuxTests/CJKIMEInputTests.swift. The NSWindow is a test fixture used by DeadKeyCompositionRegressionTests, an…
Cmux Source Artifacts ✅ Passed The pull request changes only two hand-written Swift test source files: cmuxTests/CJKIMEInputTests+DeadKeyComposition.swift and cmuxTests/CJKIMEInputTests.swift. The diff adds test logic and comme…
Cmux No Test Or Debug Seam In Production Source ✅ Passed PASS. The PR changes only cmuxTests/CJKIMEInputTests+DeadKeyComposition.swift and cmuxTests/CJKIMEInputTests.swift. Neither file is a Swift file under a production Sources/ path. The changed cod…
Title check ✅ Passed The title clearly identifies the test change and its timing-sensitive configuration fix.
Description check ✅ Passed The description includes the problem, root cause, implementation details, and test plan. The CI test remains unchecked, but the description is otherwise complete and the demo video is not applicable t…
  • 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.

@github-actions

Copy link
Copy Markdown
Contributor

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

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@teamleaderleo
teamleaderleo merged commit fb665a0 into main Sep 26, 2026
50 checks passed
@teamleaderleo
teamleaderleo deleted the fix/deadkey-option-state-leak branch September 26, 2026 05:15
@github-actions

Copy link
Copy Markdown
Contributor

Merge receipt for 009eca7ccc: every check was green at merge (16 verified; 14 skipped by policy). Full suite runs on main after merge.

rustybret pushed a commit to rustybret/bmux that referenced this pull request Sep 26, 2026
cc90659 test: a window with no restorable workspaces is dropped from the snapshot (manaflow-ai#14801)
9b10f7c Merge pull request manaflow-ai#14756 from manaflow-ai/12956-ssh-auth-followup-main
fb665a0 test(ime): install option-as-alt right before the dead-key dispatch (manaflow-ai#14800)
9d459e3 fix(fork): an access-time update no longer discards a fresh fork validation (manaflow-ai#14799)
39e2c3a fix(ssh): share one route check across concurrent cmux ssh opens
c344ce9 test: cover concurrent cmux ssh opens sharing one route check
9ff9017 fix(ssh): report OpenSSH failures from cmux ssh instead of a Cloud VM error
311797d test: cover cmux ssh failing fast on refused and unreachable hosts
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