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

6.4 KiB

MODIFIED Requirements

Requirement: База назначения пригодна к подмене

База назначения SHALL нести полноценный учёт доставок, а не только объекты витрины: подменяется файл базы целиком, а не одна таблица.

Состав переноса нормируется явно, потому что колонки delivery двух разных родов:

факты журнала   id, received_at, automation_name, automation_id, aggregation,
                period, session_id, bytes, sha256, raw_path, headers
                                              ← переносятся дословно
производные     parse_status, points, derived_layer, uncovered_sections,
                skipped_entities              ← начинаются пустыми

Перечень производных полей SHALL пополняться тем же изменением, которое заводит новое поле: он единственное место, где сказано, чему нельзя пережить пересборку, и следующий автор решает по нему. Поле, не внесённое в перечень, однажды перенесут «для полноты учёта».

Факты журнала SHALL переноситься дословно, включая записи, тела которых в архиве уже нет. Заголовки восстановлению не подлежат ничем — в архиве их нет, — и неполный перенос уничтожил бы их первой же подменой, а с ними и вывод слоя для всех доставок, не только подобранных. Запись без тела при этом не сворачивается и в наследовании слоя не участвует: выведенного слоя у неё нет.

Производные от разбора поля MUST начинаться пустыми. Перенос derived_layer особенно опасен и незаметен: доставка, чей повторный разбор отказал (штатный исход, когда слой не выводится), сохранила бы слой прежнего разбора, и следующая доставка той же автоматизации унаследовала бы его. Витрина снова стала бы функцией предыдущего прогона, а не журнала, причём оба прогона были бы самосогласованы — проверка «повторная пересборка ничего не меняет» этого не ловит. Для числа пропущенных сущностей цена та же и хуже: пустота у него значит «не измерялось», и перенесённое число выдавало бы измерение прежнего разбора за измерение текущего — а по нему принимается необратимое решение об удалении тела.

Scenario: Учёт переносится полностью

  • WHEN пересборка завершилась
  • THEN число строк учёта в базе назначения равно числу строк рабочей базы плюс число подобранных тел
  • AND заголовки перенесённых доставок совпадают с рабочей базой дословно

Scenario: Слой прошлого разбора в наследование не попадает

  • WHEN в рабочей базе у доставок проставлен derived_layer
  • THEN отпечаток пересобранной витрины совпадает с отпечатком пересборки того же журнала из учёта без проставленных слоёв

Scenario: Число пропущенных сущностей не переносится из журнала

  • WHEN в рабочей базе у доставки проставлено число пропущенных сущностей, а тела этой доставки в архиве уже нет
  • THEN в базе назначения её число пропущенных сущностей отсутствует

ADDED Requirements

Requirement: Отчёт пересборки показывает удержанные версии сущностей

Отчёт пересборки SHALL называть число версий сущностей, удержанных правилом «не теряем содержания», — тем же счётчиком, что ведёт свёртка.

Без него правило слияния сущностей проверить нечем. Сходимость отпечатка его не проверяет по построению: живой приём и пересборка пользуются одним правилом и одинаково сойдутся на одинаково удержанной версии. То есть слишком строгое правило — например, замораживающее тренировку на старой версии из-за исчезнувшего ключа с пустым значением — выглядело бы как идеальная сходимость. Счётчик несравнимых наборов точек выведен в отчёт по ровно той же причине и тем же рассуждением.

Число SHALL печататься всегда, а не только при ненулевом значении: ноль здесь утверждение, а не отсутствие новостей.

Scenario: Удержанная версия видна в отчёте пересборки

  • WHEN журнал содержит доставку, приехавшая версия сущности в которой теряет содержание сохранённой
  • THEN отчёт пересборки называет число удержанных версий больше нуля