Metric Correlations
CI / test (push) Successful in 1m3s
Release rolling / release (push) Has been cancelled

This commit is contained in:
Raven Scott
2026-07-18 22:43:42 -04:00
parent 5396d9d499
commit 93a239e8ef
11 changed files with 1258 additions and 31 deletions
+131
View File
@@ -0,0 +1,131 @@
import test from 'brittle'
import {
volumeScore,
ks2Score,
ksStatistic,
ksPValue,
resolveWindows,
spreadEvenly,
normalizeWeightsMethod,
computeWeights,
} from '../server/services/weights.js'
import { getStore } from '../server/services/store.js'
test('normalizeWeightsMethod aliases', (t) => {
t.is(normalizeWeightsMethod('KS2'), 'ks2')
t.is(normalizeWeightsMethod('vol'), 'volume')
t.is(normalizeWeightsMethod('anomaly'), 'anomaly-rate')
t.is(normalizeWeightsMethod('cv'), 'value')
t.is(normalizeWeightsMethod(''), '')
})
test('resolveWindows defaults baseline to 4x highlight', (t) => {
const now = Math.floor(Date.now() / 1000)
const w = resolveWindows({ after: now - 60, before: now }, 'volume')
t.absent(w.error)
t.is(w.highlightBefore - w.highlightAfter, 60)
t.is(w.baselineBefore, w.highlightAfter)
t.is(w.baselineBefore - w.baselineAfter, 60 * 4)
t.ok(w.shifts >= 2)
})
test('resolveWindows rejects short highlight', (t) => {
const now = Math.floor(Date.now() / 1000)
const w = resolveWindows({ after: now - 10, before: now }, 'ks2')
t.ok(w.error)
})
test('volumeScore is low for identical windows', (t) => {
const series = Array.from({ length: 40 }, () => 10)
t.ok(volumeScore(series, series) < 0.01)
})
test('volumeScore rises when highlight spikes', (t) => {
const baseline = Array.from({ length: 40 }, () => 10)
const highlight = Array.from({ length: 40 }, (_, i) => (i > 20 ? 40 : 10))
t.ok(volumeScore(baseline, highlight) > volumeScore(baseline, baseline))
})
test('ksStatistic is near zero for same distribution', (t) => {
const a = Array.from({ length: 50 }, (_, i) => i)
const b = Array.from({ length: 50 }, (_, i) => i)
t.ok(ksStatistic(a, b) < 0.05)
})
test('ks2Score higher for shifted diffs', (t) => {
const steady = Array.from({ length: 40 }, (_, i) => i * 0.1)
const spiked = Array.from({ length: 40 }, (_, i) => (i > 25 ? i * 2 : i * 0.1))
const same = ks2Score(steady, steady, 2)
const diff = ks2Score(steady, spiked, 2)
t.ok(diff >= same)
})
test('ksPValue bounds', (t) => {
t.ok(ksPValue(50, 0.01) > 0.5)
t.ok(ksPValue(50, 0.5) < 0.1)
})
test('spreadEvenly ranks higher raw as higher weight', (t) => {
const rows = [
{ id: 'a', weight: 0.1 },
{ id: 'b', weight: 5 },
{ id: 'c', weight: 2 },
]
spreadEvenly(rows)
const byId = Object.fromEntries(rows.map((r) => [r.id, r.weight]))
t.ok(byId.b > byId.c)
t.ok(byId.c > byId.a)
t.ok(byId.b <= 1 && byId.a > 0)
})
test('computeWeights without window returns alerts method', async (t) => {
const res = await computeWeights({ limit: 10 })
t.is(res.method, 'alerts')
t.ok(Array.isArray(res.results))
})
test('computeWeights volume scores store spike', async (t) => {
const store = getStore()
const now = Date.now()
const chart = 'system.cpu'
// Inject synthetic series: steady then spike in last 60s
const batch = []
for (let i = 300; i >= 0; i--) {
const ts = now - i * 1000
const spike = i < 45
batch.push({
chart,
context: 'system.cpu',
ts,
values: {
user: spike ? 80 : 5,
system: 2,
idle: spike ? 15 : 90,
iowait: 0,
steal: 0,
softirq: 0,
irq: 0,
guest: 0,
},
})
}
store.ingest(batch)
const before = Math.floor(now / 1000)
const after = before - 40
const res = await computeWeights({
method: 'volume',
after,
before,
points: 120,
limit: 50,
timeout: 10_000,
})
t.absent(res.error)
t.is(res.method, 'volume')
t.ok(res.view?.baseline)
t.ok(Array.isArray(res.results))
const hit = res.results.find((r) => r.id === chart)
t.ok(hit, 'system.cpu should appear in results')
t.ok(hit.weight > 0)
})