store: при равной полноте точек побеждает пришедшая доставка

- байтовый порядок канонических форм остался тай-брейком только внутри одной
  доставки: на живом корпусе он решал 98,8% спорных координат и системно хранил
  меньшее значение, из-за чего step_count терял род и verify:archive был красным
- правило перестало быть коммутативным осознанно, поэтому порядок свёртки
  приведён к журнальному: проход воркера прекращается на отложенной доставке,
  а свёртка вне порядка журнала пишет WARN
- заведены счётчики PointsHeld и PointsErased — удержание полнотой и
  единственное направление, в котором правило теряет содержание
This commit is contained in:
av
2026-08-04 11:16:24 +03:00
parent ae607f1ceb
commit b278501a6e
44 changed files with 3780 additions and 172 deletions
+18
View File
@@ -474,6 +474,24 @@ func keysOf(m map[string]json.RawMessage) map[string]struct{} {
return out
}
// CarriesKeyAbsentIn отвечает, есть ли у f ключ с НЕПУСТЫМ значением, которого
// нет у g. Значения при этом не сравниваются вовсе.
//
// Заведено ради наблюдения, которого у правила слияния не было: разряд полноты
// гаснет, когда значения общих содержательных ключей разошлись (см. Relate), и
// тогда исход решает тай-брейк — а он может отдать победу точке, у которой
// содержательного ключа нет. Событие редкое (на живом корпусе 2 координаты из
// 80 129 спорных, обе несравнимые), но это единственное направление, в котором
// новое правило способно потерять содержание, и молчать о нём нельзя.
//
// Отдельным методом, а не через Relate: Relate отвечает про СОДЕРЖАНИЕ (с
// условием совпадения значений), здесь же нужен вопрос про имена, и смешение
// этих двух вопросов однажды уже дало правило, которое считало пустое поле
// содержанием.
func (f Fields) CarriesKeyAbsentIn(g Fields) bool {
return hasExtra(keysOf(f.full), keysOf(g.full))
}
// relateKeys сравнивает два множества ключей по включению.
func relateKeys(a, b map[string]struct{}) Fullness {
aExtra := hasExtra(a, b)