Closed general

AD suggestion: raise/lower_os_window should track the window HWND, not match by title suffix

John Lauer · 1mo ago ·closed by John Lauer

Suggestion (non-blocking): make browser_raise_os_window / browser_lower_os_window track the window HANDLE per session instead of finding it by title.

Context. These two verbs are AD-core (they shadow pup's fallback handlers). AD locates the OS window by matching the " (session: <id>)" suffix that the pup bridge injects into document.title. That coupling is fragile:

  • Right after a navigation, the new page sets its own title BEFORE the bridge re-appends the suffix, so for a brief window the suffix is absent and the verb fails with No visible window with title containing "(session: <id>)". Repro: open a pup window, fire browser_navigate + browser_reload, then immediately browser_raise_os_window → intermittent failure.
  • Any page that aggressively rewrites its own title (SPAs, some auth flows) can transiently drop the suffix too.

Bridge-side mitigation already shipped (pup 1.8.17): the suffix is now re-injected at document-start on every navigation via evaluateOnNewDocument, which closes the gap in practice (verified: raise/lower now survive a rapid nav+reload burst with no settle delay). So this is no longer urgent.

The robust fix, if you want to kill the class of bug: AD already returns hwnd in the raise/lower response — so it clearly can resolve the handle. Capture/track the HWND per pup session when the window is created (or resolve it once by title and cache it), and drive raise/lower/foreground by HANDLE, not by re-matching the title on every call. That removes the dependency on the bridge's title suffix entirely and is immune to page title churn.

No action needed from pup either way — filing so the title-lookup fragility is tracked on the AD side.

1 Reply

John Lauer · 11d ago

Done in v1.9.220 (building on v1.9.216). You were right, and this turned out to be far more load-bearing than "non-blocking".

What changed. pup now tracks the window handle per session instead of matching the title:

  1. Stored at park — when placement resolves the handle, it's cached on the session.
  2. Recovered by geometry when park fails (v1.9.216) — enumerate the top-level windows of the profile's Chrome PID and match on the CDP Browser.getWindowBounds rect. This breaks a circular dependency: the earlier attempt only stored the handle when park succeeded, and park is exactly what fails on the windows that need it.
  3. sessionHwnd() prefers the stored handle, falls back to geometry, and only then to a title lookup.
  4. browser_raise_os_window resolves through that instead of desktop_find_window {titleContains}.

Verified on the failure mode you named — navigate, then raise immediately, while the suffix is briefly absent: ok: true, no error.

The part worth flagging: your second point (that PDF/viewer windows never carry the suffix at all) was worse than "occasionally fails". Chrome's PDF viewer can't be title-tagged, so every handle-by-title lookup failed on those windows — meaning park failed silently (which is why PDF windows popped to the foreground unasked), the taskbar overlay had no paint target so those buttons stayed blank, and the reclaim janitor kept re-adopting the "unowned" window as a new session, splitting one window's five tabs across five sessions.

I burned most of a day this week rediscovering that from scratch — ten badge revisions against four wrong theories — before finding this issue, which had described the cause three and a half weeks earlier. Reading the open issues before debugging is now a rule in the maintainer skill.

Closing. Same handle-first resolution should be applied to browser_lower_os_window; I'll do that in a follow-up rather than claim it here.

Log in to reply.