store: при равной полноте точек побеждает пришедшая доставка
- байтовый порядок канонических форм остался тай-брейком только внутри одной доставки: на живом корпусе он решал 98,8% спорных координат и системно хранил меньшее значение, из-за чего step_count терял род и verify:archive был красным - правило перестало быть коммутативным осознанно, поэтому порядок свёртки приведён к журнальному: проход воркера прекращается на отложенной доставке, а свёртка вне порядка журнала пишет WARN - заведены счётчики PointsHeld и PointsErased — удержание полнотой и единственное направление, в котором правило теряет содержание
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
|
||||
- **Секция:** ядро
|
||||
- **Зачем:** Доставка, свёрнутая раньше своей предшественницы, уходит в failed навсегда, и живая витрина молча расходится с пересборкой
|
||||
- **Теги:** goal:journal-and-rebuild
|
||||
- **Теги:** goal:journal-and-rebuild, question
|
||||
|
||||
**Решение принято владельцем 2026-08-02: вариант (в), но не раньше `/stats`.**
|
||||
До появления наблюдаемости живём вариантом (г) с уже записанным в спеке
|
||||
@@ -13,6 +13,70 @@
|
||||
Вынут ревью кода задачи «Разнести ответ приёма и свёртку доставки» (профиль
|
||||
`deep`, враждебный проход, находка с построенным путём и прогоном).
|
||||
|
||||
## Вопросы
|
||||
|
||||
**Решение (в) порядок журнала не восстанавливает, а цена окна выросла.**
|
||||
Записано 2026-08-04 задачей `tie-break-equal-completeness`.
|
||||
|
||||
Что случилось. Тай-брейк точек при равной полноте сменён на «побеждает
|
||||
пришедшая»: байтовый порядок системно хранил меньшее значение и стоил
|
||||
`step_count` его рода. Плата за это названа и внесена — порядок свёртки
|
||||
приведён к порядку журнала: проход воркера прекращается на первой отложенной
|
||||
занятостью доставке, а не перешагивает её. Это закрыло ту половину окна,
|
||||
которая была во власти воркера.
|
||||
|
||||
Вторая половина осталась и закрывается только на приёме: `received_at`
|
||||
фиксируется при выпуске ULID, строка учёта становится видимой после записи тела
|
||||
(184 мс на 62 МиБ), поэтому при конкурентном приёме доставка с более ранней
|
||||
меткой сворачивается позже своей преемницы.
|
||||
|
||||
**Что изменилось по сравнению с постановкой ниже.** Прежде цена окна была узкой:
|
||||
доставка без плотных метрик не выводила слой и уходила в `failed` — класс редкий
|
||||
(только автоматизации без плотных метрик). Теперь та же перестановка оставляет в
|
||||
витрине значение не той доставки, что стоит в журнале последней, — **у любой
|
||||
метрики**. Расхождение живой витрины с пересборкой перестало быть свойством
|
||||
редкого класса и стало свойством любого столкновения равной полноты, то есть
|
||||
98,8% спорных координат (находка 54).
|
||||
|
||||
**Почему это вопрос, а не работа.** Выбранный вариант **(в)** — повторы при
|
||||
`ErrLayerUnknown` — лечит невыводимый слой, но порядок журнала не
|
||||
восстанавливает: доставка всё равно сворачивается после своей преемницы, просто
|
||||
не уходит в `failed`. Порядок восстанавливают только **(а)** (резервировать
|
||||
строку учёта в начале `Accept`) и **(б)** (выдержка перед свёрткой). То есть
|
||||
после реализации (в) заявленное равенство «пересборка = приём» останется
|
||||
недостижимым, а спека хранения будет обещать его условно.
|
||||
|
||||
**Что сделано вместо, чтобы не молчать.** Воркер перед свёрткой спрашивает
|
||||
журнал, есть ли доставка позже этой в статусе `parsed` или `partial`; есть —
|
||||
пишется `WARN` с идентификатором. Расхождение стало наблюдаемым и лечится
|
||||
`healthlog reindex`. Это страж окна, и его сносят вместе с окном.
|
||||
|
||||
**Варианты и цена — те же, что ниже, плюс четвёртый.**
|
||||
|
||||
- **(в), как решено** — окно живёт, наблюдается `WARN`, лечится пересборкой.
|
||||
Дёшево; цена — «витрина есть свёртка журнала» держится на прогоне, который в
|
||||
гейт не входит.
|
||||
- **(а)** — резервировать строку учёта до записи тела. Закрывает окно совсем.
|
||||
Цена: ломается инвариант «тело на диск раньше строки учёта», появляется
|
||||
состояние «строка есть, тела нет», которое обязаны понимать пересборка и
|
||||
ретеншен.
|
||||
- **(а′)** — не резервировать, а **сериализовать** выпуск ULID вместе с записью
|
||||
тела и вставкой строки: тогда видимость строк монотонна вместе с метками, а
|
||||
инвариант «тело раньше строки» сохраняется. Цена: приём становится
|
||||
последовательным, и батч-доставки HAE выстраиваются в очередь (184 мс на
|
||||
62 МиБ на доставку).
|
||||
- **Провенанс на объект** (не на точку) — колонка с позицией журнала у часового
|
||||
объекта, тай-брейк по ней, как у сущностей. Правило снова становится
|
||||
коммутативным, окно перестаёт быть дефектом, барьер и `WARN` не нужны. Цена:
|
||||
миграция и смена формата, которую решение владельца 2026-08-04 запретило по
|
||||
бюджету, — но запрет там назван бюджетным, а не принципиальным.
|
||||
|
||||
**Рекомендация.** Пересмотреть (в) в пользу **(а′)**: он единственный закрывает
|
||||
окно, не трогая ни схему, ни инвариант «тело раньше строки». Если
|
||||
последовательный приём неприемлем по задержке — тогда провенанс на объект, а не
|
||||
жизнь с условным равенством: сегодня его проверяет один прогон, который гоняют
|
||||
руками.
|
||||
|
||||
## Что происходит
|
||||
|
||||
Метка `received_at` доставки фиксируется в момент выпуска ULID — **до** записи
|
||||
|
||||
Reference in New Issue
Block a user