Metric
World recordBundles every derivable metric from a round's 5 solves into one aggregator: official Single / Average plus BAo5 (best 3 of 5), WAo5 (worst 3 of 5), Mo5 (mean of all 5, no trim), BPA / WPA (best / worst possible average from the first 4), Median, Best / Worst Counting, Worst, Variance, and Best/Avg Ratio — 13 metrics in total.
One raw input (5 attempts per round) repeatedly squeezed to surface luck vs consistency. The UI groups the 13 metrics into Basic / Composite / Distribution dropdowns.
By the numbers
Data source
This class issues no SQL of its own — query() returns `. Each child (wr_bao5 / wr_mo5 / wr_bpa / ...) hooks into the RoundMetric base class, which runs one batch SQL across all ao5 events and shares the attempt rows. Each child only overrides computeMetric(values)` to define how the 5 numbers collapse.
The aggregator wraps the 13 children's toJson() outputs as MetricPanel[] keyed by id, and adds metricGroups metadata so the UI can render group dropdowns.
// 13 个子类按 id 注册,逐个 import + run
for (const def of METRIC_DEFS) {
const mod = await def.module();
const inst = new (Object.values(mod).find(v => typeof v === 'function'))();
const sub = await inst.toJson();
metricPanels.push({
id: def.id, labelEn: def.label,
labelZh: sub.titleZh, panels: sub.panels,
});
if (global.gc) global.gc(); // 子统计完释放,防 OOM
}Algorithm / pipeline
RoundMetric shares one SQL across all batch-mode children — round attempts come back as a GROUP_CONCAT string. The cached rows feed all 11 batch children, dodging 11× redundant queries.filterWrHistory(strict=true).toJson() outputs concatenate in METRIC_DEFS order; each entry holds id / labelEn / labelZh / panels. The UI matches metricPanels[i].id against the dropdown.Key formulae
Caveats & edges
- All metrics target ao5 events only (
EVENTS_WITH_AO5); BLD / MBLD / FMC have no 5-solve grouping and don't participate. - BPA / WPA are order-sensitive on the first 4 attempts: ordering comes from
attempt_number, which SQL preserves viaGROUP_CONCAT(... ORDER BY attempt_number). - Worst Counting tolerates at most 1 DNF (else the ao5 itself is DNF); Worst Solve requires all 5 valid.
- Median returns null with ≥ 3 DNFs; otherwise picks the sorted index 2 — DNFs shift the median up to a higher valid solve.