хранилище описано как свёртка по журналу событий
- экспорт Apple это снапшот всей истории, доставки после его даты — события поверх; состояние пересобирается как import(экспорт) + replay(доставки) - отсюда ретеншен архива меняется с произвольных 14 дней на «до следующего проверенного экспорта» (~2 ГБ за квартал, измерено), а свёртка обязана быть детерминированной — воспроизведение строго по received_at - названы границы модели: stateOfMind в экспорт не попадает вовсе, а верхние слои за периоды с удалёнными доставками не воскресают и досчитываться не должны — каталог обязан говорить это честно
This commit is contained in:
@@ -7,7 +7,7 @@
|
||||
## высокий
|
||||
- [Разбор метрик в часовые объекты](razbor-metrik-v-obekty.md) — Доставки копятся непрозрачными телами — точек в хранилище нет вовсе, всё остальное упирается в это
|
||||
- [Тренировки и секции с собственными id](trenirovki-i-zapisi.md) — Тренировки с геотреком и состояние разума приходят, но не разбираются — без них не закрыть ни трекер, ни агента-медика
|
||||
- [Пересборка хранилища из сырого архива](reindex-iz-arhiva.md) — Разбор будет ошибаться, а окно на исправление — 14 дней жизни архива
|
||||
- [Пересборка хранилища из сырого архива](reindex-iz-arhiva.md) — Ошибка разбора без пересборки становится потерей данных — исправленный код не применится к уже разобранному
|
||||
- [Измеренный род агрегации и каталог разрезов](rod-agregacii-i-katalog.md) — Без рода метрики свёртка в ответе неотличима от угадывания — а суммировать нижний слой значит завысить втрое
|
||||
- [Read API: точки, выбор слоя, свёртка по сетке](read-api-tochki.md) — Данные видны только через sqlite на хосте — ни один из трёх потребителей ничего прочитать не может
|
||||
- [OpenAPI-спека и Swagger UI](openapi-swagger.md) — Потребителей три и один из них агент — контракт должен читаться машиной, а не пересказываться в чате
|
||||
|
||||
@@ -3,14 +3,26 @@
|
||||
**Приоритет:** высокий
|
||||
|
||||
Разбор пишется по реальным данным и будет ошибаться — это норма, а не риск.
|
||||
Риск в другом: сырой архив живёт 14 дней, и окно на исправление ошибки равно
|
||||
этому сроку. Без `reindex` ошибка разбора становится потерей данных.
|
||||
Риск в другом: без пересборки ошибка разбора становится потерей данных —
|
||||
исправленный код не применится к тому, что уже разобрано неверно.
|
||||
|
||||
Пересчёт по всей истории сразу ещё и **точнее** приёма: вывод слоя и род
|
||||
агрегации на полном ряду доставок надёжнее, чем на одной.
|
||||
|
||||
Готово, когда `healthlog reindex` пересобирает хранилище с нуля из `data/raw`
|
||||
и результат совпадает с накопленным приёмом.
|
||||
Проектировать это надо сразу как **свёртку по журналу**, а не как разовую
|
||||
утилиту: состояние есть `import(снапшот экспорта) + replay(доставки после его
|
||||
даты)`, и пересборка из архива — вырожденный случай с пустым снапшотом. Тогда
|
||||
`reindex` и `import` окажутся одной операцией с разным входом, а не двумя
|
||||
похожими.
|
||||
|
||||
Отсюда требование, которое легко упустить: **свёртка обязана быть
|
||||
детерминированной.** Проигрывание должно давать то же состояние, что приём в
|
||||
реальном времени. Слияние «выигрывает более полная точка» коммутативно, но две
|
||||
одинаково полные точки с разными значениями разрешает порядок — значит
|
||||
воспроизведение идёт строго по `received_at`, а не по порядку файлов в каталоге.
|
||||
|
||||
Готово, когда пересборка с нуля даёт состояние, совпадающее с накопленным
|
||||
приёмом, и повторный прогон ничего не меняет.
|
||||
|
||||
Связано: план шаг 3, `docs/architecture.md` → «Сырой архив».
|
||||
|
||||
|
||||
@@ -5,10 +5,24 @@
|
||||
Срок жизни сырого архива объявлен (14 дней, `storage.raw_retention`), но
|
||||
удаления нет: архив растёт бесконечно. Пока это 16 МБ и проблемой не является.
|
||||
|
||||
Включать **после** того, как разбор устоится и `reindex` докажет, что
|
||||
хранилище действительно пересобирается: иначе страховка исчезнет раньше, чем
|
||||
**Само правило изменилось.** Экспорт Apple — снапшот всей истории, доставки
|
||||
после его даты — события поверх снапшота, и состояние всегда пересобираемо
|
||||
свёрткой. Значит доставки должны жить **до следующего проверенного экспорта**,
|
||||
а не фиксированные две недели: иначе между концом ретеншена и датой снапшота
|
||||
образуется дыра в журнале, и пересобрать этот отрезок будет нечем.
|
||||
|
||||
Цена измерена: ~23 МБ архива в сутки, то есть ~2 ГБ за квартал между
|
||||
экспортами. Дёшево за возможность пересобрать что угодно.
|
||||
|
||||
Отдельное исключение: `stateOfMind` в экспорт не попадает вовсе (проверено на
|
||||
свежем архиве). Для него доставки — не хвост журнала, а единственный источник,
|
||||
и под общее правило удаления он не подпадает.
|
||||
|
||||
Включать **после** того, как разбор устоится и пересборка докажет, что
|
||||
хранилище действительно восстанавливается: иначе страховка исчезнет раньше, чем
|
||||
перестанет быть нужна.
|
||||
|
||||
Готово, когда старые тела удаляются по расписанию, а `/stats` показывает
|
||||
глубину архива в днях.
|
||||
Готово, когда удаляются только доставки старше последнего проверенного
|
||||
экспорта, записи `stateOfMind` не трогаются вовсе, а `/stats` показывает
|
||||
глубину архива и дату снапшота, до которой он подрезан.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user