test(crash-reporting): cover speech churn breadcrumb name-coalescing

The churn breadcrumb's registration in COALESCED_RENDERER_BREADCRUMB_NAMES and
NAME_ONLY_COALESCED_BREADCRUMB_NAMES had no test: the storm test only asserted
the constant equals its own literal. Removing either registration kept the whole
suite green.

It carries no message field, so without the name-only entry
rendererBreadcrumbCoalesceKey returns undefined and every firing takes its own
ring slot — the eviction this breadcrumb exists to avoid.
This commit is contained in:
Neil
2026-08-02 01:04:34 -07:00
parent 2a86089b0d
commit 88558fe48b
@@ -275,6 +275,27 @@ describe('renderer breadcrumb IPC routing', () => {
}
})
// Why: each window emits its own churn notice with a different payload, so
// coalescing by name is what keeps a download storm to one ring slot. Without
// the registration these carry no message and fall through uncoalesced —
// evicting the pre-crash trail this breadcrumb exists to sit beside.
it('coalesces speech model-state churn by name across windows', () => {
emitRendererBreadcrumb({
name: 'speech_model_state_churn',
data: { refreshes: 250, noOpRefreshes: 249, windowMs: 4200 }
})
emitRendererBreadcrumb({
name: 'speech_model_state_churn',
data: { refreshes: 250, noOpRefreshes: 12, windowMs: 3100 }
})
expect(recordCrashBreadcrumbMock).not.toHaveBeenCalled()
expect(recordCoalescedCrashBreadcrumbMock).toHaveBeenCalledTimes(2)
for (const call of recordCoalescedCrashBreadcrumbMock.mock.calls) {
expect(call[0]).toMatchObject({ coalesceKey: 'speech_model_state_churn' })
}
})
// Why kind-scoped: a routine post-wake atlas reset must never suppress the
// context-loss crumb that says the driver gave up on this renderer.
it('coalesces WebGL diagnostics per kind so one kind cannot mask another', () => {