Per-sample sustained-coast mask per output channel (speed/power/cadence), computed ONCE here (it's window-independent and the pond-fill pass is the expensive part) and reused by every channel build / zoom.
Where the distance axis comes from: a pool swim's lengths, the GPS line, the device's own distance, or nothing.
Where the recording starts and ends on the time axis: the activity's start (or an earlier first sample) to the last sample, widened to a pool swim's recorded lengths. With no timestamps, the sample count.
Whether the activity has a time axis at all: its samples' timestamps, or a pool swim's timed lengths and rests (which need no pool size and no samples). Elapsed, moving and swimming time need it.
Whether the samples carry timestamps (so speed is meaningful and a sample has a place on the time axis).
Whether the activity has a GPS track. False for GPS-less sources (indoor / GPS-off head units): no map, distance comes from the device stream.
OptionalmovingFor a rule other than speed: per sample i ≥ 1, whether the time before it counts as moving.
How moving is decided for this activity (see activity/moving.ts).
OptionalmovingFor a rule other than speed: the stretches that count as moving, in seconds from the start. Moving time is the overlap with them, so a sample gap that is half swimming counts half.
OptionalpoolFor a pool swim with a known pool length: each swum length, in seconds from the start, and its distance. A section's distance is then the lengths inside it (a length cut in two counts its share).
Some samples of a GPS track have no fix (NaN in cols.lat).
Derived instantaneous speed (m/s); NaN where no timestamp delta.
Elapsed seconds since the first sample.
The canonical pond series — always present (GPS or GPS-less). hasTrack
says whether it carries positions.
The streams decoded once into the per-sample arrays every downstream metric reads — track, columns, cumulative distance, derived speed, relative time. Building the pond track + reading columns is the expensive part of the summary compute, so prepareActivity does it once and both the summary (summaryFromPrepared) and the zoom-resolution profiles (windowChannels) reuse it — no second decode per zoom. Opaque shape; treat it as a handle, not a public data contract.