- байтовый порядок канонических форм остался тай-брейком только внутри одной доставки: на живом корпусе он решал 98,8% спорных координат и системно хранил меньшее значение, из-за чего step_count терял род и verify:archive был красным - правило перестало быть коммутативным осознанно, поэтому порядок свёртки приведён к журнальному: проход воркера прекращается на отложенной доставке, а свёртка вне порядка журнала пишет WARN - заведены счётчики PointsHeld и PointsErased — удержание полнотой и единственное направление, в котором правило теряет содержание
10 KiB
10 KiB
1. Правило слияния точек
- 1.1
candidateполучает флагincoming; схлопывание совпавших канонических форм поднимает флаг, а байты оставляет встреченные первыми - 1.2
pointLess— лексикографический порядок по паре(не incoming, каноническая форма);pointDominatesне трогается - 1.3
resolveвозвращает признак «победил сохранённый при наличии пришедших»;mergePointsсчитает удержания - 1.4
MergeStats.PointsHeldиPointsHeldAt; проброс черезmergeResult,SaveBuckets,fold.Stats,replay.Outcome/Reportи лог свёртки — без значений точек
2. Порядок свёртки равен порядку журнала
- 2.1
Worker.Passпрекращает проход на исходеDeferred; доставка, оставшаясяpendingбез такого исхода, курсор двигает - 2.2
Store.ParsedAfter— есть ли доставка позже данной в статусеparsedилиpartial(кортежный предикат; индекс —delivery_received_at, цена измерена и названа в design.md) - 2.3 воркер пишет одну запись
WARNна доставку о свёртке вне порядка журнала; пересборка эту проверку не выполняет
3. Тесты
- 3.1 пришедшая побеждает сохранённую при равной полноте
- 3.2 столкновение внутри одной доставки решается порядком канонических форм и не зависит от порядка элементов массива
- 3.3 повторная присылка канонически совпавшего содержимого не переписывает объект (хеш не двигается)
- 3.4 полнота сильнее происхождения; счётчик удержаний растёт
- 3.5 сходимость: живой путь через воркер с отложенной занятостью базы доставкой даёт тот же отпечаток, что пересборка
- 3.6 проход воркера не перешагивает отложенную доставку
- 3.7
WARNо свёртке вне порядка журнала пишется, не содержит значений и не пишется наfailed-преемнице - 3.8 при разошедшихся значениях пустые ключи сохранённой точки её не удерживают (сценарий, парный к 3.4)
4. Документы
- 4.1
docs/architecture.md— «Разрешение столкновений» плюс все упоминания правила: инвариант в шапке, «порядок прихода значения не имеет» в разделе синхронизации; таблица двух правил равной полноты (точки против сущностей) с критерием выбора - 4.2
CLAUDE.md— формулировка инварианта «ничего не теряем молча»: «выигрывает более полная, при равной полноте — стоящая позже в журнале» - 4.3
internal/store/entity.go— комментарии, чей довод («порядок свёртки журналу не равен») этим изменением сужен до окна видимости - 4.4
docs/research/apple-health.md— перемер 2026-08-04 с методом: ключ со слоем, 155 доставок, 460 995 координат, 80 129 спорных, 981 полнотой, 79 148 тай-брейком, 75 494 меняют исход - 4.5
docs/review.md— запись о дефекте (посылка оракула умерла с ростом корпуса) и о том, что конвейер её не ловил - 4.7 вопрос владельцу в
docs/tasks/items/journal-order-on-ingest.md(раздел «Вопросы» + тегquestion): решение (в) порядок журнала не восстанавливает, а цена окна выросла с вывода слоя до значений точек - 4.6
docs/conventions/— промоут двух правил: «в проверке на живом корпусе утверждается инвариант, число печатается» и «оракул сходимости называет свою посылку рядом с собой»
5. Оракулы
- 5.1
task gateзелёный - 5.2
task verify:archive— ноль противоречащих часов,step_countнакопительная, отпечаток изменился - 5.3
task verify:archiveвторой раз подряд — тот же отпечаток - 5.4
task verify:busyзелёный - 5.5 замер удержаний на живом архиве — число названо, не утверждено
Приёмочные критерии из ревью предложения (профиль design, проход rubric)
Свойства, по которым судится узел рода «правило слияния версий в хранилище-свёртке по журналу» плюс «упорядочивающий воркер очереди».
- Р1 исход слияния — функция префикса журнала и только его; запрос воркера «есть ли доставка позже» влияет на лог и MUST NOT влиять на содержимое
- Р2 законные расхождения живого пути и пересборки перечислены поимённо, и у оракула названа посылка
- Р3 повторная свёртка идемпотентна на суффиксе журнала; свёртка более ранней доставки после более поздней меняет состояние наблюдаемо
- Р4 победитель — функция множества кандидатов и их происхождения, но не порядка точек внутри доставки; отношение победы ациклично (проверка перестановками ТРОЙКИ, не пары)
- Р5 правило тотально на вырожденном входе: один кандидат, равные канонические формы с разными байтами, не-JSON, несравнимые множества
- Р6 победитель сохраняется дословно; цена лишних записей названа числом
- Р7 правило структурно: не читает ни значение точки, ни род, ни витрину
- Р8 барьер очереди не останавливает поток: названо, что держит очередь и что её освобождает; канонизация и сжатие вне транзакции записи
- Р9 наблюдаемость отличает «правило сработало» от «не сработало» и не несёт значений здоровья; тест на утечку разбирает запись, а не ищет подстроку в сыром буфере
- Р10 ни одно утверждение теста не пришпилено к числу, производному от размера корпуса: утверждается инвариант, число печатается
- Р11 два правила равной полноты (точки и сущности) не расходятся молча: различие механизмов и критерий выбора записаны
- Р12 место снапшота Apple в порядке журнала — либо названо, либо явно отложено до задачи импорта (сегодня стадия снапшота пуста)
Критерии приёмки задачи
Приходят из docs/tasks/items/tie-break-equal-completeness.md, дословно. Числа
в них производны от размера корпуса — по каждому названо, чем именно измерено и
что при этом печатается, а не утверждается (docs/review.md, 2026-08-02).
- ни одна метрика не теряет род из-за столкновения равной полноты;
step_countснова накопительная — оракул:task verify:archive, ноль противоречащих часов - живая свёртка и пересборка дают один отпечаток витрины — оракул:
healthlog reindexпротив живого состояния; это же и есть страховка от потерянной коммутативности - повторный прогон реплея даёт тот же отпечаток — оракул:
task verify:archive, второй прогон подряд - столкновение внутри одной доставки разрешается прежним байтовым порядком — оракул: тест на двух точках одной доставки с равной полнотой
- «пришедшая точка проиграла сохранённой» считается отдельно от общего
MergeStats.Overwrites— оракул: тест плюс прогон на живом архиве, число сходится с замером 2026-08-04