fix(focus): the reopen key hold also waits for a restored browser tab's page; Cmd-L reaches its address bar (REOPEN-F4 browser case)

Merged
LA
2d ago
+168-20

Summary

After Cmd-Q (Keep) and a reopen with a browser page focused, a person's Cmd-L typed right away opens a new New Tab page, and the text typed after it goes there instead of into the address bar. Journey reopen-browser-first-key (kit cp/reopen-video-kit@9c22661888, review SHIP) on feat c569f95 (build 6661b995): 3 of 5 cycles lost the real Cmd-L + marker (lost at 106-122 ms after main, kept at 297-312 ms). STATUS 5871.

Cause (input journal + code): a restored Chromium tab gets its page from an async start (TabContentCache.browser -> makeCEFTab in a Task; nil until onBrowserReady, about 300-400 ms after main). In that gap the focus already names the browser page, but the pane has no browser content. Cmd-L is Focus Location Bar (PaneController.focusLocation), whose "not a browser" branch opens a New Tab page (cx-e2aa). It is the same class as REOPEN-F4 fault 2 (#31707): focused content whose view is not ready, here a page instead of a terminal.

Fix: the #31707 key hold also waits for a focused browser tab whose page is not made yet.

  • AwaitedContent (new, CmuxNextFocusUI, a pure policy): the decision "the focus names content its pane does not show yet", for a terminal (unchanged rule) and now a browser page. The coordinator's old inline decision moves there (commit 1, no behavior change).
  • CreationInputBuffer.awaitContent: a page hold has no terminal lane. Every key but a close waits (Cmd-L needs the page), at most holdLimit (2 s) from the hold's start.
  • The hold ends when the page is presented (contentPresented -> focus settle -> flush). The keys then run again as typed: Cmd-L focuses the address bar, and the letters after it go there. At the bound they run as typed too.
  • FocusState.awaitableContent (CmuxNextFocus) maps the focus to the content keys are for. Net CmuxNextApp −4 lines.

Not part of this PR: the smoke gate's step-70 "reopened window not key" (STATUS 5612/5810) is a gate gap, not this fault. With #31684 the restored page keeps the keyboard in its Chromium page window. The harness owner's fix is on cp/smoke-known-gap (37fb4ba6272).

Testing

  • AwaitedContentTests (CmuxNextAppTests): the terminal rule (commit 1, green), then aRestoredBrowserTabIsAwaitedUntilItsPageExists (commit 561522e6e3e, red: the browser tab is not awaited, and its keys would get a terminal lane).
    Fleet runs (package-test-lane.sh suite, AwaitedContentTests named 5 times, through proof-step.py):
  • Red 561522e6e3e (browser test, policy without the browser rule), job 58bdcdfb8862a3f5a07af639: aRestoredBrowserTabIsAwaitedUntilItsPageExists fails 5 of 5; the terminal tests pass.
  • Red 9249761ae90 (review: shortcut test, pageHoldKeeps stubbed to true), job d165e0a6eb3f1a9dbdbc618f: aPageHoldLetsAppShortcutsPassWhileEmptyButKeepsPageActions fails 5 of 5. (The first try 2244fcce ran on the Blacksmith overflow and failed with no test output: an infra run, rerun at the same sha.)
  • Green at the head ee0fb3ca578, job 38290ab3c58dae522b6c03ca: all 5 tests pass 5 of 5. Compile of the head: job 50816a586ed681f9c011db7a passed.
  • End result (REOPEN VIDEO owner, STATUS 6007), build 4611f6ba740b7f1d7900687e of the first fix (d64f06a4fb0): reopen-browser-first-key (kit 9c22661888) 3 of 3 rounds, 9 of 9 cycles (Cmd-L + marker reached the address bar 9/9; Cmd-N + Ctrl-made a terminal in a new workspace 9/9);reopen-first-key` (kit ff80174a568) 1 round, 0 keys lost in 5 cycles, kill-all line reached the shell. Base feat c569f95: 3 of 5 cycles lost.

Merge of feat (head a919ea996a0, PR was DIRTY; one conflict with #32098 in flush, both changes kept): compile of the head passes for the app and cmux-tui; the CmuxNext tests at the head fail only on the feat tip red AgentPaneRelayedAllowTests.swift:328 (#32113, STATUS 6262). Proof ref 5c124146a70 = head + that one file from before #32113 (proof only): compile a2a839d605bbdfcd740ae77b passed; AwaitedContentTests x5 job d1dd75af548b663e429c0d58: all 5 tests pass 5 of 5. Display proof: the end-result journey above is the real-app proof (REOPEN VIDEO, real HID keys on a mini's console session); AwaitedContentTests is a pure policy and needs no display.

Review: SHIP at a919ea996a0 (comment 6575617084); earlier SHIP at ee0fb3ca578 (comment 6573991292). Its first FIX (a cold Chromium tab's page hold delayed app shortcuts) and its notes are fixed in 9249761ae90 / 37c96ebaf20 / ee0fb3ca578.

Observed / Not run

  • Observed: the journals of rounds rbk2-feat-c569f95/a1-a3 (lost cycles: Cmd-L key-down at 106-122 ms, the pane shows a pending_tab, then agentPage, the marker goes there). Code read of TabContentCache.browser and focusLocation. Pre-push gate: no new violations.
  • Not run on the final head: the journeys ran on d64f06a4fb0 (before the review fixes). The review fixes narrow the hold (app shortcuts pass while it is empty; a tab whose hold reached its bound gets no new hold until its page arrives); they do not touch the Cmd-L path the journey drives.
  • The last test (aTabExcludedAfterItsBoundIsHeldAgainOnceItsPageArrived) is in the same commit as its fix (ee0fb3ca578), not committed red first.
  • Follow-up (review note): split the one-line pageArrived(key); for ... at AppServices.swift:742 into a coordinator method; not done here because it adds App lines the arch ratchet refuses.
  • Not covered: plain keys (no Cmd-L) typed into a restored page before it exists run again into the shell window's responder, not the Chromium page window; the observed case is Cmd-L first.

Changelog

Fixed: After cmux reopens with a browser tab focused, Cmd-L and what you type right away go to its address bar instead of opening a new tab

Proof

No capture: input routing; the proof is the tests and the reopen journey.