ключ точки — интервал одной формы, класс «эпизодных метрик» убран
Перепись по 22 метрикам с интервалами опровергла признак из первой редакции: start всегда равен date, интервалы несёт не только сон, обе формы точки не смешиваются внутри метрики одной доставки, а разные интервалы под одной меткой всегда несут разное содержимое. Значит ключ единый — метрика + слой + начало + конец, у измерения вырожденный, без ветвления по классу.
This commit is contained in:
@@ -2,11 +2,33 @@
|
||||
|
||||
### Requirement: Идентичность точки по координатам
|
||||
|
||||
Система SHALL адресовать точку-измерение координатами
|
||||
`метрика + слой + метка времени`. Поле `source` в ключ входить MUST NOT: оно
|
||||
нестабильно — то же измерение с тем же значением приезжает то как
|
||||
`Apple Watch Ultra 3|iPad (Anton)`, то как `Apple Watch Ultra 3`, потому что
|
||||
Health переосмысливает атрибуцию задним числом.
|
||||
Система SHALL адресовать точку координатами
|
||||
`метрика + слой + начало + конец`. У точки-измерения конец равен началу; у
|
||||
точки-интервала — концу интервала. Ключ MUST быть одной формы для всех точек:
|
||||
интервальная и точечная формы не встречаются вперемешку внутри одной метрики
|
||||
одной доставки (проверено на всём корпусе), поэтому ветвление по «классу
|
||||
метрики» не нужно и вводить его MUST NOT.
|
||||
|
||||
Поле `source` в ключ входить MUST NOT: оно нестабильно — то же измерение с тем
|
||||
же значением приезжает то как `Apple Watch Ultra 3|iPad (Anton)`, то как
|
||||
`Apple Watch Ultra 3`, потому что Health переосмысливает атрибуцию задним
|
||||
числом.
|
||||
|
||||
Начало точки берётся из `start`, а при его отсутствии — из `date`; конец — из
|
||||
`end`, а при его отсутствии — из начала. Измерено: `start`, когда он есть,
|
||||
**всегда** совпадает с `date` (ноль исключений на 22 метриках), поэтому правило
|
||||
не вводит второго источника метки — оно лишь закрывает случай, когда HAE
|
||||
перестанет их дублировать.
|
||||
|
||||
Час объекта определяется по началу точки: интервал пересекает границы часов, и
|
||||
любой другой выбор сделал бы принадлежность объекту зависящей от длительности.
|
||||
|
||||
Ключ по одной метке проверялся и отвергнут: он схлопывает записи сна. Измерено
|
||||
на всех 94 доставках — 170 координат против 174 и **33 столкновения внутри
|
||||
одной доставки**, где `received_at` общий, тай-брейк по нему неприменим в
|
||||
принципе, и исход решал бы порядок элементов в JSON-массиве, а он нестабилен.
|
||||
При этом разные интервалы под одной меткой всегда несут разное содержимое
|
||||
(проверено по всем метрикам), то есть ключ с интервалом ничего не задваивает.
|
||||
|
||||
Идентичность по хешу содержимого проверялась и отвергнута: она задваивала
|
||||
минутный слой целиком — 120 точек в часе вместо 60.
|
||||
@@ -21,44 +43,28 @@ Health переосмысливает атрибуцию задним число
|
||||
- **WHEN** точка с теми же координатами приезжает с другой строкой `source`
|
||||
- **THEN** она остаётся одной точкой, а не превращается в две
|
||||
|
||||
### Requirement: Идентичность эпизода по интервалу
|
||||
|
||||
Система SHALL адресовать точку-интервал координатами
|
||||
`метрика + слой + начало + конец`. Метки времени для неё недостаточно: под
|
||||
одной меткой лежит до трёх разных эпизодов сна.
|
||||
|
||||
Эпизодность SHALL выводиться из формы точки — точка несёт `start` и `end`,
|
||||
отличные от `date`, — а не назначаться списком имён метрик. Список был бы
|
||||
вторым способом описывать то, что уже сказано формой точки, и разошёлся бы с
|
||||
ней на первой же новой метрике HAE.
|
||||
|
||||
Измерено на всех 94 доставках (1880 эпизодных точек, находка 47): ключ по метке
|
||||
даёт 170 координат и 33 столкновения **внутри одной доставки**, ключ по
|
||||
интервалу — 174 координаты и ноль столкновений. Внутридоставочные столкновения
|
||||
и делают ключ по метке неисправимым: `received_at` там общий, тай-брейк по нему
|
||||
неприменим в принципе, и исход решал бы порядок элементов в JSON-массиве — а он
|
||||
нестабилен.
|
||||
|
||||
Час объекта для точки-интервала SHALL определяться по началу эпизода: эпизод
|
||||
пересекает границы часов, и любой другой выбор сделал бы принадлежность
|
||||
объекту зависящей от длительности.
|
||||
|
||||
#### Scenario: Эпизоды с одной меткой и разными интервалами не схлопываются
|
||||
#### Scenario: Записи с одной меткой и разными интервалами не схлопываются
|
||||
|
||||
- **WHEN** в доставке приходят точки `sleep_analysis` с одинаковым `date` и
|
||||
разными парами `start`/`end`
|
||||
- **THEN** каждая сохраняется отдельной точкой
|
||||
|
||||
#### Scenario: Повтор эпизода в следующей доставке не задваивает
|
||||
#### Scenario: Повтор записи в следующей доставке не задваивает
|
||||
|
||||
- **WHEN** точка с тем же `start` и `end` приезжает следующей доставкой
|
||||
- **WHEN** точка с тем же началом и концом приезжает следующей доставкой
|
||||
- **THEN** она остаётся одной точкой
|
||||
|
||||
#### Scenario: Точка-измерение адресуется вырожденным интервалом
|
||||
|
||||
- **WHEN** точка не несёт `end`
|
||||
- **THEN** её конец равен началу, и ключ имеет ту же форму, что у интервала
|
||||
|
||||
### Requirement: Разрешение столкновений по полноте
|
||||
|
||||
Когда по одним координатам приходят разные содержимые, система SHALL оставлять
|
||||
**более полную** точку — ту, у которой больше значащих полей, — а не последнюю
|
||||
пришедшую. Иначе бедная доставка стирает `start`/`end` у богатой.
|
||||
пришедшую. Иначе бедная доставка стирает у богатой поля, которых сама не несёт:
|
||||
0.66% координат различаются именно набором полей при одинаковом значении.
|
||||
|
||||
Если полнота равна, а значения различаются, исход MUST быть детерминированным
|
||||
и не зависеть от порядка, в котором доставки дошли до хранилища: свёртка по
|
||||
@@ -71,9 +77,9 @@ Health переосмысливает атрибуцию задним число
|
||||
|
||||
#### Scenario: Бедная точка не стирает поля богатой
|
||||
|
||||
- **WHEN** сохранена точка с `qty`, `start` и `end`
|
||||
- **AND** по тем же координатам приезжает точка только с `qty`
|
||||
- **THEN** сохранённая точка остаётся с `start` и `end`
|
||||
- **WHEN** сохранена точка с `Avg`, `Min`, `Max` и `context`
|
||||
- **AND** по тем же координатам приезжает точка только с `Avg`, `Min` и `Max`
|
||||
- **THEN** сохранённая точка остаётся с `context`
|
||||
|
||||
#### Scenario: Одинаково полные точки с разными значениями
|
||||
|
||||
|
||||
Reference in New Issue
Block a user