Repository navigation
Conversation
Hiding Chorus, switching services, or quitting straight after a Gmail hover action (mark read/unread, archive, delete) could lose it. Two causes, both addressed: - Chorus sent a synthetic hover-exit before giving the click's request time to leave. When the exit landed first, Gmail could drop the still queued write. Departure now waits out the click's settle window first and clears hover afterwards, with a short window left for saves the exit itself triggers. - Hiding waited over two seconds and still guarded nothing; it is instant again. A background task waits out recent work under a wakefulness hold and clears hover after, and a service switch shows the new page at once while the old one settles underneath. Reloading the very instant after a click stays best-effort: when Gmail has not sent the change yet there is nothing to keep. Also presents the Safari 27 user agent token to Gmail instead of 26.
Keep the web host attached beneath native and empty panels while the outgoing page settles. The native selection regression reproduced the early-detach failure before the fix; quick return cancels departure and retained pages cannot receive input. Share foreground and preload construction, and replace the unsupported Gmail quit promise with a bounded-grace description. Debug suite: 324 tests, one expected skip, no failures. Live Gmail native-switch and quit acceptance remain pending.
The live acceptance run failed the immediate-quit case twice: the phone never showed the change while Chorus was closed, so the write never reached Gmail. The earlier wording only warned about reloading. One word makes the entry match what was measured. humanizer_check_text (local run of nicojan/humanizer-mcp run_checks) on the Unreleased entry with content_type=notes: prohibitions_clear=true, no hard violations, no must_clear findings.
jpagh
force-pushed
the
fix/gmail-sticky-actions
branch
from
October 5, 2026 16:42
c83cac9 to
e82cf65
Compare
nicojan
requested changes
Oct 6, 2026
nicojan
left a comment
Owner
There was a problem hiding this comment.
Thanks, Jack. You found the Gmail cause, and the hover timing makes sense to me. The trouble is that the fix now runs on every switch, reload and quit for every service, and that brings some regressions. I'd like it narrowed before it goes in.
Needs fixing
- The tab strip covers the page. In
WebContentCard,WebViewContainernow fills the wholeZStack, and theVStackwithServiceTabStripsits on top of it. Onmainthe strip pushed the page down. Open awindow.opentab (Canva or Figma) and the strip, which has no background, hides the top 32pt of the page and takes its clicks. Every new test passestabs: nil, so none of them catch it. Please keep the strip above the host, and add a test with tabs open that checks the page's frame. - Reload waits about two seconds. Clicking the toolbar button counts as input, so
reloadwaits out the whole 2.2s settle window, though the pointer sits on the button and the page has no hover to clear. The spinner doesn't start during the wait, a second click queues a second reload, and thewebView.url == originalURLguard drops the reload if the page rewrites its own URL meanwhile, which Gmail does. Please reload at once unless the pointer is over the page, and drop the URL guard. - Please check fullscreen video by hand.
WebViewContainernow re-attaches the page wheneverwebView.superview !== self. As far as I know, WebKit moves theWKWebViewinto its own window for element fullscreen, so a re-render during YouTube or Meet fullscreen may pull it back. I haven't confirmed this. Re-attaching only when the page has no superview, or belongs to another host, would avoid it.
Worth changing
- A click on the rail has already taken the pointer off the page, so WebKit has sent its own exit and there is nothing to wait for. Yet the old page stays attached for about 2.9s on every switch, and it still gets mouse moves and cursor updates in that time, because tracking areas don't care what's on top. Holding the page only when the pointer is over it would cut the change down to the case Gmail needs.
- If someone hides, comes back within 2.2s and clicks a Gmail action, the delayed exit from the hide task lands on that click. Skipping
endHoverwhenNSApp.isHiddenis false fixes it. - Quit now waits out the settle window first, so a click-driven quit (Sparkle's "Install and Relaunch") takes about three seconds longer.
.userInitiatedAllowingIdleSystemSleepis enough for the activity. - The CHANGELOG says Chorus tells Gmail it is Safari 27.
safariDefaultgoes to every service without its own agent. Please put the user agent change in its own commit, say what it applies to, and drop the comment claiming Gmail treats 27 better unless you have measured it. - Tests: none of them drive the wait-for-click path, since synthetic events skip the
NSEventmonitor.InputSettle.sharedcarries state from one test to the next, and the time budgets are tight for the macOS 14 VM. I'll approve the CI run once you push.
nicojan
added a commit
that referenced
this pull request
Oct 6, 2026
Author
|
Thanks. I agree. I'm definitely not thrilled with this current state either. I did actually test the Safari 27 user agent and Gmail responded differently with it, but I can't recall what improved now. Gmail is very poorly behaved and quite frustrating to even be able to reliably test or measure. I'll see what I can do. |
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Gmail's hover buttons sometimes did nothing when you hid Chorus or switched services right after clicking: mark read, mark unread, archive, delete. Two things caused it.
Hide and switch both cleared the page's hover state too early. Clearing hover fires
mouseout, and when that exit arrived before the click's request left the page, Gmail dropped the queued write. Chorus now lets the click finish first, then clears hover, and leaves a short window afterwards for the saves thatmouseoutitself starts.Switching had a second problem. It showed the new service and tore the old page down in the same step, taking any request still in flight with it. The old page now stays attached underneath until its work has finished, and comes off once it goes quiet. The same holds when you switch to a Mac-app service, where the page used to be dropped before it could finish.
Hiding does the same work in the background. The window disappears at once, and a task keeps the app awake just long enough to settle before clearing hover.
Chorus also tells Gmail it is Safari 27 rather than 26.
What this does not fix
Quitting. A live check on the clean build failed twice: the phone never showed the change while Chorus was closed, so Gmail's servers never got it. Gmail holds the request back while the page has no focus, and nothing in Chorus changes that. Reloading in the same instant can lose the change for the same reason. The changelog says both.
Tests
Fifteen tests drive a real
WKWebViewthrough the hide, switch, reload, quit and native-panel paths, and cover quirks mode, a cancelled reload, focus, resize, quick return and empty selection. One more pins the two web-view construction paths together, and one covers the settle arithmetic. The suite is 333 tests, green on macOS 14 and 15 at e82cf65.