b85b351993
Display ORDERING only. No grade, ledger row, lock_line, scoring, or edge_pct
scale/display change. Push scoring untouched.
Two defects removed from selectTopGrades (wrong at ANY scale, independent of
edge_pct's separate retirement):
1. edge: Math.abs(numOr(g.edge, -Infinity)) — abs() on an already-
direction-signed value ranked the model's strongest DISAGREEMENTS level
with its strongest agreements (177 public ledger rows carry a negative
edge; positive = the model AGREES with the graded side).
2. Math.abs(-Infinity) === Infinity, so a row with NO edge sorted FIRST —
absent data presented as the top pick (the Number(null) class).
New key: grade -> confidence -> takeable-gated p_win (nulls LAST) -> SIGNED
edge (nulls LAST) -> input order. Scales are never mixed in one comparator.
Takeable band = web valueState.isTakeable, asserted byte-equal to the hero's
config/valueEngine.isTakeable (-160..+200) incl. strict-null.
Alt-line ladder (analyzeViaEngine1:506) no longer sorts by edge_pct: ordered
highest-p_win-first derived analytically at zero added compute — P(stat >= k)
is monotone non-increasing in k, so p_win-desc is line-ASC for an over and
line-DESC for an under. base stays marked; no consumer depends on
alt_lines[0]; deskShowcaseService.rungsOf already re-sorted by line.
THREE PREMISE BREAKS found report-first, before code:
- /api/props/top-graded 404s in prod (absent from src/) so the dashboard
board renders receipts/empty — the edge sort orders nothing there today.
The prior order's "97.3% of rows tie" was a LEDGER measurement wrongly
extrapolated to that board. Fix is correct-in-itself and lands when the
feed is restored.
- p_win cannot be a client-side key for all tiers: snapshotGating strips it
for unentitled tiers ("shipping p_win is shipping the model price").
Verified live: prod /api/snapshot carries p_win on 0/8 MLB, 0/25 WNBA.
- Ladder rungs carry no per-rung price, so the takeable gate is inapplicable.
Verified on real data, both sports, both paths: unentitled — WNBA (n=25)
ordering CHANGED, MLB (n=8) unchanged, signed edge non-increasing in every
(grade,confidence) tie group (20 pairs, 0 violations); entitled — 40 real
ledger rows with p_win+locked_odds, p_win-descending, untakeable chalk NOT
promoted (Trea Turner .757 @-275 does not beat Rhyne Howard .745 @-120)
(36 pairs, 0 violations).
Hero consistency, stated honestly: same signal + same gate, different
precedence BY CONTRACT (board = grade-tier-first "top GRADES"; hero =
p_win-first "top read"). Identical within the leading tier (verified); across
tiers the board may lead with an A the hero doesn't pick. Not a contradiction.
Floor: 310 suites / 3864 tests green, web build exit 0. Dashboard + Desk
visuals are auth/feed-gated -> tagged for the Chrome audit, no visual faked.
Held: edge_pct rescale/display retirement (Order B); building the missing
/api/props/top-graded selector; exposing p_win to unentitled tiers.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QJs13VsyiSKYQP6rj3NNmc
4.2 KiB
4.2 KiB
SPEC — Fix the grade-board sort (display ordering only)
Status: built 2026-07-29. Report-first found three premise breaks — see §2. Scope: display ORDERING only. No grade, ledger row, lock_line, scoring, model, or edge_pct scale/display change. Push scoring untouched.
1. The two defects (wrong at ANY scale, independent of edge_pct's retirement)
web/src/lib/slateAdapter.js selectTopGrades ranked on
edge: Math.abs(numOr(g.edge, -Infinity)):
- abs() on an already-signed value.
edgeis signed BY DIRECTION upstream (edgePctFor:over ? proj−line : line−proj), so positive = the model AGREES with the graded side. Taking|edge|ranked the model's strongest DISAGREEMENTS equal to its strongest agreements. 177 public ledger rows carry a negative edge (58 B / 118 C / 1 F, worst −86.7). Math.abs(-Infinity) === Infinity→ a row with NO edge sorted FIRST. Absent data presented as the top pick — theNumber(null)fabrication class.
src/services/intelligence/analyzeViaEngine1.js:506 sorted the Desk alt-line
ladder by edge_pct desc — the same price-free 0.5-line artifact.
2. REPORT-FIRST — three premise breaks found before building
- B1. Site 1's board is fed by a 404.
/api/props/top-gradeddoes not exist insrc/(only three axios callers reference it) and returns 404 in prod. The Next proxy catches →{props: []}→topGrades = []→selectTopGrades([])→ the dashboard rendersproofMode(yesterday's receipts) or honest empty copy. The edge sort orders nothing on that surface today. CORRECTION to the prior order: its "97.3% of rows tie → the edge key decides the board" was a LEDGER population measurement extrapolated to this board; the board has no rows to order. The fix is still correct-in-itself and lands the moment the feed is restored. - B2. p_win CANNOT be the client-side sort key.
src/utils/snapshotGating.js(Session 67) stripsp_win/ev_pct/model_odds/value/takeablefor unentitled tiers, with the explicit rationale "shipping p_win is shipping the price in a different base."selectTopGradesruns in the BROWSER. Ranking there by p_win for all tiers would REVERSE that gate. Implemented instead: p_win is used WHEN THE ROW CARRIES IT (entitled tiers / server callers), takeable-gated identically to the hero; unentitled tiers fall through to the signed edge uniformly. Scales are NEVER mixed in one comparator. - B3. The ladder cannot take the takeable gate, and p_win order there is
ANALYTICALLY the line order. Ladder rungs carry no per-rung price (books
price each line differently; we do not fetch them), and
isTakeableis a property of price alone → inapplicable per rung. AndP(stat ≥ k)is monotone non-increasing ink, so p_win-desc ≡ line-asc for an over, line-desc for an under. Implemented as the direction-aware line order = exactly p_win-desc, at zero added compute. (deskShowcaseService.rungsOf:40already re-sorted rungs by line, discarding the edge order — so onlyGradeResultCardever showed it.)
3. What ships
selectTopGrades:grade → confidence → takeable-gated p_win (nulls last) → SIGNED edge (nulls last) → input order. Noabs(). Missing signal ranks LAST, rows are never dropped.- Alt-line ladder: ordered by highest p_win first, computed via the monotonic
line equivalence (direction-aware). No
edge_pctin the sort. - The takeable band is
web/src/lib/valueState.isTakeable(−160..+200), which mirrorssrc/config/valueEngine.isTakeable— the hero's exact definition.
4. Acceptance criteria
- A disagreement (negative-edge) prop does NOT outrank an agreement at equal grade+confidence.
- A missing-signal row sorts LAST and is still PRESENT.
- A takeable p_win row outranks a higher-p_win UNTAKEABLE (chalk) row.
- p_win and edge are never compared against each other.
- Ladder rungs are ordered highest-p_win-first for both over and under.
- No grade/ledger/lock_line/scoring write. Full suite green, web build exit 0.
5. Held (NOT this order)
edge_pct rescale or display retirement (Order B) · building the missing
/api/props/top-graded server selector · exposing p_win to unentitled tiers.