- proposal и две capability: parsing (вывод слоя, форматы времени, канонизация) и storage (координатный ключ, слияние по полноте, часовые объекты) - design фиксирует границы: разбор отдельным пакетом, синхронно после записи в архив, конкурентная запись в один час — риск с тестом - вне scope сознательно: тренировки, reindex, словарь кодов, род агрегации
5.0 KiB
5.0 KiB
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,payloadBLOB,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поднимает сервис, новая доставка с телефона разбирается