feat: bootstrap the telemetry bar from history medians on cold connect - #26
Merged
Merged
Conversation
A hub with no cached tick — server restart, or the router briefly down — left the telemetry bar empty until the first successful poll. HandleWS now falls back to a bootstrap-tagged telemetry_tick built from the 15-minute metric buckets (medians of CPU/RAM/temperature, and of the summed WAN rates over the monitored interfaces; buckets with incomplete interface coverage are skipped by a HAVING guard) plus live user/device counts read straight from the database. Nothing is invented: absent stays absent, and a router with no history gets no frame at all. The UI seeds the sparklines from the medians as a flat anchor line and dims the measurement tiles until a live tick lands; real ticks then append over the anchor, so the bar converges from the median toward the live curve instead of snapping from empty to busy. The frame cache in the hub keeps a per-router bootstrap for one minute so a refresh storm against a down router costs one aggregate query, and a live tick takes precedence over the cached bootstrap on every subsequent connect.
- HandleWS re-checks the live frame cache after building a bootstrap: a tick landing during the history queries can no longer be followed by the stale median frame it would overwrite. - BroadcastRouter revokes the bootstrap cache for the router and the default alias 0, so a cached pre-live frame never outlives the first live tick. - bootstrapSystemReading derives memory_usage_pct from the median free/total instead of medians of independent columns that could print an impossible triple; both readers surface rows.Err(). - The frontend seeds every sparkline explicitly: a metric missing from the bootstrap clears the previous router's line rather than lingering. - The telemetry hook no longer opens a probe socket while the active router id is unresolved; the hub answered it with the default router's replay, and the id settling a moment later tore it down and repeated everything — the bar loaded twice per refresh. The initial-load effect no longer depends on activeRouter?.id (it re-ran the whole load when the default was adopted), and loadRouters fires loadData the instant it adopts a router instead of leaving the user/device tiles queued behind the /routers live probes. Tested: 4 bootstrap tests extended (cache revocation asserted), hook tests pin the null-id silence, full gates green (go vet+tests, 397 vitest, build, sweep).
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.
The telemetry bar opened empty against a cold hub: a server restart, or a router briefly unreachable, left every tile on its dash placeholder until the first successful poll.
Backend —
/ws/telemetrynow falls back to a bootstrap-taggedtelemetry_tickwhen no live frame has ever been cached. Medians come from the existing 15-minute metric buckets (CPU / RAM / temperature, and the WAN rate summed over the monitored interfaces); buckets with incomplete interface coverage are dropped by aHAVING COUNT(DISTINCT)guard so a partial sum can't drag the WAN median. User and device counts are live DB facts, not history. A router with no history and an unresolvable router get no frame — honest placeholders beat invented numbers, and absent fields stay absent rather than zero.Frontend — bootstrap frames seed each sparkline to a flat median line and render the measurement tiles at 65% opacity via
.tile-bootstrapped; the first real tick replaces the seed, lifts the dim, and appends onto the median anchor — so the curve converges from the placeholder toward live data instead of snapping from empty to busy. A per-router frame cache (1-minute TTL) means a refresh storm against a down router costs one aggregate query; any live tick always takes precedence over the cache.Tests: 4 backend (median math, absent-history, router scoping, live-over-bootstrap precedence) + 1 frontend; full gates green (go count=3, 395 vitest, build, identifier sweep). README updated.