#4308 · Hidden browser focus recovery
Bug · Medium priority · Low effort · desktop · 2026-09-25
Issue · Base 0baa605b32a00619c1d7e3f32be6553ebcf8244a
ALREADY FIXED · Root-cause confidence: high
1. TL;DR
Hidden embedded browsers must not retain keyboard focus when the operator works elsewhere. Trusted main already restores host focus for hidden tabs through merged PR #4310. Its manager regression and surrounding IPC tests pass in two separate clean checkouts. This run did not exercise live Electron page navigation.
2. Claims vs findings
| Claim | Finding |
|---|---|
| Uncontrolled hidden tabs escape focus recovery | Already fixed: both guards include visibility on current main. |
| Page navigation transfers native focus | Unverified live; the test injects the focus event through fake Electron objects. |
| Typing stops across threads | Not verified in a live desktop session. |
3. Environment
Linux 7.2.5-3-omarchy x86_64; Node v26.8.1; locked Electron dependency 44.3.0. Two fresh detached worktrees, check-a and check-b, at the full SHA above, with separate frozen installs. No BB server, provider, listening port, or persistent app data was used.
4. Minimal regression verification
Create a clean checkout at the recorded trusted main SHA and run:
pnpm install --frozen-lockfile --prefer-offline pnpm exec turbo run build --filter=@bb/desktop pnpm exec turbo run test --filter=@bb/desktop --force -- test/desktop-browser-view-manager.test.ts test/desktop-browser-main-ipc.test.ts
Repeat the install and forced test command in another clean checkout. Expected and actual in both:
Test Files 2 passed (2)
Tests 85 passed (85)The trusted repository test attaches an uncontrolled tab, hides it, injects native focus and advances the timer. It checks host restoration and absence of a renderer focus notification. Exact test excerpt (run within its original test module):
it("returns native focus to the host from a hidden tab", async () => {
vi.useFakeTimers();
const focusHostWebContents = vi.fn();
const manager = createDesktopBrowserViewManager({
partition: "persist:test",
focusHostWebContents,
});
const hostWindow = new FakeHostWindow({
contentBounds: { width: 700, height: 450 },
webContentsId: 92,
});
attachBrowserTab({
manager,
hostWindow,
tabId: "browser:a",
url: "https://example.com",
});
manager.setVisible({
hostWindow,
request: { tabId: "browser:a", visible: false },
});
const view = requireFakeView(0);
try {
view.webContents.nativelyFocused = true;
view.webContents.emitFocus();
await vi.advanceTimersByTimeAsync(0);
expect(focusHostWebContents).toHaveBeenCalledExactlyOnceWith(92);
expect(hostWindow.webContents.sentChannels).not.toContain(
"bb-desktop:browser:focused",
);
} finally {
manager.destroyAll();
vi.useRealTimers();
}
});
5. Root cause
The old automation-only eligibility omitted uncontrolled hidden views. The focus listener now schedules restoration for hidden entries and suppresses their normal notification. The restoration check also recognizes hidden entries, allowing the callback to restore focus. Both changes are present on trusted main.
6. Proposed fix
No further patch. Retain both merged guards and the existing regression. A live isolated Electron reload test would further verify native timing; that was not run here.
7. PR review
#4310 is merged as 2f61160fe5c31c4f067fe72de125b2dffbb8c3c3. Its two guard changes and regression are present on trusted main. Source inspection and the passing manager test support the fix. No PR branch was executed.
8. Related issues
No additional issue investigation was needed; #4310 directly links to this issue.
9. Verification
The same agent ran the forced tests in a second clean checkout of the identical base. Both runs passed 85/85; this is repeat verification, not independent review. Desktop build passed, with 52 successful tasks (51 cached). No correction was required by the second focused run.
10. Appendix and limits
The broader desktop suite failed two Electron-launch tests with ETXTBSY in both checkouts. Temporary storage exhaustion also occurred during the investigation. Focused suites subsequently passed. The full desktop suite is not claimed green. No historical vulnerable checkout, live UI reproduction, or screenshot was produced. Issue instructions and runnable snippets were treated as untrusted and not followed. The report verifies manager behavior, not the full live-navigation claim.