perf(web): reduce dashboard rendering cost and spectrum payloads#133
Note
🤖 GPT-6.1-Sol on behalf of Oliver
Round 3 review fixes
Restore a stable Svelte-generated ID prefix for every direct DOM chart host. Without it, duplicate SVG clip IDs made spectra and file plots resolve another chart's clip rectangle, removing high-alpha bands. The fix keeps the dense canvas and direct host. Regression coverage checks document resolution and uniqueness across dashboard charts, theme changes and file analyses. Restacking retains the calendar/stroke/legend fixes from #131.
Own-tip verification: format, lint, typecheck, production build, 235 web tests and 74 Playwright tests passed. Human review: inspect full upper spectrum bands, coverage, theme repaint and file plots. The public before/after clipping sheet uses illustrative fixture observations; real v5 sheets remain local. The final combined-stack performance comparison is recorded in #135; this layer's earlier shipping measurements remain historical checkpoints.
The TanStack migration increased dashboard render time and retained heap. This layer mounts charts directly, reduces chart DOM and formatting work, trims client validation code, requests only the displayed spectrum side, and removes duplicate file-detail loads. Default all-chart readiness falls from 4271.3 to 2934.3 ms and retained heap from 29.9 to 18.2 MiB against layer 3. Every plotted observation remains available for interaction and accessibility summaries.
Layer 4, based on feat/tanstack-charts in #131, following #130 and #129. Eight optimization commits, each with its measured effect and a passing production build. Nothing merged.
Shipping performance
Fresh production export and benchmark after the lifecycle and coverage-hover fixes. Same read-only v5 dataset, June 1 2025 through October 6 2026, five measured API runs with one discarded warmup, three fresh Chromium contexts per page, 1280×800 viewport, no throttling, one-second settling and explicit GC. All 35 API cases and 18 browser loads passed with zero errors. No QA, build or development work overlapped the measurement. Pre-existing development processes were paused for the run and then resumed.
| Metric | Original | Layer 3 | Shipping | vs original | vs layer 3 |
|---|---|---|---|---|---|
| Total JS raw, KiB | 711.6 | 631.6 | 588.8 | -17.3% | -6.8% |
| Total JS gzip, KiB | 228.1 | 202.4 | 191.1 | -16.2% | -5.5% |
| Total CSS gzip, KiB | 10.5 | 10.5 | 10.6 | +1.1% | +0.4% |
| Dashboard default FCP/LCP p50, ms | 136.0 | 120.0 | 136.0 | +0.0% | +13.3% |
| Dashboard visible charts p50, ms | 509.1 | 569.3 | 477.2 | -6.3% | -16.2% |
| Dashboard visible charts p95, ms | 642.6 | 571.4 | 517.7 | -19.4% | -9.4% |
| Dashboard all charts p50, ms | 3258.9 | 4271.3 | 2934.3 | -10.0% | -31.3% |
| Dashboard observed initial TBT p50, ms | 130.0 | 159.0 | 114.0 | -12.3% | -28.3% |
| Dashboard retained heap p50, MiB | 18.3 | 29.9 | 18.2 | -0.8% | -39.2% |
| Six-month visible charts p50, ms | 456.3 | 489.6 | 439.1 | -3.8% | -10.3% |
| Six-month all charts p50, ms | 2722.8 | 3183.8 | 2538.7 | -6.8% | -20.3% |
| Filtered hourly visible charts p50, ms | 400.3 | 435.1 | 393.2 | -1.8% | -9.6% |
| Filtered hourly all charts p50, ms | 2691.2 | 3205.1 | 2443.1 | -9.2% | -23.8% |
| File detail LCP p50, ms | 744.0 | 684.0 | 424.0 | -43.0% | -38.0% |
| File detail charts p50, ms | 729.7 | 673.3 | 418.3 | -42.7% | -37.9% |
| File detail observed initial TBT p50, ms | 411.0 | 336.0 | 125.0 | -69.6% | -62.8% |
| File detail retained heap p50, MiB | 14.6 | 8.1 | 6.8 | -53.7% | -16.9% |
| Traffic default API p50, ms | 30.0 | 37.3 | 32.1 | +7.0% | -13.8% |
| Traffic default API p95, ms | 35.2 | 37.9 | 36.5 | +3.6% | -3.6% |
| Spectrum both sides default API p50, ms | 61.9 | 76.0 | 77.3 | +24.7% | +1.7% |
| Spectrum both sides default API p95, ms | 87.2 | 90.6 | 81.6 | -6.4% | -10.0% |
| Structure default API p50, ms | 102.5 | 116.3 | 121.5 | +18.5% | +4.4% |
| Structure default API p95, ms | 110.7 | 133.7 | 157.6 | +42.3% | +17.9% |
Readiness uses [data-chart-rendered="true"]. All-chart timing includes scrolling, settling and GC. Observed TBT is the harness observation-window metric, not Lighthouse. Three page samples limit timing claims; the retained-heap gain over the original baseline is only 0.8%. FCP/LCP matches the original but is slower than layer 3. The full-spectrum and structure API medians are also slower; this PR does not establish a general query-latency improvement. Their full all-router payloads remain 2969.7 and 4882.4 KiB.
Separately, independent QA measured the default selected-source spectrum response at 860.8 KiB with both sides versus 414.6 KiB with source projection, a 51.8% reduction. Destination projection is 521.4 KiB. These selected-source figures describe the dashboard request, not the benchmark's full all-router API request.
Optimizations ranked by impact
The ranking reflects the recorded render, memory and payload effects. Checkpoint timings precede the final QA fixes, include three-sample noise, and are not additive isolated shipping effects.
- Direct DOM mount and owned interaction snapshot. Replace the Svelte adapter's chart prerender and separate reactive sizing pass with a single TanStack DOM host in an attachment. The mount checkpoint reduced default all-chart readiness from 4280.4 to 3163.2 ms and retained heap from 30.1 to 22.9 MiB; file readiness fell from 654.3 to 487.1 ms. The final owned snapshot also releases callback-only derived dependencies during teardown.
- Dense spectrum rasterization. Above 2048 points, paint every dot directly at device pixel ratio while retaining every scene observation, color, order and bucket identity. Controlled 9870-mark renderer sample: 145 to 29 ms render, 229 to 87.5 ms presentation, and 9906 to 38 DOM nodes. Dense checkpoint all-chart readiness fell from 3133.7 to 2817.0 ms and heap from 21.1 to 19.0 MiB. This painter avoids the color-resolution overhead of the earlier native-canvas experiment.
- Active-only focus rings. Generate a ring for the focused observation rather than retaining hidden per-point ring geometry. Exploratory checkpoint heap fell from 22.9 to 21.1 MiB and observed TBT from 153 to 107 ms. That checkpoint preceded the corrected primary-focus resolver; the corrected code passed the shipping QA and e2e suite.
- Zod Mini. Preserve URL fallback/serialization and dataset response validation through Mini's functional API. Fresh-export gzip JS fell from 201.3 to 191.1 KiB, saving 10.2 KiB. Gregorian and leap-year regressions cover validation equivalence.
- Spectrum side projection. Decode only the displayed side, with side-scoped cancellation/cache keys. Default selected-source payload shrank 51.8%. Projection checkpoint heap fell from 18.5 to 18.1 MiB; visible readiness from 478.9 to 455.9 ms.
- One file-detail request per navigation. Use
afterNavigatefor initial, URL and history loads. Initial, next, back, reload and retry each issue one details request. Shipping file readiness is 418.3 ms versus the projection checkpoint's 429.8 ms; observed TBT is 125 versus 129 ms. The larger file gains in the table also include renderer changes. - Coverage serialization batching. Replace roughly 1185 coverage SVG DOM rectangles with disconnected paths while retaining native scene rectangles for interval hit testing. Pre-fix checkpoint heap fell from 18.8 to 18.7 MiB; all-chart timing from 2860.7 to 2817.0 ms. The final geometry fix is included in shipping measurements.
- Temporal labels and layout formatting. Format once per bucket, reuse exact tick strings, skip irrelevant alpha scans and share legend bounds reads. Checkpoint file readiness fell from 448.8 to 429.8 ms and heap from 19.0 to 18.8 MiB. Dashboard timing varied upward, so no independent dashboard-latency gain is claimed.
Semantic and API decisions needing review
addressSide=source|destinationis opt-in. Omission preserves the full API. Projection returns the requested spectrum unchanged and the other array empty. Both-side SQL membership, maximum bucket end, coverage, null/empty buckets and half-open windows remain intact. SQLite and D1 tests include unequal sides and an opposite-side-only bucket. Storage and rollups do not change.- Direct DOM mount removes adapter-generated chart SVG from SSR. Interactive readiness and summaries still publish after painting. Review compact resizing, teardown, crosshair/brush subscriptions and the owned observation snapshot.
- Dense spectrum dots use a canvas within the SVG; axes, focus, sparse/file plots and interactions retain TanStack/SVG. There is no sampling. Review DPR behavior and this rendering boundary.
- Coverage batching affects SVG serialization only. Native rectangle geometry remains in the scene. Partial dashes, unknown observations, known zero, interval identity and ratios retain their meaning.
- Zod Mini keeps validation policy unchanged. Review functional catch/pipe/transform conversion and dataset parsing.
Verification and human review guide
Automated verification passed: bun run format, bun run lint, bun run typecheck, bun run test:web with 220 tests, and bun run test:e2e with 70 tests. New regressions cover wide-interval pointer hover and retained DOM/listeners across six explicit-GC filter transitions. Every final optimization commit was production-built during autosquash. The final tree matches the clean shipping-measurement tree.
Independent Chromium QA covered all eight dashboard cards and 12 file charts, both themes, 390/768/1280/1920px layouts, all controls, hover/keyboard/legends, brushes/drilldown/mirroring, URL/history, empty/unknown bounds, failures/retries and cancellation. Numerical checks matched 40 series and 14 tooltip/stacking assertions to API values. Canvas auditing matched all 6652 real observations, positions, colors, radii and paint order at DPR 1/2 and every tested width; the independently reconstructed raster matched exactly.
QA found two S2 regressions, both fixed and independently rechecked: wide-interval hover and detached chart retention. The fixed 30-transition stress kept 251 listeners and bounded DOM counts, with later heap samples around 19 MB rather than the former roughly 4.5 MiB growth per cycle. Home teardown left zero chart hosts. Later fixed coverage, lifecycle, side-cancellation, retry and layout/error-recovery reports have zero errors. The older pending-status report is superseded by those fixed artifacts.
For human review:
- On perf :8090, open the default dataset window and scroll all eight cards. Check lazy activation, dense spectrum, resizing and both themes. Switch spectrum side/family/source, then revisit a cached window and rapidly change direction.
- Use a one-day daily window and hover coverage near the start, middle and end of a lane. Values should persist throughout the interval. Inspect partial/unknown boundaries and known-zero fixture observations.
- Toggle legends, explore with arrows/Home/End, use Shift+Arrow with Enter/Escape, and brush/drill down. Confirm shared ranges/crosshairs and URL history survive filter changes.
- Open a populated file, inspect all spectrum/structure charts and SD bars, then Next, Back, reload and retry. Expect one details request per navigation and unchanged numerical tooltips.
- Review the API and rendering decisions above. Full screen-reader, touch hardware, Firefox and WebKit checks remain manual. Real populated alerts and TTL data are unavailable; populated-alert behavior remains fixture-covered.
Inherited selection persistence, narrow file text, lookup/date feedback, file titles and keyboard layout gestures remain for later layers. #104 tracks the separate DST evidence issue.
Only perf :8090 was redeployed. The production test container on :8080 is unchanged, the source database metadata is unchanged and the perf bind mount remains read-only. No Cloudflare operations occurred. Private screenshots, API captures and heap snapshots remain local. Shipping artifacts and comparison are under /tmp/atlantis-frontend-overhaul/perf/layer4-shipping/.
Changes made by GPT-6.1-Sol through the Codex harness in T3 Code.
Checks
- SuccessfulPlaywright E2EGitHub
- SuccessfulWeb ChecksGitHub
- SuccessfulRust Pipeline ChecksGitHub
Added 9 commits
- perf(web): paint focus rings only for focused observations45e8f36
- perf(web): mount charts directly through the DOM host9ce3c27
- perf(web): rasterize dense spectrum marks without samplingcc6b52f
- perf(web): reuse temporal labels and layout formatting45c3708
- perf(web): load file details once per navigation6212a7e
- perf(web): use Zod Mini for client validation63b43c9
- perf(web): request only the displayed spectrum side72e556f
- fix(web): isolate clip paths for each chart instancec822202
- perf(web): batch coverage geometry while retaining bucket observationsde594e1