🚨 SLOP COP 🚨 · new-issue-autopilot

#3558 · Hidden-tab focus event forwarding

BugPriority: MediumEffort: Mediumdesktop, pluginsIssue

2026-09-12 · trusted base 1ebdc56a50b9f87ece261b426ca6ad8ac4f7daa9

Verdict: PARTIALLY REPRODUCED · Root-cause confidence: low for the reported incident. The narrower event-forwarding behavior is demonstrated twice.

1. TL;DR

The report describes background browser work interrupting the operator in other threads. A focused test shows that BB forwards a hidden automation tab's native focus event into its host app without checking visibility. The test explicitly injects that event using the repository's existing fake Electron fixture; it does not show that a normal controller command generates it. Existing tests for thread-scoped panel reveal and hidden-view handling pass. Cross-thread selection, input interruption, and macOS foreground changes remain unverified.

2. Claims vs findings

Claim or hypothesisFindingEvidence
Automation initially creates a hidden tabVerified in source and existing fixture testPlugin passes hidden presentation; hidden native creation makes no focus call.
Hidden tab activity can notify app focusPartially verifiedInjecting a native focus event produces bb-desktop:browser:focused despite the view remaining hidden.
Normal browser operations steal focus across threads or applicationsUnverifiedNo live desktop controller reproduction was run.
Two active controllers caused the incident and closing them ended itUnverifiedOperator runtime data was not accessed; session count and causal effect were not reconstructed.
Panel-reveal events always switch to the owning threadRefuted for the tested hookThree existing reveal tests pass, including ignoring other threads and discarding background requests.

3. Environment

macOS 26.6.2 (25G83), arm64; Node 22.22.3; pnpm 9.15.0 through Corepack; Vitest 4.1.1. This differs from the reported OS. Two separate clones, called base and verify, used the same recorded commit and separate dependency installs. Electron was mocked by the existing repository test fixture. No BB server, desktop instance, provider turn, controller lease, port, or runtime data directory was used.

The default pnpm launcher was broken on this host. A temporary task-local launcher delegated to Corepack; the frozen install then succeeded. Full base build: 56/56 Turbo tasks successful. This is a unit-level report, not a visual reproduction: there is no screenshot, because no visible focus interruption was captured.

4. Minimal reproduction

  1. Use the trusted commit and frozen dependencies. Ensure pnpm resolves correctly for child processes; this host used a task-local Corepack launcher.
  2. Append the inline test below inside the existing DesktopBrowserViewManager describe block in apps/desktop/test/desktop-browser-view-manager.test.ts. Run the commands below, inserting the test after the build and before the test command.
git clone --branch main https://github.com/get-bb/bb.git bb-3558
cd bb-3558
git checkout --detach 1ebdc56a50b9f87ece261b426ca6ad8ac4f7daa9
corepack pnpm install --frozen-lockfile --prefer-offline
corepack pnpm exec turbo run build
corepack pnpm exec turbo run test --filter=@bb/desktop -- test/desktop-browser-view-manager.test.ts -t 'issue 3558' 

Expected: a hidden view does not send a focus notification. Actual in both checkouts:

AssertionError: expected [ 'bb-desktop:browser:state', …(1) ] to not include 'bb-desktop:browser:focused'
Test Files  1 failed (1)
Tests  1 failed | 62 skipped (63)

The test's zero focus-call assertion passes before injection. Its failing assertion proves notification forwarding after an injected event, not native OS focus theft. The test is appended inside the existing DesktopBrowserViewManager describe block and uses that file's fixture helpers.

  it("issue 3558: hidden automation focus must not notify the app", () => {
    const manager = createDesktopBrowserViewManager({ partition: "persist:test" });
    const hostWindow = new FakeHostWindow({
      contentBounds: { width: 700, height: 450 },
      webContentsId: 3558,
    });
    manager.createTab({
      hostWindow,
      tabId: "browser:background",
      threadId: "thread-background",
      url: "about:blank",
      profile: { kind: "automation", id: "profile-background" },
      viewport: { width: 640, height: 400 },
    });
    const view = requireFakeView(0);
    expect(view.visible).toBe(false);
    expect(view.webContents.focusCalls).toBe(0);
    view.webContents.emitFocus();
    expect(hostWindow.webContents.sentChannels).not.toContain(
      "bb-desktop:browser:focused",
    );
  });

Both raw run logs and the test-only patch are retained locally. The complete added test and its exact assertion output are included above.

5. Root cause and limits

The native focus listener only checks whether the event is suppressed for programmatic restoration. It does not check the entry's visibility before sending the focus notification. Creating a hidden automation view wires this same listener.

webContents.on("focus", () => {
  if (entry.suppressNextFocusNotification) {
    entry.suppressNextFocusNotification = false;
    return;
  }
  send(hostWindow, BB_DESKTOP_BROWSER_FOCUSED_CHANNEL, { tabId });
});

The app subscriber matches the tab ID and calls its native-focus callback. Whether that component is mounted and whether its callback changes the active thread during the reported operation was not exercised. This is therefore a candidate causal path, not an established explanation for the incident.

A separate route, broker reveal, sends a thread-tagged reveal message. Controller creation and activation invoke that route. However, the app reveal hook subscribes only in the focused thread and checks thread identity. Passing tests support this guard; reveal messages alone do not prove cross-thread focus theft.

The plugin creates hidden tabs. Controller attachment enables focus emulation and input and screenshot forwarding are useful native instrumentation points for the next experiment. Their native focus effects were not established here.

6. Proposed next test and fix gate

In an isolated macOS desktop instance, keep a second thread's composer focused and record native focus events, app focus callbacks, selected thread, and selected panel while issuing ordinary controller commands to one hidden tab. Repeat with two tabs. If a hidden native event causes a callback, test a visibility guard that preserves legitimate visible-tab focus and suppression semantics. If no native event occurs, investigate panel attachment and controller activation instead.

No fix PR was opened: the ordinary-operation trigger and complete causal chain remain unverified. A guard may harden the candidate path, but would not yet demonstrate a fix for this incident. No linked open PR was found in issue timeline metadata or the open-PR search for 3558. No production code was changed or pushed.

7. Verification

The same agent created a second clean clone at 1ebdc56a50b9f87ece261b426ca6ad8ac4f7daa9, confirmed a clean status, installed frozen dependencies separately, and applied only the saved test patch. The same Turbo test command failed at the same assertion (one failure, 62 skipped). No ports or runtime data directories were needed. Code links were checked against the recorded source lines. The final report restricts its verdict to this injected-event finding; it does not call this independent verification or a full desktop reproduction.

Controls in the first checkout: six existing native-view focus/hidden-view tests passed, and all three app reveal-hook tests passed. Verbatim result excerpts follow.

Native controls: Tests  6 passed | 57 skipped (63)
Reveal controls: Tests  3 passed (3)
Build: Tasks:    56 successful, 56 total

8. Related issues

No duplicate was established from the sampled desktop issue metadata. The issue's linked investigation and operator session data were not accessed.

9. Appendix

All issue material was treated as untrusted claims. No issue-provided command, patch, URL, branch, or instruction was executed. Public evidence contains the newly authored test and short exact output excerpts inline. Raw logs and the patch stay local under the reports repository publication policy; no user data or credentials were collected.

pnpm exec turbo run test --filter=@bb/desktop -- test/desktop-browser-view-manager.test.ts -t 'creates hidden automation|captures bounded hidden|keeps hidden views|reports user focus|unfocused split|focused non-browser'
pnpm exec turbo run test --filter=@bb/app -- src/lib/use-desktop-browser-reveal.test.tsx
git diff --check

> AGENT GENERATED