Files
av cd7a4c1493 отработаны находки ревью кода
Триаж свёл 62 сырые находки девяти проходов к 33 причинам: 3 блокера,
4 «сейчас», 2 развилки. Все закрыты регрессионными тестами.

- схема точки сна определяется по самой точке, а не по индексу в исходном
  массиве: одна пропущенная точка меняла эпизод и сводку местами
- доставка сворачивается одной транзакцией: частичное состояние было
  недетерминированным (восемь прогонов — семь состояний)
- граница размера на распакованном теле: 400 КиБ gzip разворачивались в
  400 МиБ мимо max_body_mb
- столкновение — расхождение канонических форм, а не байтов; WARN с
  координатами объекта; payload без HTML-экранирования
- выравнивание по местной метке: получасовые зоны уводили часовую выгрузку
  в minute
- доставка из одних суточных сводок больше не отвергается целиком
- единицы не переписываются молча; счётчик считает сохранённые точки
- все выходы Fold логируются, исход пишется на переживающем отмену контексте

Четыре развилки вынесены блокерами в беклог.
2026-08-01 19:02:05 +03:00

95 lines
4.4 KiB
Go

package hae
// assignLayers проставляет слой каждой группе точек.
//
// Правило проверено на всей истории (находка 33) и дважды ломалось на живых
// данных при более простых формулировках: классификация доставки целиком
// сложила минутные точки с посекундными и удвоила сумму за час, а
// классификация каждой метрики по отдельности растащила редкие метрики по трём
// слоям.
//
// Работающая формулировка в три шага:
//
// 1. плотная метрика (не меньше denseThreshold точек) классифицируется по
// собственному выравниванию;
// 2. редкая наследует самый мелкий слой среди плотных метрик этой доставки —
// её собственное выравнивание ничего не значит, одна метка на часе бывает
// и у минутного ряда;
// 3. доставка без плотных метрик вовсе наследует последний надёжно выведенный
// слой той же автоматизации, а если и его нет — берёт слой из НАДЁЖНОГО
// заголовка.
//
// Третий шаг не роскошь: измерено 2 такие доставки из 89, обе с заголовком
// `Default`. Заменить его заголовком нельзя — `Default` не означает режима.
func assignLayers(groups []group, meta Meta, res *Result) error {
delivery := deliveryLayer(groups)
if delivery == "" {
// Плотных метрик нет: наследуем от прошлых доставок этой автоматизации,
// иначе — от надёжного заголовка.
delivery = meta.FallbackLayer
if delivery == "" {
delivery = res.HeaderLayer
}
if delivery == "" && needsDerivedLayer(groups) {
return ErrLayerUnknown
}
}
res.Layer = delivery
// Расхождение сверяется только с надёжным заголовком: `Default` не
// означает режима, и сравнение с ним давало бы WARN на каждой доставке
// потока в пять минут — сигнал утонул бы в собственном шуме.
res.LayerMismatch = res.HeaderLayer != "" && delivery != res.HeaderLayer
for i := range groups {
g := &groups[i]
switch {
case g.fixed:
// Слой назначен схемой, выводить нечего.
case g.dense:
g.layer = g.alignment
default:
g.layer = delivery
}
}
return nil
}
// needsDerivedLayer говорит, осталась ли в доставке хоть одна группа, которой
// слой действительно надо вывести.
//
// Доставка, состоящая из одних суточных сводок сна, слоя не требует — он у них
// назначен схемой. Отказ ради неё был бы необратим: исход детерминирован, и
// пересборка из архива повторила бы его вечно, то есть автоматизация,
// настроенная только на сон, не донесла бы данных никогда.
func needsDerivedLayer(groups []group) bool {
for _, g := range groups {
if !g.fixed {
return true
}
}
return false
}
// deliveryLayer — самый мелкий слой среди плотных метрик доставки. Пустой,
// если плотных метрик нет.
//
// Группы с назначенным слоем в голосовании не участвуют: суточных сводок сна
// бывает больше порога плотности, и их полуночные метки иначе назначили бы
// всей доставке слой hour.
func deliveryLayer(groups []group) Layer {
var out Layer
for _, g := range groups {
if g.fixed || !g.dense {
continue
}
if out == "" {
out = g.alignment
continue
}
out = finer(out, g.alignment)
}
return out
}