отработаны находки ревью кода
Триаж свёл 62 сырые находки девяти проходов к 33 причинам: 3 блокера, 4 «сейчас», 2 развилки. Все закрыты регрессионными тестами. - схема точки сна определяется по самой точке, а не по индексу в исходном массиве: одна пропущенная точка меняла эпизод и сводку местами - доставка сворачивается одной транзакцией: частичное состояние было недетерминированным (восемь прогонов — семь состояний) - граница размера на распакованном теле: 400 КиБ gzip разворачивались в 400 МиБ мимо max_body_mb - столкновение — расхождение канонических форм, а не байтов; WARN с координатами объекта; payload без HTML-экранирования - выравнивание по местной метке: получасовые зоны уводили часовую выгрузку в minute - доставка из одних суточных сводок больше не отвергается целиком - единицы не переписываются молча; счётчик считает сохранённые точки - все выходы Fold логируются, исход пишется на переживающем отмену контексте Четыре развилки вынесены блокерами в беклог.
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
# Правило выбора победителя при столкновении точек
|
||||
|
||||
**Приоритет:** блокеры
|
||||
|
||||
Вынуто ревью кода задачи `razbor-metrik-v-obekty` (профиль `deep`, находка №7
|
||||
триажа, severity major). Трогает записанный инвариант «при столкновении
|
||||
выигрывает более полная точка».
|
||||
|
||||
## Что решить
|
||||
|
||||
Как выбирать победителя, когда по одним координатам приехали разные
|
||||
содержимые. Сегодняшнее правило измеримо неверно в двух местах.
|
||||
|
||||
## Оракул: измерено
|
||||
|
||||
**Полнота — это счётчик ключей**, чьё значение не `null`, не `""` и не пусто.
|
||||
Поэтому `{}`, `[]`, `0` и `false` считаются содержательными:
|
||||
|
||||
```
|
||||
точка {"qty":0,"a":0,"b":0,"c":{},"d":[]} полнота 5
|
||||
точка {"date":"…","qty":123.4} полнота 2
|
||||
```
|
||||
|
||||
Вторая точка — настоящее измерение — проигрывает первой и стирается
|
||||
безвозвратно. Восстановить можно только из сырого архива, пока он жив.
|
||||
|
||||
**Тай-брейк при равной полноте** — лексикографический порядок канонических
|
||||
форм, то есть исход зависит от самого значения. Для накопительной метрики,
|
||||
которую досчитывают задним числом, это систематическая победа **меньшего**
|
||||
числа: `qty:1` бьёт `qty:100`. Недосчёт, неотличимый от нормы.
|
||||
|
||||
Частота на живом потоке **не измерена** — стоит прогнать по архиву до решения.
|
||||
|
||||
## Варианты и цена
|
||||
|
||||
**(1) Полнота по множеству ключей: побеждает надмножество; несравнимые
|
||||
множества — объединять поля, а не выбирать точку целиком.**
|
||||
Цена: средняя — правка спеки, `resolve` и тестов. Самое честное прочтение
|
||||
инварианта «ничего не теряем молча»: при несравнимых наборах не теряется
|
||||
ничего вообще.
|
||||
|
||||
**(2) Оставить счёт ключей, но не считать содержательными `{}`, `[]`, `0`,
|
||||
`false`, `""`.**
|
||||
Цена: малая. Правило остаётся играбельным (точку с лишними непустыми полями
|
||||
никто не мешает прислать), и произвол тай-брейка не решён.
|
||||
|
||||
**(3) При равной полноте побеждает точка более поздней доставки по
|
||||
`received_at`.**
|
||||
Цена: малая, но спека должна признать зависимость от журнала, и нужен
|
||||
детерминированный порядок **внутри** одной доставки — а именно там измерены
|
||||
столкновения (31 координата в 21 доставке из 89).
|
||||
|
||||
## Рекомендация
|
||||
|
||||
**(1).** Объединение полей при несравнимых наборах — единственный вариант, при
|
||||
котором столкновение вообще перестаёт быть выбором «кого потерять».
|
||||
|
||||
## Что стоит без решения
|
||||
|
||||
Правило работает и теперь **наблюдаемо**: столкновение считается расхождением
|
||||
канонических форм (а не байтов, как было), даёт `WARN` с координатами объекта
|
||||
и счётчик `overwrites`. Если правило начнёт терять — это станет видно в логе,
|
||||
а не через месяцы при сверке с экспортом Apple.
|
||||
|
||||
Связано: `openspec/specs/storage` → «Разрешение столкновений по полноте».
|
||||
Reference in New Issue
Block a user