Fix: the incumbent ruler respects the allow-list (correcting my own model)
My first delta run modelled the incumbent as first-row-wins over the RAW feed and reported that an EXCLUDED book was "the market" on 69% of MLB prop-lines, with prizepicks alone at 47%. That is WRONG and I caught it before it went anywhere. normalizeProps applies ALLOWED_BOOKS BEFORE gradeSlateService.dedupeProps runs, so DFS books never reach the incumbent. The allow-list, for all the coverage it costs, does keep DFS out of the ruler. incumbentFairProb now takes the allow-list (defaulting to the live ALLOWED_BOOKS) and reproduces the real chain. Two tests lock it, including that a prop with no admitted book has NO incumbent -- it is never graded at all, which is the real loss and is already measured as invisible_props. Overstating the incumbent's badness would have been as dishonest as understating it, and more persuasive. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QJs13VsyiSKYQP6rj3NNmc
This commit is contained in:
@@ -124,15 +124,27 @@ function consensusFairProb(quotes, line, side, opts = {}) {
|
||||
}
|
||||
|
||||
/**
|
||||
* CHALLENGER DELTA. The incumbent is "first row wins" — literally the first
|
||||
* quote in feed order, whatever book that is. This reproduces it faithfully so
|
||||
* the comparison measures the real change and not an idealised one.
|
||||
* CHALLENGER DELTA — the incumbent, reproduced FAITHFULLY.
|
||||
*
|
||||
* The live chain is: PropLine -> `normalizeProps` (which applies the
|
||||
* ALLOWED_BOOKS filter FIRST) -> `gradeSlateService.dedupeProps` (first row per
|
||||
* player+stat+line wins). So the incumbent is the first quote from an ADMITTED
|
||||
* book — not the first quote in the raw feed.
|
||||
*
|
||||
* This distinction is load-bearing and easy to get wrong in the alarming
|
||||
* direction: ignoring the allow-list makes it look as though DFS pick'em has
|
||||
* been pricing the model (prizepicks alone is 47% of raw first-rows). It has
|
||||
* not — the allow-list, for all the coverage it costs, does keep DFS out of the
|
||||
* incumbent. Overstating the incumbent's badness would be as dishonest as
|
||||
* understating it.
|
||||
*/
|
||||
function incumbentFairProb(quotes, line, side) {
|
||||
function incumbentFairProb(quotes, line, side, allowedBooks) {
|
||||
const want = String(side || 'over').toLowerCase() === 'under' ? 'under' : 'over';
|
||||
const target = num(line);
|
||||
const allow = allowedBooks || require('../utils/oddsNormalizer').ALLOWED_BOOKS;
|
||||
for (const q of quotes || []) {
|
||||
if (!q || !q.book) continue;
|
||||
if (allow && !allow.has(String(q.book).toLowerCase())) continue;
|
||||
if (target != null && num(q.line) !== target) continue;
|
||||
const over = num(q.over_odds);
|
||||
const under = num(q.under_odds);
|
||||
@@ -150,7 +162,7 @@ function incumbentFairProb(quotes, line, side) {
|
||||
|
||||
/** Both rulers plus the signed delta, for a single prop. */
|
||||
function compareRulers(quotes, line, side, opts = {}) {
|
||||
const incumbent = incumbentFairProb(quotes, line, side);
|
||||
const incumbent = incumbentFairProb(quotes, line, side, opts.allowedBooks);
|
||||
const consensus = consensusFairProb(quotes, line, side, opts);
|
||||
const delta = (incumbent.fair_prob != null && consensus.fair_prob != null)
|
||||
? round4(consensus.fair_prob - incumbent.fair_prob)
|
||||
|
||||
Reference in New Issue
Block a user