Per-sport rank guard + edge diagnostic-only display + delta report
DELTA MEASURED on live prod grades (live ordering unchanged): MLB 7/8 props move (87.5%), mean 2.5 places, TOP READ CHANGES (corey seager hits 1.5 under -> jake burger hits 0.5 over). WNBA 25/25 move, mean 4.1, max 12. This is a large re-ordering, not a tweak. Caveat recorded rather than buried: MLB had only 8 graded props at measurement time. The percentages are real; the sample is one small slate. Re-run before the flip -- it is one call. PER-SPORT DOCTRINE ENFORCED IN CODE. WNBA moves the most and must NOT adopt this: its p_win is anti-predictive, so ranking that board by p_win would sort it by a signal measured to point the WRONG WAY -- worse than the incumbent, not better. A comment would not have stopped a future flip from going global, so FORECAST_RANKED_SPORTS = Set(['mlb']) gates the forecast_rank stamp, with tests asserting no sport inherits MLB's result. A sport joins only by passing its own holdout. EDGE IS NOW DIAGNOSTIC-ONLY IN DISPLAY. MobileEdgeBoard.EdgeCell rendered green (--g-a) for positive edge and red (--miss) for negative. Two things were wrong: green/red IS a quality claim on a quantity that does not predict, and ROW-GRAMMAR reserves red for settled-negative ONLY -- a negative diagnostic is not a settled loss. Now neutral mono with a diagnostic tooltip; header reads "MKT GAP · DIAGNOSTIC". The number is still shown -- no display went blank. DeskShowcase neutralised likewise. PINNACLE LOGGED, NOT ENSHRINED. Per the order, "market-not-sharp" is PENDING-RECOVERY rather than a confirmed permanent limitation. The single question for PropLine is in BLOCKERS.md with its evidence, and MASTER-PLAN now carries the pending status instead of the permanent claim. Live sorts remain byte-identical: selectTopGrades, flattenToEdgeBoard and topGradedService all still call the incumbent. Gates: 4,041 tests / 323 suites green; next build exit 0. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QJs13VsyiSKYQP6rj3NNmc
This commit is contained in:
@@ -10,7 +10,7 @@
|
||||
*/
|
||||
|
||||
const {
|
||||
rankGrades, rankByForecast, rankingDelta, gradeKey, takeablePWin,
|
||||
rankGrades, rankByForecast, rankingDelta, gradeKey, takeablePWin, ranksOnForecast, FORECAST_RANKED_SPORTS,
|
||||
} = require('../../src/utils/gradeRanking');
|
||||
|
||||
const g = (player, grade, p_win, odds = -110, extra = {}) => ({
|
||||
@@ -96,3 +96,18 @@ describe('rankingDelta — the challenger-first measurement', () => {
|
||||
expect(JSON.stringify(rows)).toBe(snapshot);
|
||||
});
|
||||
});
|
||||
|
||||
describe('per-sport doctrine — who may rank on the forecast', () => {
|
||||
it('MLB may; WNBA may NOT (its p_win is anti-predictive, it abstains)', () => {
|
||||
expect(ranksOnForecast('mlb')).toBe(true);
|
||||
expect(ranksOnForecast('MLB')).toBe(true);
|
||||
expect(ranksOnForecast('wnba')).toBe(false);
|
||||
});
|
||||
|
||||
it('no sport inherits MLB’s result — unknown sports are excluded', () => {
|
||||
for (const s of ['nba', 'nfl', 'soccer', 'nhl', 'ncaab', '', null, undefined]) {
|
||||
expect(ranksOnForecast(s)).toBe(false);
|
||||
}
|
||||
expect([...FORECAST_RANKED_SPORTS]).toEqual(['mlb']);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user