fix(crash-reporting): coalesce the duplicate-tab-owner breadcrumb

Its renderer guard is once-per-tab-id, so the stale worktree map it exists to
diagnose duplicates every tab id at once and could evict the whole 30-entry
ring. Also drops two keyed re-reads of tabsByWorktree that would throw for a
prototype-named worktree id, and pins the activeTabIdByWorktree guard with a
test that fails without it.

Co-authored-by: Orca <help@stably.ai>
This commit is contained in:
Neil
2026-08-01 04:58:21 -07:00
co-authored by Orca
parent 46e7da1816
commit dd1aae641e
3 changed files with 36 additions and 9 deletions
+7 -1
View File
@@ -331,6 +331,7 @@ const COALESCED_RENDERER_BREADCRUMB_NAMES = new Set([
'renderer_unhandled_rejection',
'terminal_park_verdict_churn',
'terminal_safe_fit_retry_exhausted',
'terminal_tab_id_owned_by_multiple_worktrees',
TERMINAL_WEBGL_DIAGNOSTIC_BREADCRUMB
])
const RENDERER_BREADCRUMB_COALESCE_MS = 30_000
@@ -343,9 +344,14 @@ const RENDERER_BREADCRUMB_COALESCE_MS = 30_000
// mounted pane within ~60ms. Windows crash F0BKR84AHEH lost 26-90% of its
// 30-entry ring to two such bursts. `suppressedSinceLast` keeps the pane count
// — the only signal these carry — in one slot.
//
// terminal_tab_id_owned_by_multiple_worktrees: its renderer-side guard is
// once-per-tab-id, not once-per-session, so one stale worktree map duplicates
// every tab id at once and emits a crumb per tab.
const NAME_ONLY_COALESCED_BREADCRUMB_NAMES = new Set([
'terminal_park_verdict_churn',
'terminal_safe_fit_retry_exhausted'
'terminal_safe_fit_retry_exhausted',
'terminal_tab_id_owned_by_multiple_worktrees'
])
function rendererBreadcrumbCoalesceKey(
@@ -115,6 +115,27 @@ describe('active-terminal repair effect cannot drive a React #185 update loop',
expect(useAppStore.getState().activeTabIdByWorktree['wt-active']).toBe('t1')
})
it('does not reallocate activeTabIdByWorktree when the tab is already active', () => {
// Why: that map is a dependency of both the repair effect and the parked
// watcher sync, so a redundant activation must not re-run either.
useAppStore.setState({
activeWorktreeId: 'wt-active',
activeTabType: 'terminal',
activeTabId: 't1',
activeTabIdByWorktree: {},
tabsByWorktree: { 'wt-active': [terminalTab('t1', 'wt-active')] },
unifiedTabsByWorktree: {}
})
act(() => {
useAppStore.getState().setActiveTab('t1')
})
const settled = useAppStore.getState().activeTabIdByWorktree
act(() => {
useAppStore.getState().setActiveTab('t1')
})
expect(useAppStore.getState().activeTabIdByWorktree).toBe(settled)
})
it('keeps bell attribution off a background worktree tab', () => {
useAppStore.setState({
activeWorktreeId: 'wt-active',
@@ -23,6 +23,9 @@ export function resolveActiveTabOwnerWorktreeId(
): string | null {
let firstOwnerId: string | null = null
let ownerCount = 0
// Why tracked in-loop rather than re-read by key: `tabsByWorktree[activeWorktreeId]`
// resolves inherited members for ids like `toString`, and `?.some` would then throw.
let activeWorktreeOwnsTab = false
for (const [worktreeId, tabs] of Object.entries(tabsByWorktree)) {
if (!tabs.some((tab) => tab.id === tabId)) {
continue
@@ -31,6 +34,9 @@ export function resolveActiveTabOwnerWorktreeId(
if (firstOwnerId === null) {
firstOwnerId = worktreeId
}
if (worktreeId === activeWorktreeId) {
activeWorktreeOwnsTab = true
}
}
// Why breadcrumb: no production origin for a duplicated tab id is known yet,
@@ -39,17 +45,11 @@ export function resolveActiveTabOwnerWorktreeId(
reportedDuplicateTabIds.add(tabId)
recordRendererCrashBreadcrumb('terminal_tab_id_owned_by_multiple_worktrees', {
ownerCount,
resolvedToActiveWorktree: Boolean(
activeWorktreeId && tabsByWorktree[activeWorktreeId]?.some((tab) => tab.id === tabId)
)
resolvedToActiveWorktree: activeWorktreeOwnsTab
})
}
if (
ownerCount > 1 &&
activeWorktreeId &&
tabsByWorktree[activeWorktreeId]?.some((tab) => tab.id === tabId)
) {
if (ownerCount > 1 && activeWorktreeId && activeWorktreeOwnsTab) {
return activeWorktreeId
}
return firstOwnerId