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:
Kev
2026-07-20 18:22:00 -04:00
parent f549422758
commit 8cf9cbfc26
11 changed files with 1027 additions and 1 deletions
+40 -1
View File
@@ -105,6 +105,45 @@ function mapScanToGradeResult(input = {}) {
// Session 42 — Player Intelligence additions. All OPTIONAL + self-hiding:
// they only render once the engine supplies them (Session 43 data pipeline).
...buildIntelFields(input),
// Session 66 — the PRICE LAYER (book · fair · model). Self-hiding: absent
// unless the engine supplied real prices, so a read with no market prices
// renders the projection alone rather than an empty gauge. NEVER
// fabricated — the design file's numbers are a spec, not a fallback.
...buildPriceTriplet(input),
};
}
/**
* buildPriceTriplet(input) — the optional price-layer block for the card.
*
* Returns `{}` (section stays hidden) unless the engine supplied at least a
* book price AND a fair price: with no honest de-vigged number there is no
* price story to tell, and a lone book price is just the market repeated back.
*
* `model_price_locked` is set by the SERVER (utils/tierGating strips
* `model_odds` for unentitled tiers and flags it) — the free tier never
* receives the model price, so the lock is real, not a client-side blur over
* data that was already sent. Book and fair always pass through: the fair leg
* is never the paywall.
*/
function buildPriceTriplet(input) {
const n = (v) => {
if (v == null || v === '') return null;
const x = typeof v === 'number' ? v : Number(v);
return Number.isFinite(x) ? x : null;
};
const book = n(input.book_odds);
const fair = n(input.fair_odds);
if (book == null || fair == null) return {};
return {
priceTriplet: {
book_odds: book,
fair_odds: fair,
model_odds: n(input.model_odds),
ev_pct: n(input.ev_pct),
quarantine_reason: input.quarantine_reason || null,
model_price_locked: input.model_price_locked === true,
},
};
}
@@ -142,4 +181,4 @@ function buildIntelFields(input) {
return out;
}
module.exports = { mapScanToGradeResult, statLabel, computeEdge, isPhosphorConfirmed, toSignals, buildIntelFields };
module.exports = { mapScanToGradeResult, statLabel, computeEdge, isPhosphorConfirmed, toSignals, buildIntelFields, buildPriceTriplet };