# Спецификация 02: HrSampleStore — буфер пульса (чистый JVM) Источники: Ф-3.2 (текущее значение + линия последнего подхода), module_reqs разд. 1 (буфер, устаревание >10 с, решение 4 — только память). Единица 2. ## 1. Интерфейс ```kotlin class HrSampleStore { fun add(bpm: Int, atMs: Long) // сэмпл транспортом fun current(nowMs: Long, staleAfterMs: Long = 10_000): Int? fun average(fromMs: Long, toMs: Long): Int? // среднее за окно fun series(fromMs: Long, toMs: Long): List> // (atMs, bpm) fun clear() // сброс (новая тренировка) val lastSampleAtMs: Long? } ``` - время — абсолютные миллисекунды (`System.currentTimeMillis()` передаётся вызывающим; в тестах — фикссированные значения); - хранение: весь список сэмплов сессии (`ArrayList>`) — при 1 Гц и 3-часовой тренировке ~10⁴ записей, деградации памяти нет; среднее считается инкрементально по окну проходом (список короткий), без накопления суммы всей сессии; - `current`: последний сэмпл, если `nowMs − atMs ≤ staleAfterMs`, иначе `null` (прочерк, «нет данных»); - `average`: арифметическое `Int` (округление вниз) по сэмплам окна `[fromMs, toMs]`; пусто → `null`; `toMs` обычно «сейчас»; - `series` — сэмплы окна в порядке поступления (линия последнего подхода: `fromMs = время последнего logSet`, толщина линии — один сэмпл = одна точка); - значения bpm вне 30–250 в буфер не попадают (отфильтрованы парсером, спец 01 §3 — двойная защита: `add` тоже игнорирует вне диапазона). ## 2. Связь с тренировкой - окно средней — от старта тренировки (`workout.startedAt`) до финиша; сэмплы вне окна (канал работал до старта — экран «Допуск») в среднее не входят; - `clear()` вызывается фасадом при `unbind` после финишированной тренировки; между тренировками буфер накапливается только при открытом экране «Допуск» (для «взять с часов», спец 03 §4). ## 3. Тесты (pure JVM) - фильтрация диапазона при `add`; - `current`: свежий / устаревший (10 001 мс) / пустой буфер; - `average`: пусто → null; одно значение; окно вырезает сэмплы до/после; округление вниз (127,5 → 127); - `series`: порядок и граница окна включительно; - `clear` обнуляет всё.