- proposal и две capability: parsing (вывод слоя, форматы времени, канонизация) и storage (координатный ключ, слияние по полноте, часовые объекты) - design фиксирует границы: разбор отдельным пакетом, синхронно после записи в архив, конкурентная запись в один час — риск с тестом - вне scope сознательно: тренировки, reindex, словарь кодов, род агрегации
6.2 KiB
ADDED Requirements
Requirement: Идентичность точки по координатам
Система SHALL адресовать точку координатами метрика + слой + метка времени.
Поле source в ключ входить MUST NOT: оно нестабильно — то же измерение с тем
же значением приезжает то как Apple Watch Ultra 3|iPad (Anton), то как
Apple Watch Ultra 3, потому что Health переосмысливает атрибуцию задним
числом.
Идентичность по хешу содержимого проверялась и отвергнута: она задваивала минутный слой целиком — 120 точек в часе вместо 60.
Scenario: Повторная доставка той же точки ничего не меняет
- WHEN точка с теми же координатами и тем же содержимым приезжает снова
- THEN хранилище не изменяется
Scenario: Смена источника не создаёт вторую точку
- WHEN точка с теми же координатами приезжает с другой строкой
source - THEN она остаётся одной точкой, а не превращается в две
Requirement: Разрешение столкновений по полноте
Когда по одним координатам приходят разные содержимые, система SHALL оставлять
более полную точку — ту, у которой больше значащих полей, — а не последнюю
пришедшую. Иначе бедная доставка стирает start/end у богатой.
Если полнота равна, а значения различаются, исход определяет порядок
воспроизведения, и он MUST быть по received_at доставки: свёртка по журналу
обязана давать то же состояние, что приём в реальном времени.
Scenario: Бедная точка не стирает поля богатой
- WHEN сохранена точка с
qty,startиend - AND по тем же координатам приезжает точка только с
qty - THEN сохранённая точка остаётся с
startиend
Scenario: Одинаково полные точки с разными значениями
- WHEN по одним координатам приходят две одинаково полные точки с разными значениями
- THEN побеждает точка из доставки с большим
received_at
Requirement: Хранение часовыми объектами
Система SHALL хранить точки часовыми объектами с ключом
метрика + слой + час (UTC). Содержимое объекта — сжатый gzip блоб; точки
внутри упорядочены по времени.
Запись — чтение объекта, слияние точек, запись обратно. Точки из объекта MUST NOT удаляться.
Scenario: Точки за один час ложатся в один объект
- WHEN приходят точки одной метрики и слоя за один час UTC
- THEN они хранятся одним объектом
Scenario: Дозапись в существующий час
- WHEN приходят новые точки за уже существующий час
- THEN объект перечитывается, точки сливаются, объект записывается обратно
- AND ранее сохранённые точки остаются в объекте
Requirement: Хеш как детектор изменений
Система SHALL хранить хеш канонической формы объекта и пропускать запись, если хеш не изменился. Хеш — детектор, а не ключ.
Это то, что делает широкие проходы синхронизации дешёвыми: глубокий проход переприсылает неделю, но почти все сравнения сходятся и записи не происходит.
Scenario: Повторная присылка того же часа не пишет в базу
- WHEN приезжает доставка, целиком повторяющая уже сохранённый час
- THEN хеш совпадает и запись не выполняется
Requirement: Признак запечатанного часа
Система SHALL отмечать признаком sealed часы, которые уже не должны
меняться. Изменение запечатанного объекта — не отказ, а сигнал.
Scenario: Изменение запечатанного часа
- WHEN приходят точки за час, помеченный
sealed - THEN система пишет запись уровня
WARN - AND данные всё равно сохраняются
Requirement: Значения точек не попадают в логи
Данные о здоровье чувствительнее токенов. Система MUST NOT писать значения
точек и тела доставок в записи лога уровня выше DEBUG.
Scenario: Разбор доставки логируется без значений
- WHEN доставка разобрана
- THEN запись лога содержит счётчики (метрик, точек, объектов) и идентификатор доставки
- AND не содержит ни значений точек, ни имён устройств