From e96fd826c62ccdf0ca7e5667d7589f85aeaca207 Mon Sep 17 00:00:00 2001 From: Connor Tsui Date: Tue, 8 Sep 2026 11:37:29 -0400 Subject: [PATCH] Wait one second before hover prefetch Signed-off-by: Connor Tsui --- docs/architecture/design-decisions.md | 2 +- docs/architecture/performance.md | 2 +- web/components/Chart.loading.test.tsx | 8 ++++---- web/lib/chart-format.test.ts | 4 ++-- web/lib/chart-format.ts | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/architecture/design-decisions.md b/docs/architecture/design-decisions.md index bf06fe1..bb86694 100644 --- a/docs/architecture/design-decisions.md +++ b/docs/architecture/design-decisions.md @@ -158,7 +158,7 @@ v3 auto-queued a background `?n=all` fetch for every chart on group open; on a 22-chart group that queued tens of megabytes nobody asked for, contending with the windowed fetches a user actually waits on. v4 removed the auto-warmup: full history loads only on a deliberate per-chart signal — a window-chip click, a -~600ms hover dwell, or a pan/zoom into the unloaded region. +~1000ms hover dwell, or a pan/zoom into the unloaded region. → `web/components/Chart.tsx`, `web/lib/chart-format.ts`. **Bounded windows render on the full-length virtual x-axis.** diff --git a/docs/architecture/performance.md b/docs/architecture/performance.md index ef11dc8..8fe8a73 100644 --- a/docs/architecture/performance.md +++ b/docs/architecture/performance.md @@ -182,7 +182,7 @@ per-chart signal: windowed → loading → complete → error/retry state machine, so the partial view is never silent and a failed load is retryable. Charts with fewer than 100 commits are born complete and show no chip. -- **A ~600 ms hover *dwell*** (`HOVER_DWELL_MS`) starts a silent prefetch at a +- **A ~1000 ms hover *dwell*** (`HOVER_DWELL_MS`) starts a silent prefetch at a mid-tier priority (`HOVER_PREFETCH_PRIORITY = 500_000`, between idle background `0` and a direct `INTERACTION_FULL_PRIORITY = 1_000_000`), so a deliberate hover has data ready while a mouse sweep across the page fetches nothing. diff --git a/web/components/Chart.loading.test.tsx b/web/components/Chart.loading.test.tsx index 7517e74..cc1162b 100644 --- a/web/components/Chart.loading.test.tsx +++ b/web/components/Chart.loading.test.tsx @@ -227,7 +227,7 @@ describe('Chart opt-in full-history loading', () => { vi.useFakeTimers(); card.dispatchEvent(new Event('pointerenter')); await act(async () => { - await vi.advanceTimersByTimeAsync(599); + await vi.advanceTimersByTimeAsync(999); }); expect(fetchCalls.some((u) => u.includes('n=all'))).toBe(false); await act(async () => { @@ -246,7 +246,7 @@ describe('Chart opt-in full-history loading', () => { }); card.dispatchEvent(new Event('pointerleave')); await act(async () => { - await vi.advanceTimersByTimeAsync(600); + await vi.advanceTimersByTimeAsync(1000); }); expect(fetchCalls.some((u) => u.includes('n=all'))).toBe(false); }); @@ -275,7 +275,7 @@ describe('Chart opt-in full-history loading', () => { vi.useFakeTimers(); card.dispatchEvent(new Event('pointerenter')); await act(async () => { - await vi.advanceTimersByTimeAsync(700); + await vi.advanceTimersByTimeAsync(1100); }); expect(fetchCalls.filter((u) => u.includes('n=all')).length).toBe(before); }); @@ -315,7 +315,7 @@ describe('Chart opt-in full-history loading', () => { vi.useFakeTimers(); card.dispatchEvent(new Event('pointerenter')); await act(async () => { - await vi.advanceTimersByTimeAsync(601); + await vi.advanceTimersByTimeAsync(1001); }); vi.useRealTimers(); // The `?n=all` upgrade drains through the full-history queue across several diff --git a/web/lib/chart-format.test.ts b/web/lib/chart-format.test.ts index d5254e2..be588dd 100644 --- a/web/lib/chart-format.test.ts +++ b/web/lib/chart-format.test.ts @@ -679,8 +679,8 @@ describe('clampRangeWindow', () => { }); describe('hover-dwell prefetch constants', () => { - it('dwell is a deliberate ~600ms pause, not an accidental sweep', () => { - expect(HOVER_DWELL_MS).toBe(600); + it('dwell is a deliberate one-second pause, not an accidental sweep', () => { + expect(HOVER_DWELL_MS).toBe(1000); }); it('hover-prefetch priority sits above background (0) and below direct interaction', () => { diff --git a/web/lib/chart-format.ts b/web/lib/chart-format.ts index c0c9bb0..bce2ff9 100644 --- a/web/lib/chart-format.ts +++ b/web/lib/chart-format.ts @@ -45,7 +45,7 @@ export const HOVER_PREFETCH_PRIORITY = 500_000; /** How long the pointer must rest on one chart card before the silent * full-history prefetch starts, so a mouse sweep across the page fetches * nothing while a deliberate hover has data ready by the time the user acts. */ -export const HOVER_DWELL_MS = 600; +export const HOVER_DWELL_MS = 1000; /** Per-fetch timeout (ms) for the chart `?n=100` / `?n=all` requests. A stalled * request aborts at this bound instead of spinning the loading indicator * forever. 30s is generous headroom over a cold Vercel function first-hit