- рядом с воркером свёртки живёт горутина, раз в минуту разбирающая журнал
пассивным чекпойнтом; «журнал не разбирается» видно строкой владельцу, а не
только по `df`. Признак — пара чисел, а не флаг занятости: тот молчит под
удерживаемым читателем (`busy=0` при 6256 страницах и пяти перенесённых), а
при занятой блокировке отдаёт `-1` вместо ответа, и `-1 >= -1` читалось бы как
«разобрано целиком»
- каталог отвечает `304` на `If-None-Match`, не открывая снимок витрины. Метка
собрана из всего, от чего зависит ответ: версии витрины (`data_version` с
закреплённого соединения плюс поколение — значение локально для соединения и
не переживает переоткрытия), горизонта измерения и области действия ресурса.
Версия снимается до и после сборки: снятая после пометила бы устаревший снимок
свежим номером
- предел и дедлайн ответа отложены в задачу Read API точек вместе с измеренной
ценой первого запроса; попутно починен флаки-тест чужой задачи, искавший
значение точки в сыром буфере записи лога
- Правило покрытия получило второй разряд (условный, как у точек), запрет
вырождения формы и счёт содержательных элементов ряда: скелет из скаляров и
ряд из null больше не затирают маршрут. Победитель внутри доставки стал
функцией множества версий — общим помощником с точками, — а провенанс
поднимается и при совпавшем хеше, иначе отложенная доставка возвращала витрину
к прежнему содержимому.
- Одно поле не того типа больше не уносит сущность, а пропуски видны в учётной
записи доставки (миграция 00008, NULL = «не измерялось»); каноническая форма
считается один раз и вне транзакции; откат бинаря поверх новой схемы отказывает
на старте; текст ошибки разбора не несёт значений из тела.
- Ревью кода профилем deep (девять проходов) нашло две регрессии и обе закрыты:
безусловный второй разряд запирал законный досчёт навсегда, а выбор победителя
был квадратичен по числу присланных версий одного ключа.
- `healthlog reindex` собирает витрину из журнала (тела архива + учёт
доставок) в ОТДЕЛЬНЫЙ файл базы, строго по `(received_at, id)`; рабочую
базу читает без наката миграций и не трогает вовсе. Подмену делает
человек при остановленном сервисе: переименование поверх открытого
дескриптора портит базу молча.
- Журналом считается архив, а не таблица доставок: тело без учётной записи
заводится заново (метка из ULID, размер и хеш по распакованному телу),
запись без тела переносится, но не сворачивается. Оракул сходимости
встроен — два отпечатка и «объектов было/стало»; пустой журнал успехом не
считается.
- Прогон живого архива переехал на новый пакет: второго проигрывателя
журнала в проекте не осталось, а его утверждение о ключе сна перестало
быть константой, протухающей с каждой доставкой.
- слияние read-modify-write в одной транзакции, ключ точки — интервал,
победа более полной точки, тай-брейк по канонической форме
- хеш объекта как детектор изменений: совпал — записи нет
- _txlock=immediate и повтор всей тройки при SQLITE_BUSY/BUSY_SNAPSHOT
- миграции через goose.Provider: пакетные SetBaseFS/SetDialect писали глобалы
и давали гонку при двух Open
- POST /api/v1/ingest: токен, лимит тела, gzip, durable-запись тела в сырой
архив, учёт доставки в SQLite
- код ответа отражает доставку, а не разбор: битый JSON — 400, непонятое
содержимое — 200, данные уже сохранены и доразберутся позже
- сохраняется полный набор заголовков запроса с вычисткой секретов по имени
и по совпадению значения с токеном