- каждая запись каталога задач получила тип вместо тега kind: и префикса заголовка; секция роадмапа «Разработка» стала «Сопровождением», порядок секций канонический - поправлены протухшие факты: нереализованные маршруты Read API, MCP и `healthlog import`, словарь слоёв в инварианте, семантика гейта по покрытию диффа, периметр перестал дублировать security.md - замер слияния переведён с находки 49 на находку 54, заполнены Purpose спек storage и parsing
6.9 KiB
🔬 Измерить, нужно ли правило полноты рядом с LWW
- Тип: research
- Категория: Ядро
- Зачем: Полнота решает 1,2% спорных координат, и неизвестно, была ли более полная точка более поздней — от этого зависит, нужна ли она вообще
- Теги: goal:merge-robustness, sprint:2026-08-03
Правило слияния перестаёт зависеть от того, чей набор полей богаче, — либо зависит ровно там, где замер показал, что без этого теряются данные. Сегодня неизвестно, какой из двух случаев верен.
Двигает строку «Завершения» цели: «Правило выбора между версиями измерено: полнота либо нужна, либо снята».
Откуда задача
Владелец предложил 2026-08-04 держаться стратегии LWW («выигрывает
последняя»): экспорт Apple
Health — база снапшота, новые доставки HAE затирают предыдущие. Это отменяет
critical-инвариант CLAUDE.md «при столкновении выигрывает более полная
точка, а не последняя», и потому меняется не молча, а этой задачей.
Соседняя задача «Тай-брейк при равной полноте» двигала то же правило в ту же сторону, но осторожнее: она поменяла только тай-брейк при равной полноте, оставив саму полноту первичной. Она сделана 2026-08-04 — решение записано в ADR о тай-брейке по порядку журнала. Эта задача решает, надо ли снимать и саму полноту.
Замер — первый шаг, и от него ветвится всё остальное
Из 84 978 спорных координат живого архива (замер 2026-08-04, tmp/diag):
| координат | |
|---|---|
| решено полнотой | 1 022 (1,2%) |
| упало на тай-брейк | 83 956 (98,8%) |
Вопрос ровно один: в этих 1 022 случаях более полная точка была более поздней или более ранней?
- Всегда более поздней — полнота ничего не решает сверх порядка, LWW
строго проще и ничего не теряет. Ветка полноты удаляется, инвариант в
CLAUDE.mdпереписывается. - Иногда более ранней — значит HAE присылает обеднённые версии задним числом, и LWW будет молча стирать поля. Тогда полнота остаётся, а граница её применения записывается числом: сколько таких случаев, у каких метрик, какие поля пропадали.
Замер обязан различать точки метрик и сущности (workouts,
stateOfMind): у сущностей отношение другое — покрытие, код другой
(internal/store/winner.go), и он не мерялся вовсе.
Оба исхода — законный результат задачи. Исход «полнота нужна» не считается провалом и не отменяет предложение владельца: он его уточняет границей.
Две рамки, без которых «экспорт — источник правды» ломает работающее
Обе выведены при постановке и в замере не нуждаются:
- По времени. Экспорт — снапшот на дату выгрузки; доставки HAE после этой
даты обязаны его перекрывать, иначе новые данные не доедут. Совместимо с
инвариантом «хранилище — свёртка по журналу»:
import(экспорт) + replay(доставки по received_at). - По типам.
stateOfMindв экспорте Apple отсутствует ни одним типом (измерено,docs/research/apple-health.md). Для него единственный источник — доставки HAE, и объявить экспорт источником правды для него нельзя.
Критерии приёмки
- для 1 022 координат, где полнота решила исход, названо число: в скольких из них более полная точка была более поздней — оракул: прогон замера на живом архиве, число воспроизводится вторым прогоном
- тот же вопрос отвечён отдельно для сущностей (
workouts,stateOfMind) — оракул: тот же прогон, отдельная колонка - правило слияния приведено к исходу замера, и
CLAUDE.mdговорит то же, что делает код — оракул: глазами, сверка формулировки инварианта с реализацией - повторный прогон живого архива даёт тот же отпечаток, живая свёртка равна
пересборке — оракул:
task verify:archiveдважды подряд - ни одна метрика не потеряла род из-за изменения правила — оракул:
task verify:archive, ноль противоречащих часов
Рамки
Схему не трогаем. Отпечаток витрины изменится — пересборка обязательна и делается человеком при остановленном сервисе; подмена файла базы необратима и в задаче не выполняется. Тай-брейк при равной полноте уже влит, поэтому замер отвечает про действующее правило, а не про снятое.
Связано: находки 10, 47, 49, 53; docs/architecture.md → «Разрешение
столкновений»; docs/review.md, запись 2026-08-04.