Price-layer token foundation + the price triplet, built natively on it
PHASE 0 finding, reported before building: the token layer this order asked
me to establish ALREADY EXISTS and already matches HANDOFF.md exactly.
web/src/app/globals.css :root carries the design's surfaces, borders, text
ramp, fonts and grade colours byte-for-byte (aligned 2026-07-16), and
lib/colorContract.js already encodes the green-is-edge-only and
glow-is-A-tier-only laws with a test enforcing them. The stack is Tailwind v4
CSS-first (no config file) with components styled by inline style={{}} reading
var(--x) — 1,916 such reads — so CSS custom properties are the only vehicle
the stack natively consumes. Creating a second parallel layer would have meant
two competing sources of truth, so this EXTENDS the existing one.
PHASE 1 — additive only. globals.css gains one colour the system did not have,
the priced-out blue (#8fb2de + tints), plus a tokenized A-tier glow and the
fair-leg tints. The block writes the LAWS into the token layer itself — green
= takeable edge only, glow = A-tier only, amber = caution + the fair leg, red
= miss/negative only, blue = edge priced out, JetBrains Mono = all data — and
a test asserts every newly-declared name is new (zero collisions, zero
overrides). No existing hardcoded style was touched and no live surface was
migrated: the diff over existing files is 149 insertions, 0 deletions.
PHASE 2 — lib/valueState.js is the single verdict function; the component
renders what it returns and never re-derives one. VALUE fires only on
ev >= 2 AND a takeable price, mirroring src/config/valueEngine.js with a test
that cross-checks both files and fails on drift. Five states: VALUE (green),
EDGE-NOT-TAKEABLE (blue), NO EDGE (grey, stated at full voice), QUARANTINE
(model leg withheld, book+fair stand), REFUSAL (nothing rendered). Free tier
is gated at the wire — tierGating strips model_odds and sets
model_price_locked, so the lock is real rather than a blur over data already
sent; book and fair pass through on every tier because the fair leg is never
the paywall. Wired into the landing hero (data was already on /api/hero-prop)
and the read card, where the projection block reads first and the triplet sits
beside it, not in place of it. Ledger and public profile are out of scope —
no fair-odds columns exist there.
PHASE 3 — induced all six states in a real browser and read back computed
styles, not just markup. Green resolves on VALUE alone: rgb(0,212,160) on the
model leg and verdict; the +11.7%-EV-at-210 row renders rgb(143,178,222) blue
and a white model leg; quarantine shows MODEL "—" with book and fair intact;
refusal renders no legs at all; free tier renders a lock bar with book -120 and
fair -104 still honest. Landing hero on live data: book -153, fair -129, model
-343, VALUE +21.1% vs fair at +28.1% EV. At a real 390px column the three legs
hold at 117px each with no horizontal overflow and fair no smaller than its
neighbours.
Induction caught a real bug that markup review would not have: the "VS FAIR"
figure compared BOOK to fair, printing "VALUE · -6.5% VS FAIR" — a
contradiction on screen. The design's own two worked examples pin the formula
as MODEL minus FAIR in implied-probability percentage points; modelVsFair now
reproduces both exactly (+2.9 and -1.8) and a test locks them. The figure is
shown only when its sign agrees with the verdict, so a row that clears the EV
bar on the book price while our price sits level with fair leads with the EV
instead of a number that reads as a contradiction.
Tests 3539 passed / 290 suites, web build exit 0.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VCNgGSt5qvcLxaeQqa7Zpj
This commit is contained in:
@@ -144,6 +144,55 @@
|
||||
--forest: var(--acc-0);
|
||||
--forest-dark: #0A2A20;
|
||||
--forest-light: var(--acc-1);
|
||||
|
||||
/* ═════════════════════════════════════════════════════════
|
||||
SESSION 66 — PRICE-LAYER TOKENS (ADDITIVE).
|
||||
The Jul-20 design bundle (`Vyndr Price Triplet.dc.html`) introduces one
|
||||
colour the system did not have. Everything else it specifies already
|
||||
resolves above and is byte-identical to HANDOFF.md — nothing here
|
||||
re-declares or overrides an existing token, and no existing component
|
||||
changes because these are added.
|
||||
|
||||
THE LAWS THESE TOKENS CARRY (machine-readable mirror in
|
||||
`web/src/lib/colorContract.js`; enforced by colorContract.test.js and
|
||||
priceTriplet.test.js — a component must be able to read the law, not
|
||||
just the hex):
|
||||
|
||||
--g-a (#00D4A0) GREEN = EDGE ONLY. edge / active / A-tier /
|
||||
primary CTA. Never decorative. On the price layer:
|
||||
green fires ONLY on takeable edge (ev >= 2 AND the
|
||||
price inside the takeable band) — never on a juiced
|
||||
price, never on raw positive EV.
|
||||
--glow-a GLOW = A-TIER ONLY (A / A+). The scarcest cue in the
|
||||
system; gate every glow through gradeGlows().
|
||||
--amber AMBER = CAUTION / CORRELATION only — plus, from this
|
||||
bundle, the FAIR leg of the price triplet (the
|
||||
de-vigged number is the hero of the price layer).
|
||||
--miss RED = MISS / NEGATIVE only. Never "no edge" (an
|
||||
honest no is the instrument working, not a loss).
|
||||
--priced-out BLUE = EDGE PRICED OUT. The carve-out that lets a row
|
||||
say "there is edge" WITHOUT green saying "take it":
|
||||
positive EV at a price outside the takeable band.
|
||||
Used nowhere else in the system.
|
||||
--mono JETBRAINS MONO = ALL DATA (tabular-nums). Inter is
|
||||
chrome only. Prices are data.
|
||||
═════════════════════════════════════════════════════════ */
|
||||
|
||||
/* A-tier glow, tokenized. The law (glow = A/A+ only) lived in
|
||||
colorContract.gradeGlows() with no token to hand back; this is that value. */
|
||||
--glow-a: 0 0 12px rgba(0, 212, 160, 0.45);
|
||||
|
||||
/* EDGE PRICED OUT — muted blue. Exact values from the design bundle. */
|
||||
--priced-out: #8fb2de;
|
||||
--priced-out-dim: #7a93b0;
|
||||
--priced-out-tint: rgba(106, 147, 200, 0.08);
|
||||
--priced-out-tint-2: rgba(106, 147, 200, 0.12);
|
||||
--priced-out-border: rgba(106, 147, 200, 0.30);
|
||||
--priced-out-border-hi: rgba(106, 147, 200, 0.34);
|
||||
|
||||
/* FAIR leg surface tints (amber hero of the price layer). */
|
||||
--fair-tint: rgba(255, 179, 71, 0.055);
|
||||
--fair-border: rgba(255, 179, 71, 0.22);
|
||||
}
|
||||
|
||||
/* ─────────────────────────────────────────────────────────
|
||||
|
||||
@@ -67,6 +67,14 @@ interface ScanResponse {
|
||||
archetype?: string;
|
||||
archetype_blend?: { archetype: string; weight: number }[];
|
||||
prop_dna?: { reliable: string[]; volatile: string[] };
|
||||
// Session 66 — the PRICE LAYER. `model_odds` is derived from p_win by the
|
||||
// engine and STRIPPED for unentitled tiers, which is what sets
|
||||
// `model_price_locked` — so a locked leg and a missing leg stay distinct.
|
||||
book_odds?: number | null;
|
||||
fair_odds?: number | null;
|
||||
model_odds?: number | null;
|
||||
ev_pct?: number | null;
|
||||
model_price_locked?: boolean;
|
||||
}
|
||||
|
||||
const NBA_STATS = [
|
||||
@@ -742,6 +750,15 @@ export default function ScanPage() {
|
||||
archetype: result.archetype,
|
||||
archetype_blend: result.archetype_blend,
|
||||
prop_dna: result.prop_dna,
|
||||
// Session 66 — the PRICE LAYER. Without these forwarded the
|
||||
// triplet stays hidden no matter what the engine computed
|
||||
// (the Session-44 lesson: this call site is a hardcoded
|
||||
// whitelist, not a spread).
|
||||
book_odds: result.book_odds,
|
||||
fair_odds: result.fair_odds,
|
||||
model_odds: result.model_odds,
|
||||
ev_pct: result.ev_pct,
|
||||
model_price_locked: result.model_price_locked,
|
||||
}) as GradeResultData}
|
||||
onAddToParlay={() => {
|
||||
addLeg({
|
||||
|
||||
Reference in New Issue
Block a user