From 628cc5722cb33372fd66e930503e6554a2790eab Mon Sep 17 00:00:00 2001 From: jay Date: Thu, 11 Jun 2026 19:23:33 -0400 Subject: [PATCH] =?UTF-8?q?Reliability:=20slow=20=E2=89=A0=20failed=20?= =?UTF-8?q?=E2=80=94=20SW=20nav=20timeout,=20slow-boot=20telemetry,=20de-b?= =?UTF-8?q?ot=20stats?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Root cause of the intermittent white screen: the shell HTML is no-cache (cf-cache-status: DYNAMIC), so every page-open does a synchronous round-trip to the residential origin before any pixel renders — and the SW's network-first navigation only fell back to the cached shell on REJECTION, never on slowness. A stalled fetch meant staring at white with a perfectly good shell in cache. The boot seatbelt couldn't see it either: it lives inside the HTML that hadn't arrived yet, so slow boots left no telemetry. - service-worker: race navigation fetch vs 2.5s grace timer. Network wins → fresh HTML as before; timer/5xx/failure → cached shell instantly, network response still refreshes the cache in the background. Safe due to the 14-day immutable-chunk grace window. Caps the white screen at ~2.5s for repeat visitors on any network. - app.html: beacon `boot-slow: Nms (html Nms) on 4g` when mount takes >4s — the "white screen, then it loaded" glitches finally leave a trace, with HTML-arrival timing to separate slow-origin from slow-JS. - admin: bot UAs (HeadlessChrome/bot/spider/crawl/…) excluded from the headline "Load errors today" count — throttled crawlers trip the 10s boot check routinely (the one recorded error was HeadlessChrome on X11, not a phone). Bots stay visible in the list, tagged + dimmed. Tests: telemetry test extended for bot flag + filtered counts. 223 pytest + 11 vitest green. Co-Authored-By: Claude Opus 4.8 --- frontend/src/app.html | 15 ++++++++++ frontend/src/routes/admin/+page.svelte | 9 ++++-- frontend/src/service-worker.js | 39 ++++++++++++++++++-------- goodnews/api.py | 4 ++- goodnews/queries.py | 25 +++++++++++++++-- tests/test_admin.py | 9 ++++++ 6 files changed, 84 insertions(+), 17 deletions(-) diff --git a/frontend/src/app.html b/frontend/src/app.html index 0fb597d..3d39fbc 100644 --- a/frontend/src/app.html +++ b/frontend/src/app.html @@ -61,6 +61,21 @@ var el = document.getElementById('boot-fallback'); if (el && el.parentNode) el.parentNode.removeChild(el); try { sessionStorage.removeItem('ub_reloaded'); } catch (e) {} + // Slow-but-successful boots (the "white screen, then it loaded" glitch) + // would otherwise leave no trace — beacon the timing so they're visible. + // performance.now() counts from navigation start, so a slow-arriving + // HTML document is included, not just slow JS. + try { + var ms = Math.round(performance.now()); + if (ms > 4000) { + var nav = performance.getEntriesByType && performance.getEntriesByType('navigation')[0]; + var detail = 'boot-slow: ' + ms + 'ms'; + if (nav && nav.responseStart) detail += ' (html ' + Math.round(nav.responseStart) + 'ms)'; + if (navigator.connection && navigator.connection.effectiveType) + detail += ' on ' + navigator.connection.effectiveType; + report(detail); + } + } catch (e) { /* timing is best-effort */ } }; addEventListener('vite:preloadError', function (e) { report('preloadError: ' + ((e && e.payload && e.payload.message) || '')); diff --git a/frontend/src/routes/admin/+page.svelte b/frontend/src/routes/admin/+page.svelte index 0c79079..bd19ed5 100644 --- a/frontend/src/routes/admin/+page.svelte +++ b/frontend/src/routes/admin/+page.svelte @@ -458,9 +458,9 @@

Recent load errors (last {clientErrors.length})