Skip to content

perf(web): reduce dashboard rendering cost and spectrum payloads - #133

Open
flamboh wants to merge 9 commits into
feat/tanstack-chartsfrom
perf/optimize
Open

flamboh wants to merge 9 commits into
feat/tanstack-chartsfrom
perf/optimize

Conversation

@flamboh

@flamboh flamboh commented Oct 6, 2026 •

Copy link
Copy Markdown
Owner

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.

  1. 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.
  2. 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.
  3. 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.
  4. 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.
  5. 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.
  6. One file-detail request per navigation. Use afterNavigate for 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.
  7. 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.
  8. 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|destination is 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.

Before and after: local chart clipping restores upper spectrum bands on illustrative public data

Mount through TanStack DOM in a Svelte attachment. Remove client prerender and a separate reactive resize pass. Keep responsive definitions, focus options, teardown and the positioned-observation contract. An owned interaction snapshot prevents lazy callback-only derived chains from retaining detached charts; repeated-filter GC stress verifies teardown.

Fixed-settings checkpoint versus QA-fixed layer 3: all charts 4280.4 -> 3163.2 ms, retained dashboard heap 30.1 -> 22.9 MiB; file readiness 654.3 -> 487.1 ms. The mount bundle inventory reused a directory and is invalid; later fresh exports and the final build validate bundle savings. Three browser samples per page.

Checkpoint measurements above predate the final QA lifecycle/coverage fixes and are not isolated shipping effects. Combined shipping benchmark: 477.2/2934.3 ms default visible/all charts, 114 ms observed initial TBT, 18.2 MiB retained heap and 191.1 KiB gzip JS. Original baseline: 509.1/3258.9 ms, 130 ms, 18.3 MiB, 228.1 KiB. Layer 3: 569.3/4271.3 ms, 159 ms, 29.9 MiB, 202.4 KiB. Baseline dates, five API runs, three fresh contexts per page and one warmup; no concurrent QA/build/dev work. Shipping artifacts: /tmp/atlantis-frontend-overhaul/perf/layer4-shipping/results.json. Full gates pass with 220 web and 70 e2e tests.
Generate the active focus guide instead of retaining a hidden SVG circle for every observation. Preserve primary point radius, fill and stroke. Hover does not reconstruct the scene.

Exploratory checkpoint after mount: dashboard heap 22.9 -> 21.1 MiB and initial observed TBT 153 -> 107 ms. This checkpoint preceded the corrected primary-focus resolver, so it is diagnostic rather than final interaction evidence. The corrected guide passed full e2e and final real-stage QA. Final series count/value/hover contracts are unchanged.

Checkpoint measurements above predate the final QA lifecycle/coverage fixes and are not isolated shipping effects. Combined shipping benchmark: 477.2/2934.3 ms default visible/all charts, 114 ms observed initial TBT, 18.2 MiB retained heap and 191.1 KiB gzip JS. Original baseline: 509.1/3258.9 ms, 130 ms, 18.3 MiB, 228.1 KiB. Layer 3: 569.3/4271.3 ms, 159 ms, 29.9 MiB, 202.4 KiB. Baseline dates, five API runs, three fresh contexts per page and one warmup; no concurrent QA/build/dev work. Shipping artifacts: /tmp/atlantis-frontend-overhaul/perf/layer4-shipping/results.json. Full gates pass with 220 web and 70 e2e tests.
Retain every finite observation, datum, color, position and bucket identity in the TanStack scene. Above 2048 points, paint dots directly at device pixel ratio inside the SVG mark group. Keep axes and focus SVG and sparse plots native SVG. Paint the full surface to preserve endpoint circles.

Controlled renderer microbenchmark, 9870 marks: native SVG render 145 -> 29 ms, presentation 229 -> 87.5 ms, DOM 9906 -> 38 nodes. Default dashboard checkpoint: all charts 3133.7 -> 2817.0 ms and heap 21.1 -> 19.0 MiB. Some exploratory checkpoint validation overlapped; the uncontended final benchmark is the shipping comparison. No sampling or aggregation.

Checkpoint measurements above predate the final QA lifecycle/coverage fixes and are not isolated shipping effects. Combined shipping benchmark: 477.2/2934.3 ms default visible/all charts, 114 ms observed initial TBT, 18.2 MiB retained heap and 191.1 KiB gzip JS. Original baseline: 509.1/3258.9 ms, 130 ms, 18.3 MiB, 228.1 KiB. Layer 3: 569.3/4271.3 ms, 159 ms, 29.9 MiB, 202.4 KiB. Baseline dates, five API runs, three fresh contexts per page and one warmup; no concurrent QA/build/dev work. Shipping artifacts: /tmp/atlantis-frontend-overhaul/perf/layer4-shipping/results.json. Full gates pass with 220 web and 70 e2e tests.
Format bucket labels once per bucket, cache repeated x-axis layout formatting within a definition, scan alpha bounds only for spectrum charts, and measure legend bounds once per publication.

Checkpoint after dense renderer: file readiness 448.8 -> 429.8 ms and heap 19.0 -> 18.8 MiB. Dashboard all-chart timing varied 2817.0 -> 2860.7 ms, so this checkpoint does not establish a dashboard latency improvement. Exact labels and series values are preserved.

Checkpoint measurements above predate the final QA lifecycle/coverage fixes and are not isolated shipping effects. Combined shipping benchmark: 477.2/2934.3 ms default visible/all charts, 114 ms observed initial TBT, 18.2 MiB retained heap and 191.1 KiB gzip JS. Original baseline: 509.1/3258.9 ms, 130 ms, 18.3 MiB, 228.1 KiB. Layer 3: 569.3/4271.3 ms, 159 ms, 29.9 MiB, 202.4 KiB. Baseline dates, five API runs, three fresh contexts per page and one warmup; no concurrent QA/build/dev work. Shipping artifacts: /tmp/atlantis-frontend-overhaul/perf/layer4-shipping/results.json. Full gates pass with 220 web and 70 e2e tests.
Batch same-state lane rectangles only during SVG serialization. Retain native scene rectangle hit geometry, every original interval, ratio and interaction point; keep partial dash segments and transparent unknown observations. QA caught wide-interval hover loss when batching scene nodes; serialization-only batching fixes it and has near-boundary/interior regressions.

Checkpoint after label reuse: default all charts 2860.7 -> 2817.0 ms and heap 18.8 -> 18.7 MiB. Remove roughly 1185 SVG DOM coverage rectangles on the real default dashboard, retaining scene rectangles for hit testing. Unit and browser checks retain interval and coverage semantics; checkpoint timing has three-sample limits.

Checkpoint measurements above predate the final QA lifecycle/coverage fixes and are not isolated shipping effects. Combined shipping benchmark: 477.2/2934.3 ms default visible/all charts, 114 ms observed initial TBT, 18.2 MiB retained heap and 191.1 KiB gzip JS. Original baseline: 509.1/3258.9 ms, 130 ms, 18.3 MiB, 228.1 KiB. Layer 3: 569.3/4271.3 ms, 159 ms, 29.9 MiB, 202.4 KiB. Baseline dates, five API runs, three fresh contexts per page and one warmup; no concurrent QA/build/dev work. Shipping artifacts: /tmp/atlantis-frontend-overhaul/perf/layer4-shipping/results.json. Full gates pass with 220 web and 70 e2e tests.
Use the tree-shakable functional Mini API for URL and dataset schemas. Preserve parsing, date validation, fallbacks and serialization, including leap-year boundary cases.

Fresh production export: total gzip JavaScript 201.3 -> 191.1 KiB, saving 10.2 KiB. Default heap 18.7 -> 18.5 MiB; all-chart timing varied 2817.0 -> 2845.6 ms. No validation policy changes.

Checkpoint measurements above predate the final QA lifecycle/coverage fixes and are not isolated shipping effects. Combined shipping benchmark: 477.2/2934.3 ms default visible/all charts, 114 ms observed initial TBT, 18.2 MiB retained heap and 191.1 KiB gzip JS. Original baseline: 509.1/3258.9 ms, 130 ms, 18.3 MiB, 228.1 KiB. Layer 3: 569.3/4271.3 ms, 159 ms, 29.9 MiB, 202.4 KiB. Baseline dates, five API runs, three fresh contexts per page and one warmup; no concurrent QA/build/dev work. Shipping artifacts: /tmp/atlantis-frontend-overhaul/perf/layer4-shipping/results.json. Full gates pass with 220 web and 70 e2e tests.
Add optional addressSide=source|destination response projection. Omission retains the full API. Keep both sides in row membership, grouping, MAX(bucket_end) and coverage queries. Decode only the requested blob and return the other array empty. Scope dashboard request/cancellation/window-cache keys to the side.

After Mini checkpoint: default visible/all charts 478.9/2845.6 -> 455.9/2805.9 ms, TBT 104 -> 98 ms, heap 18.5 -> 18.1 MiB. Real default selected-source decoded payload 860.8 -> 414.6 KiB, saving 51.8%. SQLite and D1 tests compare projection with full responses, including unequal sides and an opposite-side-only bucket. Stored schema, additive rollups, half-open windows and zero-fill are unchanged.

Checkpoint measurements above predate the final QA lifecycle/coverage fixes and are not isolated shipping effects. Combined shipping benchmark: 477.2/2934.3 ms default visible/all charts, 114 ms observed initial TBT, 18.2 MiB retained heap and 191.1 KiB gzip JS. Original baseline: 509.1/3258.9 ms, 130 ms, 18.3 MiB, 228.1 KiB. Layer 3: 569.3/4271.3 ms, 159 ms, 29.9 MiB, 202.4 KiB. Baseline dates, five API runs, three fresh contexts per page and one warmup; no concurrent QA/build/dev work. Shipping artifacts: /tmp/atlantis-frontend-overhaul/perf/layer4-shipping/results.json. Full gates pass with 220 web and 70 e2e tests.
Use afterNavigate for initial loads and URL/history changes. Remove the duplicate onMount fetch. Regression checks require one details request for initial load, next, back and reload, alongside existing retry coverage. Update chart architecture and e2e contract documentation.

Shipping build after lifecycle/coverage fixes versus projection checkpoint: file readiness 429.8 -> 418.3 ms, TBT 129 -> 125 ms; one initial details request instead of two. Shipping default visible/all readiness 477.2/2934.3 ms, TBT 114 ms, heap 18.2 MiB, total gzip JS 191.1 KiB. Original baseline 509.1/3258.9 ms, 130 ms, 18.3 MiB and 228.1 KiB. Three fresh browser samples; no overlapping validation.

Checkpoint measurements above predate the final QA lifecycle/coverage fixes and are not isolated shipping effects. Combined shipping benchmark: 477.2/2934.3 ms default visible/all charts, 114 ms observed initial TBT, 18.2 MiB retained heap and 191.1 KiB gzip JS. Original baseline: 509.1/3258.9 ms, 130 ms, 18.3 MiB, 228.1 KiB. Layer 3: 569.3/4271.3 ms, 159 ms, 29.9 MiB, 202.4 KiB. Baseline dates, five API runs, three fresh contexts per page and one warmup; no concurrent QA/build/dev work. Shipping artifacts: /tmp/atlantis-frontend-overhaul/perf/layer4-shipping/results.json. Full gates pass with 220 web and 70 e2e tests.
Belongs-in: #133 perf/optimize

The direct DOM host lost the Svelte adapter automatic ID prefix. Shared SVG clip IDs made spectrum, coverage and file charts resolve another plot clipping rectangle. Restore per-instance Svelte IDs while retaining the DOM host and dense canvas. Verify local clip resolution across dashboard plots, theme changes and file analyses.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant