From cc4831dc3b467b94500ba74294c1d25b9fa542d6 Mon Sep 17 00:00:00 2001 From: Florent Tapponnier Date: Fri, 17 Jul 2026 15:09:48 +0200 Subject: [PATCH] ticker: defensive ceiling on live-number values An upstream corruption on the relay's vol24h feed (observed 8.26e79 today) latched into the LiveNumber snapshot pair and, in monotonic mode, stuck as the displayed value forever because every subsequent healthy tick was smaller and got rejected as a 'down tick'. Add a maxValue prop that rejects any incoming value above a plausible ceiling before it can pollute the snapshot pair, and flushes a previously-poisoned lastRef so a healthy value can seed the ticker on the next push. Ceilings sit 20 to 100x above the real world ATH so plausible growth stays uncapped: vol24h 1e13 (real ATH ~5e11), trades24h 1e10 (real ATH ~5e7), mcap 1e14 (real ATH ~4e12). --- src/components/live/live-number.tsx | 20 +++++++++++++++++++- src/components/live/ticker.tsx | 11 +++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/src/components/live/live-number.tsx b/src/components/live/live-number.tsx index c8db0d74..1abb4927 100644 --- a/src/components/live/live-number.tsx +++ b/src/components/live/live-number.tsx @@ -28,11 +28,19 @@ export function LiveNumber({ value, format, monotonic = false, + maxValue, className, }: { value: number | undefined; format: (n: number | undefined) => string; monotonic?: boolean; + /** Defensive ceiling. A single garbage push from the upstream relay + * (observed: onchain vol24h briefly returning 8e79) would otherwise + * latch into `lastRef` and, under `monotonic`, stick as the + * displayed value forever because every subsequent healthy push is + * smaller and gets rejected as a "down tick". Reject any incoming + * value above the ceiling before it can pollute the snapshot pair. */ + maxValue?: number; className?: string; }) { const [display, setDisplay] = useState(value); @@ -42,6 +50,16 @@ export function LiveNumber({ useEffect(() => { if (value == null || !Number.isFinite(value)) return; + if (maxValue != null && value > maxValue) { + // Also flush a poisoned lastRef so a healthy value can seed the + // pair on the next push instead of being rejected by the + // monotonic guard against the stale garbage. + if (lastRef.current && lastRef.current.value > maxValue) { + lastRef.current = null; + prevRef.current = null; + } + return; + } const now = performance.now(); // Only advance the snapshot pair on DISTINCT values. Consecutive pushes // with the same value (relay 1 Hz tick × lighthouse 1-5 min poll) would @@ -53,7 +71,7 @@ export function LiveNumber({ if (lastRef.current.value === value) return; prevRef.current = lastRef.current; lastRef.current = { value, ts: now }; - }, [value]); + }, [value, maxValue]); useEffect(() => { let cancelled = false; diff --git a/src/components/live/ticker.tsx b/src/components/live/ticker.tsx index 1409ef69..118504e2 100644 --- a/src/components/live/ticker.tsx +++ b/src/components/live/ticker.tsx @@ -56,22 +56,30 @@ export const LiveTicker = memo(function LiveTicker({ + {/* maxValue: defensive ceilings against upstream corruption. Real + world highs (crypto ATH): vol24h ~$500B, trades24h ~50M, + mcap ~$4T. Ceilings sit 20-100x above those to leave room for + plausible growth while catching the 10^20+ garbage tick that + latched the ticker at 8e79 on the home page on 2026-07-17. */}