store: при равной полноте точек побеждает пришедшая доставка
- байтовый порядок канонических форм остался тай-брейком только внутри одной доставки: на живом корпусе он решал 98,8% спорных координат и системно хранил меньшее значение, из-за чего step_count терял род и verify:archive был красным - правило перестало быть коммутативным осознанно, поэтому порядок свёртки приведён к журнальному: проход воркера прекращается на отложенной доставке, а свёртка вне порядка журнала пишет WARN - заведены счётчики PointsHeld и PointsErased — удержание полнотой и единственное направление, в котором правило теряет содержание
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
## Why
|
||||
|
||||
Тай-брейк при равной полноте точек сегодня — порядок канонических форм, и он
|
||||
решает **98,8% спорных координат** (83 956 из 84 978 при 453 171 координате):
|
||||
полнота отвечает лишь в 1,2% случаев. Лексикографический порядок системно берёт
|
||||
меньшее значение (1 847 из 1 912, находка 49), то есть хранит **устаревшую**
|
||||
версию точки там, где HAE досчитывает задним числом (находка 10).
|
||||
|
||||
У дефекта появился независимый оракул: `task verify:archive` покраснел на
|
||||
`master` без единого коммита, с ростом корпуса. Час `2026-08-03T07:00Z` метрики
|
||||
`step_count` получил четыре доставки с двумя различными значениями; победило
|
||||
меньшее, оно же приехавшее первым, и сверка слоёв объявила метрику мгновенной
|
||||
против 23 согласных часов. `step_count` ушёл в `unknown` — Read API больше не
|
||||
имеет права суммировать шаги.
|
||||
|
||||
Решение владельца от 2026-08-04: **при равной полноте побеждает пришедшая
|
||||
точка**, а не сохранённая. Значение при этом не интерпретируется — правило
|
||||
остаётся структурным.
|
||||
|
||||
## What Changes
|
||||
|
||||
- **BREAKING (содержимое витрины):** при равной полноте побеждает точка,
|
||||
пришедшая **этой** доставкой, а не сохранённая. Отпечаток витрины обязан
|
||||
измениться; состояние восстанавливается пересборкой из архива.
|
||||
- Порядок канонических форм остаётся тай-брейком **внутри одной доставки**, где
|
||||
провенанс общий и различать нечем.
|
||||
- **Правило слияния точек перестаёт быть функцией множества и становится явной
|
||||
функцией порядка журнала.** Отсюда — плата, которую изменение обязано
|
||||
внести целиком: порядок свёртки приводится к порядку журнала.
|
||||
- Фоновый воркер **прекращает проход на первой отложенной доставке**, а не
|
||||
перешагивает её. Иначе занятость базы переставляет доставки местами, и живая
|
||||
витрина расходится с пересборкой молча.
|
||||
- Свёртка доставки, у которой в журнале уже есть свёрнутая преемница, пишет
|
||||
`WARN`: остаточное окно (конкурентный приём делает строку учёта видимой
|
||||
не в порядке меток) закрыть без изменения приёма нельзя, но молчать о нём
|
||||
нельзя тем более.
|
||||
- Заводится счётчик «пришедшая точка проиграла сохранённой» — отдельно от
|
||||
общего `MergeStats.Overwrites`, который считает столкновения в обе стороны и
|
||||
различить их не даёт.
|
||||
- Схема не трогается: колонок провенанса на точку не заводится, формат
|
||||
`payload` не меняется, миграции нет.
|
||||
|
||||
## Capabilities
|
||||
|
||||
### New Capabilities
|
||||
|
||||
Новых нет.
|
||||
|
||||
### Modified Capabilities
|
||||
|
||||
- `storage`: тай-брейк при равной полноте точек — пришедшая побеждает
|
||||
сохранённую; порядок канонических форм остаётся только внутри доставки.
|
||||
Требование «победитель есть функция множества точек» заменяется на «функция
|
||||
множества точек и позиции в журнале». Новый счётчик удержаний.
|
||||
- `ingest`: проход воркера прекращается на первой отложенной доставке; свёртка
|
||||
вне порядка журнала становится наблюдаемой.
|
||||
- `reindex`: посылка сходимости («приём шёл последовательно») из оговорки
|
||||
сценария становится названным условием требования — теперь от порядка свёртки
|
||||
зависит не только вывод слоя, но и содержимое точек.
|
||||
|
||||
## Impact
|
||||
|
||||
- `internal/store/bucket.go` — `mergePoints`, `resolve`, `candidate`,
|
||||
`pointLess`, `MergeStats`.
|
||||
- `internal/store/delivery.go` — запрос «есть ли свёрнутая доставка позже этой».
|
||||
- `internal/replay/worker.go` — барьер на отложенной доставке, `WARN` о свёртке
|
||||
вне порядка журнала.
|
||||
- `internal/fold/fold.go` — проброс нового счётчика в итог свёртки и в лог.
|
||||
- Витрина в `./data`: отпечаток изменится. Пересборка — действие человека при
|
||||
остановленном сервисе, этим изменением не выполняется.
|
||||
- Оракулы: `task verify:archive` (ноль противоречащих часов, `step_count`
|
||||
снова накопительная), тест сходимости «живой приём = пересборка» с отложенной
|
||||
доставкой.
|
||||
Reference in New Issue
Block a user