Rank on p_win: challenger instrument + retire edge from decisions
MEASURED BASIS (n=200 settled MLB rows): corr(p_win, outcome) = +0.26; corr(edge, outcome) = -0.010 incumbent ruler / -0.022 consensus ruler. Subtracting the market destroys the signal under BOTH rulers, so a quantity that does not predict must not rank, gate or decide. CHALLENGER-FIRST -- live ordering is byte-identical. rankGrades (the incumbent, grade-first with edge as its 4th key) is untouched and tested as untouched. NEW: rankByForecast -- takeable-gated p_win -> grade -> confidence -> stable order, with NO edge term anywhere. p_win LEADS and the letter follows, deliberately: the letter measured r ~ 0.005 and is inverted (B 52.4% < C 56.9%) while p_win measures +0.26, so leading with the letter would sort by the weaker signal and use the stronger one only to break ties. Recorded in the code: isotonic calibration is a MONOTONE transform, so ranking on raw vs calibrated p_win gives the SAME ORDER. Calibration matters when p_win is displayed or thresholded; it cannot change a ranking. Nothing here needs the calibrated value. rankingDelta + GET /api/internal/ranking-delta measure how far the board would move before any flip. The endpoint reports p_win coverage alongside the delta -- if p_win is absent the challenger degrades to grade order and the delta UNDERSTATES, which is worth saying rather than reporting a clean zero. forecast_rank is stamped on snapshot grades BEFORE stripModelPrice, so every tier gets the correct order without the paid values (the topGradedService precedent -- an ordinal can travel where the magnitude cannot). Additive only: nothing sorts by it yet. RETIRED AS DECISIONS (not rankings, so done now): - altLineScanner.compareToBookImplied no longer returns value_detected: edge > 0. Edge is still COMPUTED and returned -- losing the record would be worse than mis-using it -- but the verdict is an honest null with value_basis: 'retired:edge_does_not_predict'. - scanAltLines no longer filters to edge>0 or calls the survivor "optimal". The whole ladder is returned ranked and labelled 'price_gap_diagnostic_unvalidated'. The module has ZERO callers (verified) -- unwired like mlbGrader.js, left in place and made honest. An honest asymmetry recorded there: ranking props AGAINST EACH OTHER must not use edge, but choosing between RUNGS OF THE SAME PROP is inherently price-relative -- ranking rungs by model probability alone would always pick the lowest line, since P(over 0.5) > P(over 2.5) by construction. So the gap stays the rung key, explicitly labelled unvalidated. Two superseded tests updated to stronger properties. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QJs13VsyiSKYQP6rj3NNmc
This commit is contained in:
@@ -150,15 +150,25 @@ describe('Intelligence Engine', () => {
|
||||
expect(prob).toBeCloseTo(0.5, 1);
|
||||
});
|
||||
|
||||
test('compareToBookImplied detects value', () => {
|
||||
// SUPERSEDED 2026-08-01. This asserted `value_detected === true` from a
|
||||
// positive edge. Edge does not predict outcomes (n=200 settled MLB rows:
|
||||
// corr -0.010 incumbent ruler / -0.022 consensus, vs corr(p_win) = +0.26),
|
||||
// so it must not decide anything. The stronger property: edge is still
|
||||
// COMPUTED and returned as a diagnostic (losing the record would be worse
|
||||
// than mis-using it), while the verdict is an honest null with a reason.
|
||||
test('compareToBookImplied returns edge as a DIAGNOSTIC and refuses a verdict', () => {
|
||||
const result = compareToBookImplied(0.60, -110);
|
||||
expect(result.model_prob).toBe(0.6);
|
||||
expect(result.book_implied).toBeCloseTo(0.524, 2);
|
||||
expect(result.value_detected).toBe(true);
|
||||
expect(result.edge).toBeGreaterThan(0);
|
||||
expect(result.edge).toBeGreaterThan(0); // still recorded
|
||||
expect(result.value_detected).toBeNull(); // never a boolean verdict
|
||||
expect(result.value_basis).toBe('retired:edge_does_not_predict');
|
||||
});
|
||||
|
||||
test('scanAltLines returns optimal line with edge', () => {
|
||||
// SUPERSEDED 2026-08-01: 'optimal' was a quality claim edge cannot support,
|
||||
// and filtering to edge>0 hid rungs. The ladder is now returned whole,
|
||||
// ranked, and labelled as an unvalidated price diagnostic.
|
||||
test('scanAltLines returns the whole ladder ranked, labelled unvalidated', () => {
|
||||
const prop = { projected_mean: 25, projected_stddev: 5, direction: 'over' };
|
||||
const odds = [
|
||||
{ line: 22.5, odds: -130, book: 'draftkings' },
|
||||
@@ -167,8 +177,13 @@ describe('Intelligence Engine', () => {
|
||||
];
|
||||
const result = scanAltLines(prop, odds);
|
||||
expect(result).not.toBeNull();
|
||||
expect(result.optimal_line).toBeDefined();
|
||||
expect(result.edge).toBeGreaterThan(0);
|
||||
expect(result.top_by_price_gap).toBeDefined();
|
||||
expect(result.ranking_basis).toBe('price_gap_diagnostic_unvalidated');
|
||||
// every rung survives — a negative gap is an observation, not a reason to hide
|
||||
expect(result.ranked_lines).toHaveLength(odds.length);
|
||||
expect(result.ranked_lines[0].edge).toBeGreaterThanOrEqual(result.ranked_lines[1].edge);
|
||||
// no boolean verdict anywhere in the payload
|
||||
expect(result.ranked_lines.every((r) => r.value_detected === undefined)).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user