docs: план обрезан до порядка, отложенное переехало в беклог
- содержимое шагов не перечисляется: список работ жил в плане и в беклоге и расходился с каждой закрытой задачей - десять пунктов «Отложено» заведены задачами [idea]; два из них (ретеншен, алерт) уже были в беклоге — в плане лежал дубль - обоснование порядка расписано по шагам: это единственное, чего беклог структурно не вмещает
This commit is contained in:
@@ -40,4 +40,11 @@
|
||||
- [Устаревание нижнего слоя после экспорта](ustarevanie-nizhnego-sloya.md) — Нижний слой растёт на ~100 тысяч координат в сутки, а после экспорта Apple он избыточен
|
||||
- [Ретеншен сырого архива](retenshen-syrogo-arhiva.md) — Архив не подчищается вовсе — 14-дневный срок объявлен, но не работает
|
||||
- [Активный алерт «данных нет N часов»](alert-tishina-potoka.md) — Пропажу потока сейчас замечает человек, а не сервис
|
||||
- [[idea] Порог sealed: с какого возраста час считается запечатанным](porog-sealed.md) — WARN на изменение старого часа уже пишется, но порог не выбран — ставим по факту, когда накопится статистика досчёта
|
||||
- [[idea] Месячный проход по ручным секциям](mesyachnyj-prohod-ruchnye-sekcii.md) — Симптомы и лекарства заводятся задним числом на недели — недельного глубокого прохода им не хватит
|
||||
- [[idea] Человеческие аннотации поверх выведенных схем](annotacii-k-shemam.md) — Выведенная схема говорит форму, но не смысл метрики — нужно ли описание сверху, зависит от стабильности формата
|
||||
- [[idea] Отказ от heartbeatSeries](otkaz-ot-heartbeatseries.md) — 93% объёма HRV ради данных, которых нет ни в одном планируемом запросе
|
||||
- [[idea] Выгрузка в parquet отдельной командой](vygruzka-v-parquet.md) — Дверь для тяжёлой аналитики снаружи: DuckDB читает и parquet, и файл SQLite — спешить некуда, но и закрывать не нужно
|
||||
- [[idea] NDJSON-поток для больших выборок Read API](ndjson-potok.md) — Выборка нижнего слоя за месяц не влезает в один JSON-ответ — либо поток, либо пагинация
|
||||
- [[idea] Разворачивание маршрутов тренировок в отдельную таблицу](razvorachivanie-marshrutov.md) — Маршрут лежит блобом внутри тренировки — понадобится, только если появится клиент, которому мало отдачи одним пакетом
|
||||
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
# [idea] Человеческие аннотации поверх выведенных схем
|
||||
|
||||
**Приоритет:** низкий
|
||||
|
||||
Схема содержимого выводится из данных и говорит **форму** — какие поля есть,
|
||||
какого типа, с какой заполненностью. Чего она не говорит — что метрика значит,
|
||||
в каких единицах разумны значения и чем `apple_stand_hour` отличается от
|
||||
`apple_exercise_time`.
|
||||
|
||||
Два пути, и выбор между ними преждевременен:
|
||||
|
||||
- **аннотации поверх выведенных схем** — человеческое описание рядом с
|
||||
машинным выводом, дописывается по мере надобности;
|
||||
- **рукописный каталог метрик** — полнее, но описывал бы документацию HAE, а не
|
||||
то, что он реально прислал.
|
||||
|
||||
Почему идея, а не задача: выбор зависит от того, насколько стабильным окажется
|
||||
формат. Меняться он может только с обновлением Health Auto Export, а это
|
||||
отслеживается — значит ответ придёт сам.
|
||||
|
||||
Связано: `docs/architecture.md` → «Самоописание», задача `samoopisanie-shemy`.
|
||||
@@ -0,0 +1,21 @@
|
||||
# [idea] Месячный проход по ручным секциям
|
||||
|
||||
**Приоритет:** низкий
|
||||
|
||||
Окно досчёта не единое, и это измеренное различие, а не предположение.
|
||||
Количественные метрики (пульс, шаги, энергия) человек руками не правит — они
|
||||
опаздывают на часы, и недельного глубокого прохода им хватает. Ручные записи
|
||||
(`symptoms`, `medications`, `stateOfMind`, `cycleTracking`) заводятся задним
|
||||
числом на недели и месяцы: симптом или приём лекарства можно отметить за
|
||||
прошлую дату.
|
||||
|
||||
Растянуть общий глубокий проход на месяц нельзя: тела запросов доходили до
|
||||
42 МБ (находка 23), а месяц минутных данных — это десятки мегабайт на каждую
|
||||
доставку. Отсюда решение: редкий широкий проход **только по ручным секциям** —
|
||||
их единицы записей, и месячное окно там почти ничего не стоит.
|
||||
|
||||
Почему идея, а не задача: этих секций в живом потоке ещё не было. Заводить,
|
||||
когда они появятся, — иначе проход пишется вслепую и проверяется не на чем.
|
||||
|
||||
Связано: `docs/architecture.md` → «Досчёт задним числом», задача
|
||||
`proverka-novyh-sekcij`.
|
||||
@@ -0,0 +1,20 @@
|
||||
# [idea] NDJSON-поток для больших выборок Read API
|
||||
|
||||
**Приоритет:** низкий
|
||||
|
||||
Read API отдаёт ответ одним JSON. Для выборок нижнего слоя за длинный период
|
||||
это не работает: `heart_rate` в слое `raw` — порядка сотни тысяч координат в
|
||||
сутки, и месяц такого ряда не влезет ни в память клиента, ни в разумный ответ.
|
||||
|
||||
Сейчас проблема закрыта с другой стороны — правилом размера ответа: сервер сам
|
||||
берёт сетку погрубее, когда разбивка не задана, и отвечает ошибкой со списком
|
||||
доступных сеток, когда задана явно. Это защищает агента с ограниченным
|
||||
контекстом, но не помогает клиенту, которому действительно нужен весь ряд —
|
||||
например, разовой выгрузке в другой инструмент.
|
||||
|
||||
Почему идея, а не задача: неизвестно, появится ли такой клиент. Если появится,
|
||||
выбор между NDJSON-потоком и курсорной пагинацией зависит от того, читает он
|
||||
последовательно или с возвратами.
|
||||
|
||||
Связано: `docs/architecture.md` → «Свёртка и размер ответа», задача
|
||||
`read-api-tochki`.
|
||||
@@ -0,0 +1,19 @@
|
||||
# [idea] Отказ от heartbeatSeries
|
||||
|
||||
**Приоритет:** низкий
|
||||
|
||||
`heart_rate_variability` приезжает вместе с `heartbeatSeries` — рядом
|
||||
межударных интервалов внутри точки. Это **93% объёма метрики** (находка 39)
|
||||
ради данных, которых нет ни в одном из планируемых запросов: ни агент, ни
|
||||
трекер, ни игра межударными интервалами не оперируют.
|
||||
|
||||
Отбросить их означало бы нарушить инвариант «точки хранятся дословно» — и это
|
||||
не мелочь: срок жизни сырого архива держится ровно на том, что объект является
|
||||
полной копией. Поэтому вопрос не «выбросить или нет», а «когда цена хранения
|
||||
нижнего слоя станет заметной».
|
||||
|
||||
Почему идея, а не задача: цена пока не измерена в годовом масштабе, а решение
|
||||
необратимо — выброшенные ряды не вернуть иначе как из экспорта Apple, где их
|
||||
может не быть вовсе.
|
||||
|
||||
Связано: `docs/architecture.md` → «Открытые вопросы», находка 39.
|
||||
@@ -0,0 +1,17 @@
|
||||
# [idea] Порог sealed: с какого возраста час считается запечатанным
|
||||
|
||||
**Приоритет:** низкий
|
||||
|
||||
Флаг `sealed` отмечает часы, которые уже не должны меняться. Механика готова:
|
||||
изменение запечатанного объекта не отвергается, а пишется `WARN`, и данные
|
||||
всё равно сохраняются. Не выбрано одно — **с какого возраста** ставить флаг.
|
||||
|
||||
Почему идея, а не задача: правильный порог выводится из эксплуатации, а не из
|
||||
рассуждения. Наблюдалась глубина досчёта до 22 минут (находка 10), но одного
|
||||
наблюдения мало — ручные секции правятся задним числом на недели, а
|
||||
количественные метрики опаздывают на часы. Ставить порог сейчас значит угадать.
|
||||
|
||||
Что нужно, чтобы стало задачей: статистика `WARN` за несколько недель живого
|
||||
потока и распределение возраста изменённых часов по классам метрик.
|
||||
|
||||
Связано: `docs/architecture.md` → «Часовые объекты метрик».
|
||||
@@ -0,0 +1,17 @@
|
||||
# [idea] Разворачивание маршрутов тренировок в отдельную таблицу
|
||||
|
||||
**Приоритет:** низкий
|
||||
|
||||
Тренировка хранится нераскрытой: заголовок — колонками, всё остальное, включая
|
||||
маршрут и внутренние ряды, — блобом `payload`. Решение осознанное: структура
|
||||
тренировки разнородна и избыточна (сводки дублируют ряды, находка 15), и
|
||||
раскладывать её в таблицы значило бы решить за Apple, что в ней главное.
|
||||
|
||||
Разворачивание маршрута в отдельную таблицу точек имело бы смысл для запросов
|
||||
вида «все пробежки, проходившие через эту область» или «набор высоты по
|
||||
сегментам» — то есть когда маршрут нужен не целиком, а выборочно.
|
||||
|
||||
Почему идея, а не задача: такого клиента нет. Трекер тренировок берёт
|
||||
тренировку целиком одним пакетом, и этого ему достаточно.
|
||||
|
||||
Связано: `docs/architecture.md` → «Тренировки и прочие секции».
|
||||
@@ -13,6 +13,11 @@
|
||||
Вывод ограничивается по глубине вложенности, иначе схема тренировки с маршрутом
|
||||
разрастётся до размеров самих данных.
|
||||
|
||||
**Глубину вывода для тренировок выбираем по факту**, когда увидим, как приходят
|
||||
маршруты: структура тренировки разнородна, и заранее назначенный предел либо
|
||||
срежет полезное, либо не срежет ничего. Точка маршрута при этом описываться
|
||||
должна — блоб трека не непрозрачен, это массив однотипных объектов.
|
||||
|
||||
Готово, когда клиент по `/api/v1/metrics/{name}/schema` видит поля, их типы и
|
||||
присутствие, не выкачивая выборку.
|
||||
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
# [idea] Выгрузка в parquet отдельной командой
|
||||
|
||||
**Приоритет:** низкий
|
||||
|
||||
Отдельная команда, выгружающая хранилище в parquet, — дверь для тяжёлой
|
||||
аналитики снаружи, без миграции самого хранилища.
|
||||
|
||||
Контекст решения: DuckDB рассматривался как основное хранилище и отложен —
|
||||
чистого Go-драйвера нет, любой требует cgo, а это стоит нам `CGO_ENABLED=0` и
|
||||
одного статического бинаря. Но дверь при этом осталась открытой: DuckDB читает
|
||||
и parquet, и файл SQLite напрямую. Значит спешить некуда — выгрузка добавляется
|
||||
тогда, когда появится тяжёлый аналитический запрос, а не заранее.
|
||||
|
||||
Почему идея, а не задача: такого запроса пока нет. Ни один из трёх потребителей
|
||||
(агент-медик, трекер, игра) в аналитике по всей истории не нуждается.
|
||||
|
||||
Связано: `docs/architecture.md` → «Открытые вопросы» → «Хранилище под
|
||||
аналитику».
|
||||
Reference in New Issue
Block a user