Changelog
Changes to the computed dataset, in the open: what changed, why, what we measured, and what to do if you consume the affected fields. Numbers are as recorded at fix time.
VPR replaces the vendor ratings — 12 fields retired, 13 introduced (2026-08)
What changed. The Racing Post Rating and Topspeed fields are retired from every API response and web surface: prevRpr, prevTsr, avgRprLast3, bestRprLast5, improvingRpr, rprTrend, the six connection averages (jockeyAvgRpr … damsireAvgRpr), and the raw rpr/tsr columns on race runners. In their place: the VPR family — vpr, vprConfidence, prevVpr, avgVprLast3, bestVprLast5, improvingVpr, vprTrend and the six …AvgVpr averages. The per-runner feature count moves from 179 to 180.
Why. Our data supplier withdrew redistribution rights for the proprietary ratings (the feed has served them empty since the ruling), so we built our own figure and took the opportunity to document it to a standard no licensed rating could be: VPR — the Veredus Performance Rating — an owned, openly-methodologised rating of every GB & IRE performance back to 1988. The complete method — sources, formula, measured scales, the drift investigation, validation and coverage — is published on the methodology page.
What to do. The VPR fields are nullable end to end: null means no rated history — never a sentinel 0, unlike the retired fields. Treat vprConfidence as evidence accounting (run count, anchor quality, recency), and note that VPR is not RPR — values on a given horse will differ. Historical analytics rows carry VPR throughout the archive, computed strictly point-in-time.
Beaten-lengths features: recomputed on true decimal margins (2026-08)
What changed. prevBeatenLengths, avgBeatenLast3 and bestBeatenLast5 are now computed from decimal beaten margins (nose = 0.05, short head = 0.10, … exactly as the photo finish recorded them) instead of whole-length integers. They are also now honest about missing data: where no margin is known — a non-finisher, or an archive row that never carried one — the value is null, never a fake 0. A companion field, beatenLengthsLowPrecision, is true when any contributing run comes from the pre-2005 archive, which only records whole lengths.
Why. When we replaced our margin ingestion we audited the archive and found two defects in the inputs these features had been computed on. First, margins had been stored rounded to whole lengths, so a nose beat and a half-length beat looked identical. Second — and much worse — 2.01 million archive rows stored a margin of 0 that actually meant "not recorded": nearly two-thirds of beaten runners looked like they had dead-heated. Features averaged over those inputs were systematically pulled towards zero.
The shift, measured. After re-pulling every reachable race (2005 onwards) with fractional margins and recomputing the full archive: rows showing a previous-run margin of exactly 0 fell from 72.2% to 9.9% — the survivors are genuine wins — while close finishes under a length rose from 235k rows to 1.17M. bestBeatenLast5 = 0 fell from 95.6% to 32.4%. The mean known previous-run margin moved from 2.43 to 4.10 lengths: the old figures weren't just imprecise, they were systematically compressed towards zero by fabricated dead-heats.
What to do. Treat null as "unknown" — it is not zero — and use beatenLengthsLowPrecision to decide whether a figure is precise enough for your use. The pre-2005 archive remains whole-length precision permanently: we would rather flag coarse data than invent precision.
