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
+39 -1
View File
@@ -143,7 +143,7 @@
**Перестали проверять сознательно.**
- Прогон живого архива (`task verify:archive`) и свёртка под удерживаемой
блокировкой (`task verify:busy`) в гейт не входят: минута и 25 секунд
блокировкой (`task verify:busy`) в гейт не входят: минута и около 50 секунд
соответственно, плюс данные, которых нет ни на какой другой машине. Гоняет их
человек перед задачей, трогающей разбор или слияние (запись 2026-08-02,
прогон живого архива был красным и об этом никто не знал).
@@ -436,3 +436,41 @@
файлов каталога получили одну дату при переезде на канон (коммит `d79189b`),
и храповик на давно неподвижных задачах включится только с накоплением
собственной истории правок. Порция этой сессии отобрана по цели.
## 2026-08-04 — оракул `verify:archive` покраснел от роста корпуса второй раз за два дня [проскочил]
- **Где:** `internal/store/bucket.go`, `pointLess` — тай-брейк равной полноты
- **Симптом:** `task verify:archive` красный на `master` без единого коммита:
`step_count: противоречащих часов 1 при 22 согласных`. Разбор довёл до
причины: на час `2026-08-03T07:00Z` приехало четыре точки с двумя значениями,
победило меньшее — оно же приехавшее первым, — потому что его каноническая
форма сортируется раньше. Сверка слоёв объявила метрику мгновенной против 22
согласных часов, и `step_count` ушёл в `unknown`.
- **Причина:** байтовый тай-брейк выбран как «детерминированный и ни на что не
опирающийся», и это было верно. Неверной оказалась оценка его области:
считалось, что он крайний разряд после полноты. Перемер (находка 54) на
настоящем ключе: полнота решает 1,2% спорных координат, тай-брейк — 98,8%.
То есть «выигрывает более полная точка» — не главное правило слияния, а
редкий частный случай, и главным всё это время был лексикографический
порядок JSON.
- **Чем воспроизведён:** `task verify:archive` до и после. До — FAIL,
`step_count unknown`, отпечаток `bf36b477…`; после — PASS, `step_count
cumulative`, отпечаток `03aace91…`, ноль противоречащих часов, и заодно
`headphone_audio_exposure` вернулся из `unknown` в `instant`.
- **Почему не поймали:** та же причина, что 2026-08-02 и 2026-08-03, третий раз
подряд. Прогон живого архива в гейт не входит, значит его краснота видна
только следующей задаче, которая до него дотянется. Но добавилось новое:
здесь протухла не константа, а **оценка области действия правила**, снятая на
корпусе, где спорных координат было 2 897. Ни один проход ревью не
перепроверяет числа, на которых стоит нормативный текст спеки, — они читаются
как факт. Поймал это проход `specs` на профиле `design`: он сверил число в
дельте с находкой 49, увидел расхождение в 29 раз и потребовал назвать метод.
Метод оказался неверным (ключ без слоя), число — завышенным, а соотношение —
верным.
- **Что меняем:** ничего в составе конвейера — он сработал. Два правила
промоутятся в конвенции (см. `conventions/testing.md`): «в проверке на живом
корпусе утверждается инвариант, число печатается» — оно было записано здесь
2026-08-02 со словами «годится в конвенции» и не доехало, после чего класс
повторился дважды; и «оракул сходимости называет свою посылку рядом с собой».
Третий случай одного класса за три дня — это уже не совпадение, и в
`docs/conventions/testing.md` он теперь правило, а не запись в журнале.