perf(dash-apps): lightweight jsdom regression gate - #183
Merged
Conversation
dkneeland
marked this pull request as draft
July 29, 2026 01:29
dkneeland
force-pushed
the
feat/dashapp-perf-gate-100
branch
3 times, most recently
from
July 29, 2026 02:10
e5baf1c to
b7bd724
Compare
A CI gate that runs on every PR touching dash-apps/** and trips when a dashboard's onCarStateUpdate does too much DOM work per frame. Gate replays a deterministic 6 s drive (150 frames at 25 Hz) in jsdom. Per-tick MutationObserver records are grouped by target.parentNode (rendered as #id, .class, or tagname). Any single parent that sees >= 6 child updates per frame for 3 consecutive frames (after a 50-frame warmup) fails the gate. Verdict targets the failure mode that actually occurred: per-child update loops rewriting attributes on every sibling, every tick (the web-retro regression at 0a32362). Design: - 114-line gate.js — Proxy NativeCarState with convention-based key derivation (getEgoSpeed-egoSpeed), no getter list to sync with Kotlin - Script-inliner: no HTTP server, reads <script src> from disk - 3-in-a-row streak instead of p95 — tighter on real regressions, ignores isolated CI-runner stalls - matchMedia shim for jsdom - 46-line test, 2 fixtures (fast-app PASS, churn-app FAIL), 32-line workflow - 1 dep (jsdom ^29.1.1) - CI matrix is the single source of truth for which apps are gated (no manifest perf field duplication) Author-facing message leads with impact, names the offending element, and gives a concrete fix instruction: FAIL app — may cause dashboard lag (driver sees stale speed/blinkers) .steer-strip: 22 child updates per frame (max 6) Fix: update .steer-strip once instead of each child Matrix: web-retro, web-analog, web-ambient. Not gated: web-vanilla (WASM/canvas invisible to jsdom tripwire), web-expo (React Native bridge does not match the window.onCarStateUpdate contract the gate replays). Verified: 3/3 tests pass; web-retro, web-analog, web-ambient pass; historic 0a32362 regression trips cleanly on .steer-strip at 22/tick.
dkneeland
force-pushed
the
feat/dashapp-perf-gate-100
branch
from
July 29, 2026 03:56
b7bd724 to
bd09a37
Compare
dkneeland
marked this pull request as ready for review
July 29, 2026 03:58
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
A CI gate that replays a 6 s drive (150 frames @ 25 Hz) in jsdom and trips when a dashboard's
onCarStateUpdatemutates too many child DOM elements per frame. Targets the actual web-retro regression class: per-child update loops (cells.forEach(c => c.className = next)).Feedback
Reach
dash-apps/_perf-gate/gate.js.github/workflows/dashapp-perf.ymlwindow.onCarStateUpdatecontract)Verified
npm test3/3. All 3 matrix apps pass. Historic 0a32362 regression trips on.steer-strip 22/tick.Tuning
All knobs (budget, streak, scenario, matrix) documented in
dash-apps/README.mdtuning map.