Files
healthlog/openspec/changes/razbor-metrik-v-obekty/tasks.md
T
av c6f27e3890 заведён change на разбор метрик в часовые объекты
- proposal и две capability: parsing (вывод слоя, форматы времени, канонизация)
  и storage (координатный ключ, слияние по полноте, часовые объекты)
- design фиксирует границы: разбор отдельным пакетом, синхронно после записи в
  архив, конкурентная запись в один час — риск с тестом
- вне scope сознательно: тренировки, reindex, словарь кодов, род агрегации
2026-08-01 14:50:10 +03:00

5.0 KiB
Raw Blame History

1. Фикстуры и схема

  • 1.1 Скрипт tmp/research/fixtures.py: собирает фикстуры из data/raw, вычищая измеренные значения и сохраняя порядок ключей, точность чисел, неразрывные пробелы и форматы времени
  • 1.2 Набор internal/hae/testdata: минутная доставка, посекундная, часовая, смешанная (перенастройка автоматизации), обе схемы sleep_analysis, точка с heartbeatSeries
  • 1.3 Миграция internal/store/migrations/00003_bucket.sql: таблица bucket (metric, layer, hour_utc, payload BLOB, content_hash, points, sealed, created_at, updated_at), уникальность по (metric, layer, hour_utc)
  • 1.4 docs/database.md — ER-схема с delivery и bucket (шаг гейта er-schema требует её при изменении миграций)

2. Разбор — пакет internal/hae

  • 2.1 Разбор трёх форматов времени в UTC с сохранением офсета исходной зоны; неразобранная метка — не паника, а пропуск точки со счётчиком
  • 2.2 Вывод слоя: выравнивание меток, плотная метрика (≥10 точек) сама, редкая наследует преобладающий слой, при отсутствии плотных — заголовок доставки
  • 2.3 Расхождение выведенного слоя с заголовком доставки — запись WARN без значений точек
  • 2.4 Разделение sleep_analysis на поэпизодную и sleep_analysis_summary со слоем day
  • 2.5 Канонизация: рекурсивная сортировка ключей, округление чисел до 12 значащих цифр
  • 2.6 hae.Parse возвращает точки со слоем, метрикой, меткой и содержимым как пришло; незнакомые поля и метрики сохраняются
  • 2.7 Тесты разбора на фикстурах из 1.2, включая смешанную доставку и обе схемы сна

3. Хранение — часовые объекты

  • 3.1 Модель точки и объекта в internal/store; сериализация содержимого в gzip-BLOB, точки внутри упорядочены по времени
  • 3.2 Слияние: координатный ключ метрика + слой + метка, победа более полной точки, при равной полноте — по received_at
  • 3.3 Хеш канонической формы объекта как детектор изменений: совпал — записи нет
  • 3.4 Запись объекта в транзакции; повтор при SQLITE_BUSY
  • 3.5 Признак sealed: изменение запечатанного часа пишет WARN и всё равно сохраняет
  • 3.6 Тест конкурентной записи в один hour_utc: точки обеих сторон на месте
  • 3.7 Тест идемпотентности: повторное слияние того же набора не меняет ни содержимое, ни хеш

4. Сшивка с приёмом

  • 4.1 internal/ingest вызывает разбор после записи тела в архив и строки delivery
  • 4.2 Отказ и паника разбора не меняют код ответа: 200, parse_status=failed, запись лога уровня ERROR без значений
  • 4.3 Единственный логирующий чекпоинт на границе: счётчики метрик, точек и объектов, идентификатор доставки; ни значений, ни имён устройств
  • 4.4 Тест приёма: битый JSON — 400, непонятое содержимое — 200 с parse_status=failed

5. Сходимость на реальных данных

  • 5.1 Скрипт tmp/research/verify_buckets.py: прогоняет архив через разбор и сверяет суммы по часовому слою с прежней проверкой из разведки
  • 5.2 Прогон на всех накопленных доставках: расхождений по накопительным метрикам нет
  • 5.3 task gate зелёный; task restart поднимает сервис, новая доставка с телефона разбирается

6. Приёмочные критерии ревью дизайна