3.7 KiB
Issue 007: Timers and Polling Cleanup
Summary
The / page creates multiple intervals and timeouts. They are not the dominant problem,
but they contribute to steady background work and can wake components even when hidden.
Severity
Low to medium.
Address after the larger structural issues unless a specific timer is found to be hot.
Affected Files
Known or likely timer users:
webui/src/components/AlertFeed/index.jsxwebui/src/components/ReplaySourcesPanel/index.jsxwebui/src/components/HudOverlays/TurnsOverlay/index.jsxwebui/src/components/RoverQueuesPanel/index.jsxwebui/src/components/ModeGateOverlay/index.jsxwebui/src/components/SocketConnectionPill/index.jsxwebui/src/controls/ControlContext.jsxhorn heat intervalwebui/src/controls/overcurrentLimiter.js
Evidence
Artifact:
perf/results/2026-06-11T03-22-44-714Z-root-runtime/root-runtime-report.json
In an 18s / audit at mobile viewport with 6x CPU throttle:
intervals created: 22
timeouts created: 11
interval fires: 148
timeout fires: 6
Most common timer registrations:
interval:200 7
timeout:12000 4
interval:60000 4
interval:250 4
interval:3000 4
interval:1000 2
In a 30s audit:
interval fires: 593
Why This Matters
Timers wake the main thread. On a fast desktop they disappear into the noise; on a throttled mobile CPU, timers can combine with socket traffic and React work to create visible stalls.
The timer issue is not that any one interval is terrible. It is that many UI elements keep time independently.
Likely Sources
ReplaySourcesPanel
Cooldown display:
const interval = setInterval(update, 250);
Only needed while cooldown is active and panel is visible.
AlertFeed
Likely uses a frequent interval for alert lifetimes. This should only run while alerts exist.
TurnsOverlay / RoverQueuesPanel
Countdown displays often use setInterval(() => setNow(Date.now()), 250 or 1000).
ControlContext Horn Heat
Horn heat interval at 100ms only runs when horn is active/cooling:
const tickMs = 100;
const interval = setInterval(...)
This is probably okay, but verify it only runs when needed.
Fix Strategies
Option A: Visibility-Gate Timers
Only run panel-specific timers when the panel is visible/open.
Example:
if (!isVisible || !needsCountdown) return;
Option B: Coarse Intervals
Use 1000ms for human-readable countdowns unless sub-second precision matters.
Replay cooldowns and queue countdowns probably do not need 250ms.
Option C: Shared Clock Store
Instead of each component creating its own interval, create one shared clock:
useClock(1000)
useClock(250)
Then multiple components can share a single interval.
Option D: CSS Animations for Pure Visual Expiry
For alert progress bars, use CSS animation if the UI does not need React state each tick.
Recommended Path
After major fixes, rerun the runtime audit. If intervals still show high:
- Increase replay cooldown interval from 250ms to 1000ms.
- Gate timers by tab visibility.
- Create a shared clock hook for countdown UI.
- Convert alert lifetime visuals to CSS where possible.
Validation
Run:
CPU_THROTTLE=6 VIEWPORT=390x844 MOBILE=1 SAMPLE_MS=30000 node perf/live-root-runtime-audit.mjs https://rover.otter.land/ perf/results
Expected:
- lower
intervals - lower
intervalFires - no visible regression in countdowns/alerts
Risks
- Timers used for control safety should not be slowed without careful review.
- Alert expiration should still happen reliably.
- Queue/turn countdowns can update less often, but should not become misleading.