Files
av 8331328134 Дозакрыты находки ревью по слиянию сущностей
- Правило покрытия получило второй разряд (условный, как у точек), запрет
  вырождения формы и счёт содержательных элементов ряда: скелет из скаляров и
  ряд из null больше не затирают маршрут. Победитель внутри доставки стал
  функцией множества версий — общим помощником с точками, — а провенанс
  поднимается и при совпавшем хеше, иначе отложенная доставка возвращала витрину
  к прежнему содержимому.
- Одно поле не того типа больше не уносит сущность, а пропуски видны в учётной
  записи доставки (миграция 00008, NULL = «не измерялось»); каноническая форма
  считается один раз и вне транзакции; откат бинаря поверх новой схемы отказывает
  на старте; текст ошибки разбора не несёт значений из тела.
- Ревью кода профилем deep (девять проходов) нашло две регрессии и обе закрыты:
  безусловный второй разряд запирал законный досчёт навсегда, а выбор победителя
  был квадратичен по числу присланных версий одного ключа.
2026-08-02 16:38:18 +03:00

11 KiB
Raw Permalink Blame History

Why

Изменение «тренировки и записи с собственным id» (f8200f7) прошло ревью не полностью: проходы adversary, ops и архитектурный на коде не запускались. Дозапуск нашёл девять причин, триаж оставил семь — у каждой прогнанный оракул. Две из них необратимы по последствиям: обеднённая версия тренировки затирает маршрут молча (в экспорте Apple маршрута нет, reindex проиграет то же поражение), а одно поле не той формы уносит тренировку целиком, причём доставка при этом числится разобранной — то есть ретеншен, решающий «что потеряется, если тело удалить», получит ложное «терять нечего».

Остальные пять — молчание там, где обещана детерминированность: откат бинаря поверх новой схемы стартует без слова, победитель внутри доставки зависит от порядка элементов на проводе, провенанс устаревает на каждой из ~26 повторных присылок, канонизация идёт внутри транзакции вопреки собственному комментарию (измерено: 768 МиБ пика, 5.019 с удержания блокировки), а тело доставки в 8 МиБ целиком уезжает в текст ошибки и оттуда в WARN.

What Changes

  • Сравнение содержания сущностей получает второй разряд и запрет вырождения формы. Сегодня Covers смотрит только наличие ключа и длину верхнеуровневого массива, поэтому версия-скелет (каждый массив заменён массивом той же длины из null, каждый вложенный объект — скаляром) признаётся равной настоящей и выигрывает тай-брейк журнала. Добавляются: ключи без содержания вторым разрядом (как у точек — «иначе ключ с пустым значением исчезает по жребию»), запрет покрывающей версии подменять объект или массив скаляром, и счёт содержательных элементов верхнеуровневого массива рядом с его длиной. Предел правила остаётся названным вслух и не закрывается: сокращение внутри элемента ряда (точка маршрута без altitude) ловится только сверкой с телом в архиве.
  • Победитель внутри одной доставки становится функцией множества версий, а не порядка элементов массива. Стандарт уже записан для точек и для сущностей молча не применён: попарная свёртка частичного порядка с тотальным тай-брейком нетранзитивна — [A,B,C] даёт C, [B,C,A] даёт A. Механизм выносится в одного помощника, общего с точками. Счётчик различающихся версий при этом считает по канонической форме, а не по байтам: требование постановки («differs при разных байтах») исполнено по форме, потому что порядок ключей у HAE нестабилен и побайтовый счётчик срабатывал бы на норме потока; детерминизм обеспечен тай-брейком по байтам, а не счётчиком.
  • Провенанс обновляется при совпавшем хеше. Сегодня совпадение хеша пропускает запись вместе с провенансом, и в сущности остаётся первая свёрнутая копия, а не победитель по журналу; при возврате содержимого к прежнему живая витрина расходится с reindex.
  • Одно поле не того ТИПА больше не уносит сущность. Пять полей заголовка читаются мягко — тем же принципом, который уже записан в коде для duration. Граница названа вслух: правило закрывает смену типа значения, но не смену формата строки, а наблюдался именно дрейф формата дат — тренировка с незнакомой датой по-прежнему теряется целиком, и закрыть это может только хранение сущности с неразобранной меткой (остаток). Пропуски сущностей при этом становятся видны в учётной записи доставки, а не только в логе, причём «не измерялось» отличимо от нуля.
  • Счётчик удержанных версий выводится в отчёт пересборки. Новое правило строже прежнего, а сходимость отпечатка его не проверяет по построению: живой приём и пересборка пользуются одним правилом и одинаково сойдутся на одинаково удержанной версии.
  • store.Open сверяет версию схемы перед миграцией. Версия базы выше версии бинаря — отказ, а не повод мигрировать; прецедент записан в OpenForRead.
  • Канонизация сущности уезжает за транзакцию по-настоящему. Каноническая форма считается один раз на версию, до входа в транзакцию, и из неё же берётся хеш — сегодня форма считается дважды (в хеше и в отложенном разборе), причём второй раз внутри inTx, который повторяется до пяти раз.
  • Текст ошибки разбора перестаёт нести значения из тела: называется тип токена и смещение во входе.
  • Лог delivery failed на приёме отличает занятость базы от прочих причин.
  • Не входит: хранение сущности с id, но неразобранной меткой (NULL-метка); пределы на размер одной сущности и секции и потоковый расчёт формы и хеша; принцип «data-миграции не отбирают строки по обрезаемым спискам»; длина очереди pending в /stats. Всё четыре уходят задачами беклога.

Capabilities

New Capabilities

Новых нет. Все семь пунктов — уточнения уже записанных правил разбора и хранения; новое понятие ввёл бы второй словарь для того же домена.

Modified Capabilities

  • parsing: заголовок сущности читается мягко — поле не той формы пропускает само поле, а не сущность; диагностика разбора не несёт значений из тела.
  • storage: содержание сущностей сравнивается с двумя разрядами, запретом вырождения формы и счётом содержательных элементов массива; победитель внутри доставки объявлен функцией множества с тотальным порядком; провенанс обновляется при совпавшем хеше, а метка изменения — нет; учётная запись доставки несёт число пропущенных сущностей, отличая ноль от «не измерялось»; открытие базы сверяет версию схемы; каноническая форма сущности считается вне транзакции и один раз.
  • ingest: лог отказа приёма отличает занятость базы от прочих причин.
  • reindex: число пропущенных сущностей внесено в перечень производных полей, которые пересборка не переносит; отчёт пересборки называет число удержанных версий сущностей.

Impact

  • internal/canonCovers, форма массива, экспорт хеша по готовой форме.
  • internal/storeentity.go (версия сущности, слияние, провенанс), bucket.go (комментарий о канонизации), store.go (страж версии схемы), новая миграция 00008 (колонка skipped_entities у доставки).
  • internal/haeentity.go (мягкий заголовок), hae.go (текст ошибок).
  • internal/fold, internal/ingest — проброс счётчика пропусков в учёт, различение занятости базы в логе.
  • docs/architecture.md, docs/database.md, docs/conventions.md, docs/review-journal.md.
  • Оракулы из tmp/adv/ переезжают обычными тестами в internal/canon, internal/store, internal/hae.