Repository navigation
R-INPUT S2b step B: every window's focus machine keeps its focus in the app's one input router (cmux_input_*) - #35875
Conversation
…he app's one input router (cmux_input_*) Step B of the FFI two-step (step A #35641, re-pin #35853): FocusMachine calls the input handle (`cmux_input_focus_*`, one window key per machine) instead of a per-window `cmux_focus_*` handle. The router is made once at the composition root (AppServices.focusInput, FocusInput in CmuxNextFocus) and given to each window's FocusCoordinator through WindowState. Pure refactor: the same requests and the same reply bytes (step A's corpus test), so every focus rule is unchanged. - FocusInput owns the CmuxInput handle (memory: the Mac's physical memory, which bounds the key lanes). Each machine opens a window under a key no other machine of that router had, and closes it when freed, so a window id the app reuses (a restored closed window) never meets the state of the machine it replaces, whichever is freed first. - A machine made with no input (tests, the journal replay) gets a router of its own. - FocusMachine's Close Tab aim calls move to FocusMachine+CloseAim.swift (A12 follow-up); the file shrinks from 467 to 458 lines. - FocusResponderClassifier.describe moves to the package as FocusEvent.Responder.debugName (CmuxNextApp: -10 lines). Tests: FocusInputSharedRouterTests: a machine in the shared router reduces exactly as a machine alone (state and effects after every event) while another window acts between its events; a new machine never meets a freed machine's focus; every request goes through the input handle (the close-focus policy, the Close Tab aim, the history, the remembered panes, the checkpoint; a checkpoint that does not decode is refused and leaves the state as it was: review notes of #35641).
…t may not name an internal import)
|
cmux status (one comment, edited in place; each line is updated by the job that owns it) Review App of this head (app.zip, kept 1 day)
Shipped in:
The feat-cmux-next push run https://github.com/manaflow-ai/cmux/actions/runs/41927927728 at b5e96a1 failed: cmux-next checks (god files, concurrency, crash safety, l10n). |
…umented order (the focus moves, then the frame shows) and compares each answer with a machine alone
Bugbot needs on-demand usage enabledBugbot 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. |
|
Review (independent subagent, correctness first): SHIP at e79c99c Scope: I found no blocking defect in the production code. All findings below are non-blocking. The test findings (F1 to F3) are worth a follow-up. Checked and correct
Findings (non-blocking)F1. Test 3 compares the new path with itself, and the rewrite removed its absolute checks.
F2. Vacuous assertion at FocusInputSharedRouterTests.swift:56.
F3. Test 2 does not test the teardown (FocusInputSharedRouterTests.swift:61-78).
F4. A claim in the PR body is not accurate.
F5. A latent thread hazard; I found no path to it today.
F6. A default argument can hide a private router.
F7. Stale comment. Package.swift:99 still says "FocusMachine over cmux-focus-core's cmux_focus_* C ABI". Not run: I did no build and ran no tests (this was a read-only review). The focus bench from the DESIGN S2 acceptance ("focus bench within 5 %") has not run, as the PR body already says. |
|
Swift logic follow-up (tip watcher swift-logic row, STATUS 13027 "SWIFT LOGIC CULPRITS"; lead order). This PR raised
plans/cmux-next/layer-ownership.md says Rust owns every state, list and rule and Swift is the platform shell. Please move the new logic of this PR in a follow-up: to Rust (the crate that owns the area; the owner lists in STATUS 12147-12165 name the target per area), or at least out of the app into its package. If a declaration above is platform code (AppKit, Core Animation, OS calls, strings, tokens, DEBUG tooling), reply here and the table gets a PLATFORM row with your reason instead. The swift-logic row is a report, not a gate: nothing blocks on this comment. |
…indow close; WindowState takes the router with no default (review of #35875) (#35924) * test(focus): the shared-router tests check absolute answers, the other window's focus and the window close; WindowState takes the router with no default; a machine freed off the main thread stops debug builds (review of #35875: F1-F3, F5-F7) * test(focus): the shared-router test also checks the shown workspace's history (review of #35924, finding 1)
REWRITE R-INPUT stage S2, step B of the FFI two-step (step A #35641, re-pin #35853, DESIGN.md section 5): every window's
FocusMachinekeeps its focus in the app's one input router (cmux_input_*) under a window key of its own, instead of a per-windowcmux_focus_*handle. Pure refactor: the same requests and the same reply bytes (step A's corpus test compares them), so every focus rule is unchanged.What changes:
FocusInput(CmuxNextFocus): owns theCmuxInputhandle; made once at the composition root (AppServices.focusInput) and given to each window'sFocusCoordinatorthroughWindowState. The router's key lanes are bounded by the Mac's physical memory (cmux_input_new(memory)).InputReplay) gets a router of its own.FocusMachine's Close Tab aim calls move toFocusMachine+CloseAim.swift(the A12 follow-up);FocusMachine.swiftgoes from 467 to 458 lines.FocusResponderClassifier.describemoves to the package asFocusEvent.Responder.debugName. Archapp_lines-10.Tests
FocusInputSharedRouterTests(Packages/macOS/CmuxNext, new):aMachineInTheSharedRouterReducesAsAMachineAlone: a machine in the shared router and a machine alone get the same reply (changed, effects, omnibar flags) and the same state after every event of a sequence (topology, person moves, a selection, the address bar, a click report, an intent, a CLI move, a topology change, a palette move), while another window of the same router acts between its events; the same checkpoint, history and remembered panes at the end.aNewMachineNeverMeetsAFreedMachinesFocus: a machine freed before a new one is made leaves no history or remembered panes to it; the window still open keeps its own.everyRequestGoesThroughTheInputHandle: the close-focus policy, the Close Tab aim (pane emptied, pane moved, aimed at, presented), the history, the remembered panes and the checkpoint all go throughcmux_input_*; a checkpoint that does not decode is refused and leaves the state as it was (R-INPUT S2b (FFI step A): the app's one input handle cmux_input_* over the input router, with no copy per focus event #35641 review notes: the C ABI test did not call every export, and did not compare the state before and after a bad import).A pure refactor has no red step: the old path is gone in this PR. The check that the new path answers as the old one is step A's Rust corpus test
the_input_handle_replies_to_every_corpus_step_as_the_window_handle(cmux-tui/crates/cmux-layout-reducer-ffi/tests/input_handle.rs, landed in #35641): it replays every corpus sequence (100+ sequences, 1,000+ focus events) through the input handle and through the old window handle and compares each reply. The Swift tests above check the app's side only: a machine in the shared router answers as a machine alone while another window acts, windows stay apart, and every Swift call goes throughcmux_input_*.Compile check 1e9b30f5 of 83c1758 (this branch merged with feat 00655a4) passes; e79c99c changes only the new test file. Green: step e498ede205b71ebe3d903591 at e79c99c (aws-m4pro-4): all 21 suites pass (FocusInputSharedRouterTests, FocusPersonMovesTests, FocusWaitLeavesPageTests, CloseTabKeepsPaneTests, MultiWindowInputRoutingTests, FocusFollowsMouseTests, FocusedPaneShowsFirstTests, KeyRouterRepeatAndChordTests, MenuKeyRoutingTests, PaneCloseApplyTests, PaneCloseControllerTests, WindowFocusRestoreTests, WebViewFocusedContextTests, NewTabHoldFocusTests, CreationHoldReplyBoundTests, CreationHoldReplyBoundRuleTests, PersonTerminalKeyboardClaimTests, HomePendingTerminalFocusTests, SwitchToColdTabTypeAheadTests, HeadlessRenameTakesNoKeyboardTests, HeldKeyRunPanelTests). An earlier run at 83c1758 (step b998c98b) failed one case of my new test
everyRequestGoesThroughTheInputHandle: it called the Close Tab aim in an orderPaneCloseAimdoes not document (the frame stamped before the focus moved); e79c99c follows the documented order and compares every answer with a machine alone.ASan (
CMUX_SWIFT_SANITIZE=address, step 085409561b6c6bf6a53fb226): 5 of 8 suites pass (FocusInputSharedRouterTests, FocusPersonMovesTests, FocusWaitLeavesPageTests, WindowFocusRestoreTests, CreationHoldReplyBoundRuleTests: the machine reply reads under the sanitizer). The 3 window suites (CloseTabKeepsPaneTests, PaneCloseControllerTests, MultiWindowInputRoutingTests) abort in the ASan runtime itself before any assertion: "AddressSanitizer failed to deallocate 0x40000 bytes at address 0x...b28 (error code: 22) / Failed to munmap" (a non-page-aligned unmap inside the sanitizer's allocator). Classified as a base finding, not this change: the same 3 suites under ASan on the base feat 00655a4 (without step B, step dc3b33cf482e2f0a0de4c745, aws-m4pro-2) abort with the identical runtime error ("failed to deallocate 0x40000 bytes at address 0x...b28 (error code: 22) / Failed to munmap") in all 3 suites. So under ASan the fleet Macs (macOS 26/27, Xcode 26.6) cannot run these window suites at all, with or without this PR; the 5 suites that do run under ASan include the machine-level ones that read every reply of the input handle.S2 test phase: the input router fuzz at 1,000,000 cases on the merged step A commit dba5f44 passed (step 85d683ea37e2, Linux, 180.3 s, 0 findings).
Review
Review (independent subagent a95e30fa): SHIP at e79c99c (#35875 (comment)). Its non-blocking findings go to one follow-up PR: test 3 compares the new path with itself and the absolute checks of history and
remembered()came out (F1); one check of test 1 cannot fail (F2); test 2 does not prove thatdeinitcloses the window (F3);FocusMachine.deinitmust never run off the main thread now that it writes to the shared router (F5); the defaultFocusInput()ofWindowState.initcan give a future production window a router of its own (F6); a stalecmux_focus_*comment inPackage.swift(F7). F4 (this body named the Swift test as the parity proof) is fixed above.Observed / Not run
CMUX_SWIFT_SANITIZE=address(the lead's sanitizer plan for the app's reads of a reply: ASan's interceptors cover the Rust library's heap too); the prepush gate (no new violations,app_lines-10).Changelog
none
No capture: no visible change (a refactor).