6bc18d823c
Six live untruths corrected — no grade/snapshot/scorer/pipeline touched: 1. /compare — hardcoded Jokic A+/Wembanyama A + fake VERDICT replaced with an honest in-development state; removed from Nav + BottomTabBar (route still resolves, never the sample). Real two-player build is later. 2. Pricing — founder Desk $34.99→$44.99 (matches lib/checkout.js), Analyst $14.99; removed the struck $19.99/$44.99 "regular" numbers and DeskShowcase's stale $34.99. First-100 counter is real (ClaimMeter → Stripe countFounderSeats); no fake "first 50" desk claim added (no such counter exists). 3. FAQ "NexaPay" → Stripe (verified: live checkout is Next→Express→checkout.stripe.com). 4. FAQ + Features "Brier/CLV published from day one" removed (not surfaced yet) — returns when real. Backend Brier compute untouched. 5. MobileEdgeBoard removed from the Slate — its edge% feed was a miscalibrated placeholder (masked >40% as "—"); phones now show the real game cards. 6. Price triplet — never-computed model/EV now derives NO_MODEL (honest absent, MODEL "—" / "NOT PRICED", no verdict) instead of QUARANTINE's false "we suppressed our price / a leg is poisoned" copy. Fixes grade card + LiveHeroProp. Full suite 3833 green, web build exit 0. Tests updated to the new honest contracts. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VsztNChZ7vEvSR61AuMhD1
195 lines
8.0 KiB
JavaScript
195 lines
8.0 KiB
JavaScript
/* ============================================================
|
|
VYNDR — THE PRICE-LAYER LAW (Session 66).
|
|
|
|
Plain CommonJS so .tsx components import it AND the Jest suite requires it
|
|
directly (same pattern as colorContract.js / vyndrTokens.js / playerName.js).
|
|
|
|
ONE function decides what a price row is allowed to SAY. The triplet renders
|
|
whatever this returns and never re-derives a verdict of its own, so there is
|
|
exactly one place where "is this value?" is answered.
|
|
|
|
THE FIVE HONESTY STATES (design: `Vyndr Price Triplet.dc.html`, ACT 01):
|
|
|
|
VALUE green — ev >= VALUE_EV_THRESHOLD *AND* the book price is
|
|
inside the takeable band. Both. Raw positive EV is
|
|
NOT value: +11.7% EV at -210 is a juiced price we
|
|
will not call a play.
|
|
PRICED_OUT blue — real edge, untakeable price. We won't call a juiced
|
|
price a value, and we won't pretend the edge wasn't
|
|
there. This state exists so green never has to lie
|
|
in either direction.
|
|
NO_EDGE grey — the honest number is already priced. Stated at full
|
|
voice, never hidden. That "no" is the instrument
|
|
working.
|
|
QUARANTINE amber — the MODEL leg is withheld (graded against inputs we
|
|
no longer trust). Book and fair still render: we
|
|
never hide the honest fair number because a
|
|
different leg is poisoned. RARE — as of Jul 2026 the
|
|
only quarantined rows are one frozen historical
|
|
cohort, so this is not a routine state.
|
|
REFUSAL dim — no fair price we'd defend. Nothing renders. No
|
|
fabricated price, no empty gauge.
|
|
|
|
TRUTH LAW: the triplet never prints a number it can't stand behind. A leg
|
|
with no value renders absent, never a zero and never a placeholder.
|
|
============================================================ */
|
|
|
|
/* ---- Backend mirror -----------------------------------------------------
|
|
These MUST match src/config/valueEngine.js. The browser can't require the
|
|
backend module, so the constants are duplicated here and a test
|
|
(priceTriplet.test.js) reads BOTH files and fails if they drift — the same
|
|
guard used for playerName.js. If you tune the band, tune it in both. */
|
|
const TAKEABLE_ODDS_CEILING = -160; // most-juiced favourite we'll promote
|
|
const TAKEABLE_ODDS_MAX = 200; // longest dog we'll promote
|
|
const VALUE_EV_THRESHOLD = 2; // a real edge, not rounding
|
|
|
|
const STATES = Object.freeze({
|
|
VALUE: 'VALUE',
|
|
PRICED_OUT: 'PRICED_OUT',
|
|
NO_EDGE: 'NO_EDGE',
|
|
QUARANTINE: 'QUARANTINE',
|
|
REFUSAL: 'REFUSAL',
|
|
// Not a verdict — a display state. The model leg exists and is honest, the
|
|
// viewer just isn't entitled to it (free tier). Book + fair render normally.
|
|
NO_VERDICT_LOCKED: 'NO_VERDICT_LOCKED',
|
|
// Honesty pass: the model price was never COMPUTED (the EV layer isn't
|
|
// producing p_win/model_odds yet) — NOT quarantined, NOT locked. The model
|
|
// leg renders absent ('—'), book + fair stand, and NO verdict is claimed.
|
|
// This exists so a never-priced row never wears QUARANTINE's "we suppressed
|
|
// our own price / a leg is poisoned" copy, which asserts a deliberate act
|
|
// that did not happen.
|
|
NO_MODEL: 'NO_MODEL',
|
|
});
|
|
|
|
/** Strict numeric parse — `Number(null) === 0` is the fabrication bug this
|
|
* whole layer exists to prevent, so nothing coerces. */
|
|
function num(v) {
|
|
if (v == null || v === '') return null;
|
|
const n = typeof v === 'number' ? v : Number(v);
|
|
return Number.isFinite(n) ? n : null;
|
|
}
|
|
|
|
/** isTakeable(american) — inside the promotable band. Mirrors valueEngine. */
|
|
function isTakeable(american) {
|
|
const a = num(american);
|
|
if (a == null) return false;
|
|
return a >= TAKEABLE_ODDS_CEILING && a <= TAKEABLE_ODDS_MAX;
|
|
}
|
|
|
|
/** isValue(american, evPct) — takeable AND clears the EV threshold. Both. */
|
|
function isValue(american, evPct) {
|
|
const ev = num(evPct);
|
|
return isTakeable(american) && ev != null && ev >= VALUE_EV_THRESHOLD;
|
|
}
|
|
|
|
/**
|
|
* deriveValueState(row) — the single verdict function.
|
|
*
|
|
* row: { book_odds, fair_odds, model_odds, ev_pct, quarantine_reason,
|
|
* refused, model_price_locked }
|
|
*
|
|
* Order matters and encodes the honesty ordering:
|
|
* 1. REFUSAL first — with no fair price there is nothing honest to show.
|
|
* 2. QUARANTINE next — the model leg is untrustworthy, so no verdict may be
|
|
* computed from it, but book+fair still stand.
|
|
* 3. Then the three real verdicts.
|
|
* A locked (free-tier) model leg is NOT quarantine and NOT refusal: the data
|
|
* exists and is honest, the viewer just isn't entitled to it — so the verdict
|
|
* is withheld rather than asserted, and book+fair render normally.
|
|
*/
|
|
function deriveValueState(row = {}) {
|
|
const fair = num(row.fair_odds);
|
|
const book = num(row.book_odds);
|
|
|
|
// 1. Refusal — no fair price we'd defend (or no market to price against).
|
|
if (row.refused === true || fair == null || book == null) return STATES.REFUSAL;
|
|
|
|
// 2. Quarantine — model leg withheld; book + fair still render.
|
|
if (row.quarantine_reason) return STATES.QUARANTINE;
|
|
|
|
// Free-tier lock: entitled data withheld, not absent. No verdict is claimed
|
|
// (the verdict IS the model leg), but this is not quarantine — the row is
|
|
// honest, it's just gated.
|
|
if (row.model_price_locked === true) return STATES.NO_VERDICT_LOCKED;
|
|
|
|
const model = num(row.model_odds);
|
|
const ev = num(row.ev_pct);
|
|
// Without a model price or an EV there is no verdict to render. This is an
|
|
// absent leg, NOT a quarantine: we never computed it, so we must not claim we
|
|
// "suppressed" or "poisoned" it. Book + fair still stand; the model leg goes
|
|
// honestly absent and no verdict is asserted.
|
|
if (model == null || ev == null) return STATES.NO_MODEL;
|
|
|
|
// 3. The three real verdicts.
|
|
if (isValue(book, ev)) return STATES.VALUE;
|
|
if (ev >= VALUE_EV_THRESHOLD) return STATES.PRICED_OUT; // edge, untakeable price
|
|
return STATES.NO_EDGE;
|
|
}
|
|
|
|
/** valueStateColor(state) — the ONE mapping from verdict to token.
|
|
* Green appears here exactly once, on VALUE, and nowhere else. */
|
|
function valueStateColor(state) {
|
|
switch (state) {
|
|
case STATES.VALUE:
|
|
return 'var(--g-a)';
|
|
case STATES.PRICED_OUT:
|
|
return 'var(--priced-out)';
|
|
case STATES.QUARANTINE:
|
|
return 'var(--amber)';
|
|
case STATES.NO_EDGE:
|
|
case STATES.REFUSAL:
|
|
case STATES.NO_VERDICT_LOCKED:
|
|
case STATES.NO_MODEL:
|
|
default:
|
|
return 'var(--text-2)';
|
|
}
|
|
}
|
|
|
|
function impliedProb(american) {
|
|
const a = num(american);
|
|
if (a == null) return null;
|
|
return a > 0 ? 100 / (a + 100) : -a / (-a + 100);
|
|
}
|
|
|
|
/**
|
|
* modelVsFair(modelOdds, fairOdds) — the "+2.9% VS FAIR" figure on the verdict
|
|
* line. It is the gap between OUR price and the honest de-vigged price, in
|
|
* implied-probability PERCENTAGE POINTS (not a ratio, and NOT book-vs-fair).
|
|
*
|
|
* Derived from the design file's own two worked examples, both of which this
|
|
* reproduces exactly:
|
|
* STATE 1 book +125 · fair +110 · model +98 → "+2.9% VS FAIR"
|
|
* STATE 3 book +118 · fair +104 · model +112 → "-1.8% VS FAIR"
|
|
* Positive = the model prices it SHORTER than fair (we think it's likelier
|
|
* than the honest number says). Null unless both legs are real.
|
|
*/
|
|
function modelVsFair(modelOdds, fairOdds) {
|
|
const pm = impliedProb(modelOdds);
|
|
const pf = impliedProb(fairOdds);
|
|
if (pm == null || pf == null) return null;
|
|
return Math.round((pm - pf) * 1000) / 10;
|
|
}
|
|
|
|
/** fmtOddsAmerican(v) — display an American price, or null for honest absence.
|
|
* Never returns '0', never returns a placeholder number. */
|
|
function fmtOddsAmerican(v) {
|
|
const n = num(v);
|
|
if (n == null) return null;
|
|
const r = Math.round(n);
|
|
return r > 0 ? `+${r}` : String(r);
|
|
}
|
|
|
|
module.exports = {
|
|
STATES,
|
|
TAKEABLE_ODDS_CEILING,
|
|
TAKEABLE_ODDS_MAX,
|
|
VALUE_EV_THRESHOLD,
|
|
isTakeable,
|
|
isValue,
|
|
deriveValueState,
|
|
valueStateColor,
|
|
modelVsFair,
|
|
impliedProb,
|
|
fmtOddsAmerican,
|
|
};
|