Files
healthlog/openspec/changes/archive/2026-08-01-polnota-tochki-mnozhestvom-klyuchey/proposal.md
T
av 7a7594e3e7 полнота точки — множество ключей, победитель — функция множества точек
- отношение победы было нетранзитивным: полнота (частичный порядок) плюс
  тай-брейк (тотальный) в попарной свёртке давали цикл, из-за которого одна
  и та же доставка меняла содержимое объекта при каждой пересборке
- надмножество побеждает только при совпадении значений общих содержательных
  ключей: иначе точка без единого измерения вытесняла измерение
- Less стал тотальным, isEmpty не материализует значение, имя метрики в
  координате столкновения обрезается, отпечаток витрины включает units и sealed
- на живом архиве строгий no-op: 1737 объектов, содержимое совпало побайтово
2026-08-01 21:05:43 +03:00

4.6 KiB

Why

Полнота точки при разрешении столкновения считается числом ключей с непустым значением. Число сравнимо всегда, а сравнивать надо содержание: точка с пятью полями, где значения 0, {} и [], выигрывает у настоящего измерения с двумя полями и стирает его безвозвратно.

точка {"qty":0,"a":0,"b":0,"c":{},"d":[]}   полнота 5   ← выигрывает сегодня
точка {"date":"…","qty":123.4}              полнота 2   ← стирается

Замер по всем 99 доставкам (docs/local-research.md, находка 49) даёт основание для правильной формы правила: настоящих столкновений 2 897 из 444 256 координат (0.65%), из них наборы полей сравнимы в 981 случае, равны в 1 916 и несравнимы ни разу. То есть правило сводится к «побеждает надмножество», а самая дорогая часть — объединение полей из двух точек — на живом потоке не нужна вовсе.

What Changes

  • Полнота точки перестаёт быть числом и становится множеством ключей с непустым значением. Побеждает строгое надмножество; равные множества уходят на прежний тай-брейк.
  • Пустым значением считается не только null и "", но и 0, {}, []: поле, не несущее содержания, не делает точку полнее отсутствующего поля. Это и есть та часть, из-за которой сегодняшний счётчик даёт неверный исход на приведённой выше паре. false пустотой НЕ считается — для булева поля это одно из двух значений, а не отсутствие сведений.
  • Надмножество побеждает только при совпадении значений общих содержательных ключей: иначе точка без единого измерения вытесняла бы измерение.
  • Несравнимые множества (ни одно не является надмножеством другого) не объединяются, а считаются: счётчик в итоге слияния плюс WARN с координатами объекта (метрика, слой, час), без значений. Победителя в этом случае выбирает тот же тай-брейк, что и при равной полноте.
  • Не меняется тай-брейк при равной полноте: он зависит от рода метрики, а род измеряется сверкой слоёв (задача rod-agregacii-i-katalog). Выбирать его сейчас — угадывать то, что скоро станет известно точно.

Capabilities

New Capabilities

Нет.

Modified Capabilities

  • storage: требование «Разрешение столкновений по полноте» переформулируется с числа значащих полей на множество ключей с непустым значением; добавляется наблюдаемость несравнимых множеств.

Impact

  • internal/canonCompleteness (число) заменяется сравнением множеств ключей; расширяется понятие пустого значения.
  • internal/store/bucket.goresolve и MergeStats (новый счётчик и координаты несравнимых случаев).
  • internal/fold — новая ветвь WARN в единственном логирующем чекпоинте.
  • openspec/specs/storage/spec.md — дельта-спека.
  • Витрина не мигрирует: правило меняет исход только там, где сегодня он неверен. Проверяется прогоном task verify:archive на живом архиве — состояние обязано совпасть с прежним.