Model Train arc 1 (engine): de-vig + EV + takeable/value gates + hero v2 + triplet
Steps 1-6 — make "real opportunities at takeable prices" the engine, not a filter. 1. DE-VIG (src/utils/devig.js): two-way multiplicative de-vig strips the vig and returns fair prob + fair price per side + the overround. One side missing → fair UNAVAILABLE (null), never faked. Method noted in code + the `devig_method` field. 2. EV (devig.evPct): ev_pct = model prob × decimal − 1 at the graded side's ACTUAL price. This is the ranking signal now, replacing raw |model−consensus|. 3. TAKEABLE gate (src/config/valueEngine.js, TAKEABLE_ODDS_CEILING −160 .. +200, env-tunable): promoted surfaces only (hero/featured/alerts). The full board still shows everything; Parlay Lab exempt; JUICE_ODDS_FLOOR (−400) stays the absolute backstop underneath. Strict null-guard (Number(null)===0 would have made a missing price "takeable"). 4. VALUE flag: passes BOTH gates (takeable AND ev_pct ≥ VALUE_EV_THRESHOLD). Grade = read quality; value = the price pays you. Shipped in payloads. 5. HERO v2 (heroPropService): highest ev_pct among takeable A/B reads — a huge gap on a −900 line is trivia, not an opportunity. 6. VALUE TRIPLET: book_odds · fair_odds · model_odds on every read (snapshot, hero, scan — they all spread the grade). Handoff documents the fields; the rendering is Session-2 Design's job. All wired in analyzeViaEngine1's existing p_win/kelly block (real quantile probability × real book odds, or nothing). 33 new tests; suite 276/3306 green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -273,3 +273,26 @@ match `^[a-z0-9_]{3,20}$` (400); a handle owned by another user → 409.
|
||||
|
||||
Frontend: `/u/[handle]` (OPEN route, server shell + client record + OG card,
|
||||
Node runtime) via proxies `web/src/app/api/profiles/me|[handle]`.
|
||||
|
||||
## Value Engine fields (Model Train arc 1, 2026-07-19)
|
||||
Every graded read (snapshot `grades:{sport}`, `/api/snapshot/:sport`, `/api/hero-prop`,
|
||||
`/api/scan`) now carries — all OPTIONAL + self-hiding when absent:
|
||||
- `ev_pct` (number) — expected value % at the graded side's ACTUAL price
|
||||
(model prob × decimal − 1). The ranking signal on boards + hero, replacing raw
|
||||
|model−consensus|.
|
||||
- `value` (bool) — the read passes BOTH gates: takeable price AND ev_pct ≥
|
||||
VALUE_EV_THRESHOLD. Grade = read quality; `value` = "the price pays you." An A
|
||||
without `value` is honest (right read, price gone).
|
||||
- `takeable` (bool) — the graded-side price is inside the promotable band
|
||||
(TAKEABLE_ODDS_CEILING −160 .. +200).
|
||||
- **The value triplet** — `book_odds` · `fair_odds` · `model_odds` (all American):
|
||||
the book's price, the de-vigged FAIR price (two-way multiplicative de-vig;
|
||||
present only when BOTH sides were priced — else absent, never faked), and the
|
||||
model's implied price. This is the story to render: "book −145 · vig-free −132
|
||||
· model −110". Also `fair_prob`, `overround`, `devig_method`.
|
||||
- Suppression reasons ride on refused reads: `suppressed` + `suppressed_reason`
|
||||
(`juiced_no_edge` / `rare_event_under`) + `reasoning.summary` (branded "No
|
||||
read" copy) — for the visible-refusal moment (Model Train step 10).
|
||||
|
||||
DESIGN: the triplet + VALUE marker + refusal copy are Session-2 design surfaces
|
||||
(reveal card, board row, hero). Backend ships the fields; rendering is Design's.
|
||||
|
||||
Reference in New Issue
Block a user