Good distinction, but the 90-day trend queries actually don't touch JSONB at all, because trends hit scalar columns (avg_hrv, duration_seconds, start_time) where a regular B-tree index is sufficient. The JSONB arrays are only used for sample-level queries like "show me my HR during last night's sleep" which are inherently single-session lookups, not range aggregations.
On streaming: currently returning complete payloads. For this use case it hasn't been a problem, because the trend queries aggregate 90 rows of scalar data which is fast, and the response is compact text. Streaming would make sense if I were piping large sample arrays directly, but those get aggregated server-side before returning. Worth revisiting if I add something like full workout trace exports.