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
331 lines
15 KiB
JavaScript
331 lines
15 KiB
JavaScript
/* ============================================================
|
|
Session 66 — THE PRICE LAYER: token layer + the five honesty states.
|
|
|
|
Two things are locked here:
|
|
1. The TOKEN LAYER is additive and complete — the design bundle's values
|
|
exist in globals.css and match HANDOFF.md byte-for-byte.
|
|
2. The LAWS are enforceable, not folklore — the verdict function is the
|
|
single place "is this value?" is answered, and it can never say VALUE
|
|
on a juiced price.
|
|
============================================================ */
|
|
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
|
|
const ROOT = path.join(__dirname, '..', '..');
|
|
const read = (rel) => fs.readFileSync(path.join(ROOT, rel), 'utf8');
|
|
|
|
const CSS = read('web/src/app/globals.css');
|
|
const HANDOFF = read('specs/design-reference/HANDOFF.md');
|
|
|
|
const vs = require('../../web/src/lib/valueState');
|
|
const backendValue = require('../../src/config/valueEngine');
|
|
|
|
// ── 1. TOKEN LAYER — the design's values, present and correct ────────────
|
|
describe('token layer — HANDOFF values resolve in globals.css', () => {
|
|
// Each entry: [css custom property, expected hex, why it exists]
|
|
const TOKENS = [
|
|
['--bg-0', '#06060B'], // void
|
|
['--bg-1', '#0E0E14'], // card
|
|
['--bg-2', '#14141E'], // elevated
|
|
['--hairline', '#101018'], // row hairline
|
|
['--bg-deep', '#0A0A10'], // deep panel
|
|
['--border', '#1E1E2A'],
|
|
['--border-hi', '#2A2A38'],
|
|
['--text-0', '#F0F0F0'],
|
|
['--text-1', '#B8BCC8'],
|
|
['--text-2', '#707080'],
|
|
['--text-3', '#4a4a58'],
|
|
['--g-a', '#00d4a0'], // signal green
|
|
['--amber', '#ffb347'],
|
|
['--miss', '#FF4757'],
|
|
['--priced-out', '#8fb2de'], // NEW this session
|
|
];
|
|
|
|
test.each(TOKENS)('%s is declared as %s', (name, hex) => {
|
|
const m = CSS.match(new RegExp(`${name}\\s*:\\s*([^;]+);`));
|
|
expect(m).toBeTruthy();
|
|
expect(m[1].trim().toLowerCase()).toBe(hex.toLowerCase());
|
|
});
|
|
|
|
it('every hex above also appears in HANDOFF.md (design is the source)', () => {
|
|
// The priced-out blue comes from the triplet file, not HANDOFF's token list.
|
|
for (const [, hex] of TOKENS.filter(([n]) => n !== '--priced-out')) {
|
|
expect(HANDOFF.toLowerCase()).toContain(hex.toLowerCase());
|
|
}
|
|
});
|
|
|
|
it('grade colors follow the design: A green, B white, C grey, D/F red', () => {
|
|
expect(CSS).toMatch(/--g-a:\s*#00d4a0/i);
|
|
expect(CSS).toMatch(/--g-b:\s*#F0F0F0/i);
|
|
expect(CSS).toMatch(/--g-c:\s*#B8BCC8/i);
|
|
expect(CSS).toMatch(/--g-d:\s*#FF4757/i);
|
|
});
|
|
|
|
it('fonts: Inter for chrome, JetBrains Mono for ALL data', () => {
|
|
expect(CSS).toMatch(/--sans:[^;]*Inter/);
|
|
expect(CSS).toMatch(/--mono:[^;]*JetBrains Mono/);
|
|
});
|
|
|
|
it('the laws are written INTO the token layer, not left as folklore', () => {
|
|
const block = CSS.slice(CSS.indexOf('SESSION 66 — PRICE-LAYER TOKENS'));
|
|
expect(block).toMatch(/GREEN = EDGE ONLY/);
|
|
expect(block).toMatch(/GLOW = A-TIER ONLY/);
|
|
expect(block).toMatch(/AMBER = CAUTION/);
|
|
expect(block).toMatch(/RED = MISS \/ NEGATIVE only/i);
|
|
expect(block).toMatch(/BLUE = EDGE PRICED OUT/);
|
|
expect(block).toMatch(/JETBRAINS MONO = ALL DATA/);
|
|
});
|
|
|
|
it('is ADDITIVE — the new block declares only new names', () => {
|
|
// Bound the block to the Session-66 section itself: globals.css continues
|
|
// past :root with a11y/media layers that legitimately re-declare tokens.
|
|
const start = CSS.indexOf('SESSION 66 — PRICE-LAYER TOKENS');
|
|
const block = CSS.slice(start, CSS.indexOf('\n}', start));
|
|
const declared = [...block.matchAll(/^\s*(--[a-z0-9-]+)\s*:/gim)].map((m) => m[1]);
|
|
expect(declared.length).toBeGreaterThan(0);
|
|
// None of the newly-declared names may collide with a pre-existing token.
|
|
const before = CSS.slice(0, CSS.indexOf('SESSION 66 — PRICE-LAYER TOKENS'));
|
|
for (const name of declared) {
|
|
expect(before).not.toMatch(new RegExp(`^\\s*${name}\\s*:`, 'm'));
|
|
}
|
|
});
|
|
});
|
|
|
|
// ── 2. THE BAND — frontend law mirrors the backend engine ────────────────
|
|
describe('takeable band + EV threshold stay in sync with the backend', () => {
|
|
it('mirrors src/config/valueEngine.js exactly', () => {
|
|
expect(vs.TAKEABLE_ODDS_CEILING).toBe(backendValue.TAKEABLE_ODDS_CEILING);
|
|
expect(vs.TAKEABLE_ODDS_MAX).toBe(backendValue.TAKEABLE_ODDS_MAX);
|
|
expect(vs.VALUE_EV_THRESHOLD).toBe(backendValue.VALUE_EV_THRESHOLD);
|
|
});
|
|
|
|
it('agrees with the backend on isTakeable / isValue across the band', () => {
|
|
const prices = [-400, -210, -161, -160, -110, 100, 200, 201, 500, null, undefined, ''];
|
|
for (const p of prices) {
|
|
expect(vs.isTakeable(p)).toBe(backendValue.isTakeable(p));
|
|
for (const ev of [-58.7, 0, 1.9, 2, 11.7, 26.5]) {
|
|
expect(vs.isValue(p, ev)).toBe(backendValue.isValue(p, ev));
|
|
}
|
|
}
|
|
});
|
|
|
|
it('a missing price is NEVER takeable (Number(null) === 0 guard)', () => {
|
|
expect(vs.isTakeable(null)).toBe(false);
|
|
expect(vs.isTakeable('')).toBe(false);
|
|
expect(vs.isTakeable(undefined)).toBe(false);
|
|
});
|
|
});
|
|
|
|
// ── 3. THE FIVE HONESTY STATES ───────────────────────────────────────────
|
|
describe('deriveValueState — the single verdict function', () => {
|
|
const base = { book_odds: -120, fair_odds: -104, model_odds: -196, ev_pct: 21.4 };
|
|
|
|
it('VALUE — real edge at a takeable price (the live Petey Halpin row)', () => {
|
|
expect(vs.deriveValueState(base)).toBe(vs.STATES.VALUE);
|
|
});
|
|
|
|
it('PRICED OUT — positive EV at a juiced price (the live Josh Bell row)', () => {
|
|
// book -210, +11.7% EV: the engine refuses to call this value, and so do we.
|
|
const row = { book_odds: -210, fair_odds: -173, model_odds: -311, ev_pct: 11.7 };
|
|
expect(vs.deriveValueState(row)).toBe(vs.STATES.PRICED_OUT);
|
|
});
|
|
|
|
it('NEVER calls raw positive EV "value" — the whole point of state 2', () => {
|
|
for (const [book, ev] of [[-210, 11.7], [-190, 26.5], [-400, 60], [250, 30]]) {
|
|
const st = vs.deriveValueState({ book_odds: book, fair_odds: -150, model_odds: -300, ev_pct: ev });
|
|
expect(st).not.toBe(vs.STATES.VALUE);
|
|
expect(st).toBe(vs.STATES.PRICED_OUT);
|
|
}
|
|
});
|
|
|
|
it('EV below the threshold is NO EDGE even at a takeable price', () => {
|
|
expect(vs.deriveValueState({ ...base, ev_pct: 0.2 })).toBe(vs.STATES.NO_EDGE);
|
|
expect(vs.deriveValueState({ ...base, ev_pct: 1.99 })).toBe(vs.STATES.NO_EDGE);
|
|
expect(vs.deriveValueState({ ...base, ev_pct: 2 })).toBe(vs.STATES.VALUE); // boundary
|
|
});
|
|
|
|
it('QUARANTINE — model leg withheld, book + fair still stand', () => {
|
|
const row = { ...base, quarantine_reason: 'wrong_opponent_grade' };
|
|
expect(vs.deriveValueState(row)).toBe(vs.STATES.QUARANTINE);
|
|
});
|
|
|
|
it('REFUSAL — no fair price we would defend', () => {
|
|
expect(vs.deriveValueState({ ...base, fair_odds: null })).toBe(vs.STATES.REFUSAL);
|
|
expect(vs.deriveValueState({ ...base, book_odds: null })).toBe(vs.STATES.REFUSAL);
|
|
expect(vs.deriveValueState({ ...base, refused: true })).toBe(vs.STATES.REFUSAL);
|
|
expect(vs.deriveValueState({})).toBe(vs.STATES.REFUSAL);
|
|
});
|
|
|
|
it('a missing model price or EV → NO_MODEL (absent leg), never NO EDGE and never QUARANTINE', () => {
|
|
// Honesty pass: never-computed is NOT a deliberate quarantine, so it must
|
|
// not wear QUARANTINE's "we suppressed / a leg is poisoned" copy.
|
|
expect(vs.deriveValueState({ ...base, model_odds: null })).toBe(vs.STATES.NO_MODEL);
|
|
expect(vs.deriveValueState({ ...base, ev_pct: null })).toBe(vs.STATES.NO_MODEL);
|
|
// A real quarantine_reason still quarantines (distinct from never-computed).
|
|
expect(vs.deriveValueState({ ...base, model_odds: null, quarantine_reason: 'x' })).toBe(vs.STATES.QUARANTINE);
|
|
});
|
|
|
|
it('a LOCKED model leg is neither quarantine nor refusal', () => {
|
|
const row = { ...base, model_price_locked: true };
|
|
expect(vs.deriveValueState(row)).toBe(vs.STATES.NO_VERDICT_LOCKED);
|
|
});
|
|
});
|
|
|
|
// ── 4. THE COLOR LAW ─────────────────────────────────────────────────────
|
|
describe('valueStateColor — green appears on exactly one state', () => {
|
|
it('VALUE is the ONLY green', () => {
|
|
expect(vs.valueStateColor(vs.STATES.VALUE)).toBe('var(--g-a)');
|
|
const others = [
|
|
vs.STATES.PRICED_OUT, vs.STATES.NO_EDGE, vs.STATES.QUARANTINE,
|
|
vs.STATES.REFUSAL, vs.STATES.NO_VERDICT_LOCKED, vs.STATES.NO_MODEL,
|
|
];
|
|
for (const s of others) expect(vs.valueStateColor(s)).not.toBe('var(--g-a)');
|
|
});
|
|
|
|
it('PRICED OUT is the blue carve-out; NO EDGE is never red', () => {
|
|
expect(vs.valueStateColor(vs.STATES.PRICED_OUT)).toBe('var(--priced-out)');
|
|
// An honest "no" is the instrument working, not a loss.
|
|
expect(vs.valueStateColor(vs.STATES.NO_EDGE)).not.toBe('var(--miss)');
|
|
});
|
|
|
|
it('QUARANTINE is amber (caution), per the token law', () => {
|
|
expect(vs.valueStateColor(vs.STATES.QUARANTINE)).toBe('var(--amber)');
|
|
});
|
|
});
|
|
|
|
// ── 5. HONEST ABSENCE ────────────────────────────────────────────────────
|
|
describe('never prints a number it cannot stand behind', () => {
|
|
it('fmtOddsAmerican returns null for absence — never 0, never a placeholder', () => {
|
|
expect(vs.fmtOddsAmerican(null)).toBeNull();
|
|
expect(vs.fmtOddsAmerican('')).toBeNull();
|
|
expect(vs.fmtOddsAmerican(undefined)).toBeNull();
|
|
expect(vs.fmtOddsAmerican('abc')).toBeNull();
|
|
expect(vs.fmtOddsAmerican(-210)).toBe('-210');
|
|
expect(vs.fmtOddsAmerican(125)).toBe('+125');
|
|
});
|
|
|
|
it('modelVsFair is null unless BOTH legs are real', () => {
|
|
expect(vs.modelVsFair(null, -110)).toBeNull();
|
|
expect(vs.modelVsFair(-110, null)).toBeNull();
|
|
expect(typeof vs.modelVsFair(98, 110)).toBe('number');
|
|
});
|
|
|
|
it('reproduces the design file\'s own worked examples EXACTLY', () => {
|
|
// The design states these two figures; the formula was derived from them.
|
|
// STATE 1: book +125 · fair +110 · model +98 → "+2.9% VS FAIR"
|
|
expect(vs.modelVsFair(98, 110)).toBe(2.9);
|
|
// STATE 3: book +118 · fair +104 · model +112 → "-1.8% VS FAIR"
|
|
expect(vs.modelVsFair(112, 104)).toBe(-1.8);
|
|
});
|
|
|
|
it('compares MODEL to FAIR — not book to fair (the induction bug)', () => {
|
|
// Petey Halpin, live: book -120 · fair -104 · model -196. Our price is far
|
|
// shorter than fair, so the gap is strongly POSITIVE. Comparing the book
|
|
// to fair instead produced -6.5% on a VALUE row — a visible contradiction.
|
|
expect(vs.modelVsFair(-196, -104)).toBeGreaterThan(10);
|
|
});
|
|
});
|
|
|
|
// ── 6. THE COMPONENT carries the rulings ─────────────────────────────────
|
|
describe('PriceTriplet component', () => {
|
|
const src = read('web/src/components/vyndr/PriceTriplet.tsx');
|
|
|
|
it('uses ONLY tokens — no literal hex anywhere', () => {
|
|
const hexes = src.match(/#[0-9a-f]{3,8}\b/gi) || [];
|
|
expect(hexes).toEqual([]);
|
|
});
|
|
|
|
it('does not re-derive the verdict — it renders deriveValueState', () => {
|
|
expect(src).toContain('deriveValueState');
|
|
expect(src).not.toMatch(/ev_pct\s*>=\s*2/);
|
|
});
|
|
|
|
it('FAIR is the amber hero and is never locked', () => {
|
|
expect(src).toMatch(/label="FAIR"[\s\S]{0,200}var\(--amber\)/);
|
|
expect(src).not.toMatch(/label="FAIR"[\s\S]{0,200}locked/);
|
|
});
|
|
|
|
it('only the MODEL leg is lockable / withheld', () => {
|
|
expect(src).toMatch(/label="MODEL"[\s\S]{0,300}locked=\{modelLocked\}/);
|
|
});
|
|
|
|
it('carries no sample numbers from the design file', () => {
|
|
// Strip comments first — the docblock names the design's sample values in
|
|
// order to say they are a SPEC and must never ship as data.
|
|
const code = src.replace(/\/\*[\s\S]*?\*\//g, '').replace(/^\s*\/\/.*$/gm, '');
|
|
for (const sample of ['1,188', '1,115.5', '+125', '+110', '+98', '+130', '+116']) {
|
|
expect(code).not.toContain(sample);
|
|
}
|
|
});
|
|
|
|
it('REFUSAL renders no legs and no gauge', () => {
|
|
const refusal = src.slice(src.indexOf('STATES.REFUSAL'));
|
|
expect(refusal).toContain("CAN’T PRICE THIS ONE");
|
|
});
|
|
});
|
|
|
|
// ── 6b. CONSUMERS MUST FORWARD THE LOCK FLAG ─────────────────────────────
|
|
describe('a gated model leg never wears quarantine copy', () => {
|
|
it('deriveValueState separates GATED (locked) from NEVER-COMPUTED — neither is QUARANTINE', () => {
|
|
const gated = { book_odds: -153, fair_odds: -129, model_odds: null, ev_pct: null, model_price_locked: true };
|
|
const neverComputed = { book_odds: -153, fair_odds: -129, model_odds: null, ev_pct: null };
|
|
expect(vs.deriveValueState(gated)).toBe(vs.STATES.NO_VERDICT_LOCKED);
|
|
// Honesty pass: a never-computed model leg is NO_MODEL (absent), NOT quarantine
|
|
// — it must not claim we "suppressed" a price we never produced.
|
|
expect(vs.deriveValueState(neverComputed)).toBe(vs.STATES.NO_MODEL);
|
|
});
|
|
|
|
it('LiveHeroProp forwards model_price_locked (live bug: it did not)', () => {
|
|
// Without this the landing hero rendered "MODEL READ WITHHELD" — poison's
|
|
// copy — to every anonymous visitor, when the real reason was the paywall.
|
|
const hero = read('web/src/components/LiveHeroProp.tsx');
|
|
expect(hero).toMatch(/model_price_locked: data\.model_price_locked/);
|
|
});
|
|
|
|
it('the grade adapter forwards it too', () => {
|
|
const { buildPriceTriplet } = require('../../web/src/lib/gradeAdapter');
|
|
const t = buildPriceTriplet({ book_odds: -153, fair_odds: -129, model_price_locked: true }).priceTriplet;
|
|
expect(t.model_price_locked).toBe(true);
|
|
});
|
|
});
|
|
|
|
// ── 7. THE SERVER GATE — fair is never the paywall ───────────────────────
|
|
describe('free-tier gate strips the model price at the wire', () => {
|
|
const { applyTierGating } = require('../../src/utils/tierGating');
|
|
const row = {
|
|
grade: 'B', book_odds: -120, fair_odds: -104, model_odds: -196, ev_pct: 21.4,
|
|
};
|
|
|
|
it('free: model_odds is REMOVED, book + fair survive', () => {
|
|
const out = applyTierGating(row, 'free');
|
|
expect(out.model_odds).toBeUndefined();
|
|
expect(out.book_odds).toBe(-120);
|
|
expect(out.fair_odds).toBe(-104);
|
|
expect(out.model_price_locked).toBe(true);
|
|
});
|
|
|
|
it('analyst + desk: the full triplet passes through', () => {
|
|
for (const tier of ['analyst', 'desk']) {
|
|
const out = applyTierGating(row, tier);
|
|
expect(out.model_odds).toBe(-196);
|
|
expect(out.model_price_locked).toBeUndefined();
|
|
}
|
|
});
|
|
|
|
it('the adapter turns a stripped row into a LOCK, not an absent leg', () => {
|
|
const { buildPriceTriplet } = require('../../web/src/lib/gradeAdapter');
|
|
const gated = applyTierGating(row, 'free');
|
|
const t = buildPriceTriplet(gated).priceTriplet;
|
|
expect(t.model_odds).toBeNull();
|
|
expect(t.model_price_locked).toBe(true);
|
|
expect(vs.deriveValueState(t)).toBe(vs.STATES.NO_VERDICT_LOCKED);
|
|
});
|
|
|
|
it('no book/fair → no price story at all (section hidden, not empty)', () => {
|
|
const { buildPriceTriplet } = require('../../web/src/lib/gradeAdapter');
|
|
expect(buildPriceTriplet({ grade: 'B' })).toEqual({});
|
|
expect(buildPriceTriplet({ book_odds: -120 })).toEqual({});
|
|
});
|
|
});
|