- tmp/research/fixtures.py собирает фикстуры из архива, вычищая измерения и сохраняя порядок ключей, форму литералов, выравнивание меток и невидимые символы; шесть фикстур в internal/hae/testdata - internal/canon — общий дом канонической формы, полноты и хеша: числа читаются литералом через json.Number, округление до 12 значащих цифр - internal/hae — разбор секции metrics, вывод слоя по метрике, разделение схем сна, координаты интервалом; recover внутри Parse, фаззинг - миграция bucket и docs/database.md
79 lines
3.6 KiB
Go
79 lines
3.6 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 == "" {
|
|
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
|
|
}
|
|
|
|
// 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
|
|
}
|