store: при равной полноте точек побеждает пришедшая доставка
- байтовый порядок канонических форм остался тай-брейком только внутри одной доставки: на живом корпусе он решал 98,8% спорных координат и системно хранил меньшее значение, из-за чего step_count терял род и verify:archive был красным - правило перестало быть коммутативным осознанно, поэтому порядок свёртки приведён к журнальному: проход воркера прекращается на отложенной доставке, а свёртка вне порядка журнала пишет WARN - заведены счётчики PointsHeld и PointsErased — удержание полнотой и единственное направление, в котором правило теряет содержание
This commit is contained in:
@@ -151,3 +151,63 @@ func seedPending(t *testing.T, st *store.Store, id string, at time.Time) {
|
||||
t.Fatalf("запись доставки %q: %v", id, err)
|
||||
}
|
||||
}
|
||||
|
||||
// Свёртка вне порядка журнала обнаруживается запросом «есть ли позже меня уже
|
||||
// разобранная доставка». Это единственное наблюдение, по которому расхождение
|
||||
// живой витрины с пересборкой видно до сверки отпечатков.
|
||||
func TestParsedAfterВидитТолькоЗаписавшихВВитрину(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
st := open(t)
|
||||
ctx := context.Background()
|
||||
at := ts(t, "2026-08-01T12:00:00Z")
|
||||
|
||||
early := at
|
||||
late := at.Add(time.Second)
|
||||
seedPending(t, st, "d-early", early)
|
||||
seedPending(t, st, "d-late", late)
|
||||
|
||||
// Пока преемница в очереди, расхождения нет.
|
||||
found, err := st.ParsedAfter(ctx, early, "d-early")
|
||||
if err != nil {
|
||||
t.Fatalf("ParsedAfter: %v", err)
|
||||
}
|
||||
if found {
|
||||
t.Error("неразобранная преемница засчитана расхождением")
|
||||
}
|
||||
|
||||
// `failed` преемницей не считается: в витрину она ничего не записала, и
|
||||
// перестановка относительно неё содержимого не разводит. Исход этот
|
||||
// штатный — невыводимый слой, — и его учёт превратил бы WARN в шум.
|
||||
if err := st.FinishParse(ctx, "d-late", store.ParseOutcome{Status: store.ParseFailed}); err != nil {
|
||||
t.Fatalf("FinishParse: %v", err)
|
||||
}
|
||||
found, err = st.ParsedAfter(ctx, early, "d-early")
|
||||
if err != nil {
|
||||
t.Fatalf("ParsedAfter: %v", err)
|
||||
}
|
||||
if found {
|
||||
t.Error("отказавшая преемница засчитана расхождением")
|
||||
}
|
||||
|
||||
// А разобранная — считается.
|
||||
if err := st.FinishParse(ctx, "d-late", store.ParseOutcome{Status: store.ParseDone}); err != nil {
|
||||
t.Fatalf("FinishParse: %v", err)
|
||||
}
|
||||
found, err = st.ParsedAfter(ctx, early, "d-early")
|
||||
if err != nil {
|
||||
t.Fatalf("ParsedAfter: %v", err)
|
||||
}
|
||||
if !found {
|
||||
t.Error("разобранная преемница не замечена: свёртка вне порядка журнала осталась бы молчащей")
|
||||
}
|
||||
|
||||
// Сама преемница расхождением не является: предикат строго «позже».
|
||||
found, err = st.ParsedAfter(ctx, late, "d-late")
|
||||
if err != nil {
|
||||
t.Fatalf("ParsedAfter: %v", err)
|
||||
}
|
||||
if found {
|
||||
t.Error("доставка засчитала расхождением саму себя")
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user