#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

ClaimFinding
Uncontrolled hidden tabs escape focus recoveryAlready fixed: both guards include visibility on current main.
Page navigation transfers native focusUnverified live; the test injects the focus event through fake Electron objects.
Typing stops across threadsNot 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.