Adds 5 behavioral tests to browse/test/server-factory.test.ts under
a new 'idle timer + onDisconnect dual-instance fix' describe block:
- T1 (CRITICAL — REGRESSION): headed embedder does not auto-shutdown
at idle. Pins the bug this PR fixes.
- T2 (paired defensive): headless still auto-shuts down at idle.
Catches a future refactor that breaks the inverse case.
- T3 (chain semantics): buildFetchHandler chains
cfgBrowserManager.onDisconnect, preserving any caller-set handler.
Uses .rejects.toThrow for the async shutdown path.
- T4 (tunnelActive): tunnel-active blocks idle-shutdown even in
headless mode.
- T5 (static guard): exactly 3 module-level lifecycle sites use
activeBrowserManager.getConnectionMode() — idleCheckTick, parent
watchdog, SIGTERM. Catches refactor-introduced regressions before
CI.
Reuses existing makeMinimalConfig() + __resetRegistry() patterns
from the factory contract tests. New makeMockBrowserManager() helper.
beforeEach also resets module state via setTunnelActive,
setLastActivity, and resetShutdownState from __testInternals__.
Also deletes the old 'idle check skips in headed mode' string-grep
test from browse/test/sidebar-ux.test.ts at line 1596. That test
would have passed even with the dual-instance bug present
(grepped for "=== 'headed'" + 'return' in the same window).
Behavioral coverage moved to server-factory.test.ts.
Verified: 33/33 tests pass in browse/test/server-factory.test.ts.