priceInfoRange is a historical cursor connection whose range ends at "now": it
never returns upcoming slots. With it, the DB only ever held prices up to the
last hourly refresh, which caused two problems:
1. The price chart could only show history up to now, never a forward curve.
2. Worse, per-slot billing was subtly wrong. _tibber_strategy looks up the
price via `starts_at <= t0` (nearest slot at or before the period). Because
a period's exact 15-min slot was not fetched until the next hourly refresh
(~1h later), intra-hour periods were billed with the PREVIOUS quarter's
price and then locked in by the immutability guard — never corrected.
Switch to priceInfo(resolution: QUARTER_HOURLY) { today tomorrow }, which is
forward-looking AND quarter-hourly: today is always the full local day (96
slots) and tomorrow fills in once Tibber publishes day-ahead prices (picked up
by the next hourly refresh). Every 15-min slot's exact price is now in the DB
before the slot closes, so each period finds its own slot (accurate billing)
and the live current-price entity stays fresh.
Verified against the live Tibber API: fetch_price_range returns 192 points
(96 today + 96 tomorrow), spanning local today 00:00 → tomorrow 23:45, with
future slots present (previously 0).
priceInfoRange is a Relay-style cursor connection over the subscription's
entire price history. With no cursor, first:96 returned the OLDEST 96 slots,
anchored at the subscription start date — a fixed window that never advanced.
For a contract added mid-period this meant refresh_prices kept re-upserting the
same day-one slots forever, so GET /api/energy/prices found nothing in the
today+tomorrow window and the UI showed "No Tibber price points available".
Use last:192 to return the newest 192 quarter-hourly slots (2 days), which ends
at the latest published slot and advances daily, fully covering the prices
endpoint's today+tomorrow window.