From 0264486bf9fa61430283ee70fbf9d42970d6eb5d Mon Sep 17 00:00:00 2001 From: Kev Date: Mon, 20 Jul 2026 19:59:33 -0400 Subject: [PATCH] =?UTF-8?q?STATE:=20Session=2067=20=E2=80=94=20price=20lay?= =?UTF-8?q?er=20gated=20at=20two=20doors,=20read=20card=20wired?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.8 (1M context) Claude-Session: https://claude.ai/code/session_01VCNgGSt5qvcLxaeQqa7Zpj --- specs/STATE.md | 95 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 94 insertions(+), 1 deletion(-) diff --git a/specs/STATE.md b/specs/STATE.md index 6ff98db..94abdaf 100644 --- a/specs/STATE.md +++ b/specs/STATE.md @@ -1,5 +1,5 @@ # VYNDR โ€” STATE OF THE WORLD -### As of `8cf9cbf` (main, DEPLOYED + fingerprinted live), 2026-07-20. This file opens every future session. **Start with the CURRENT STATUS + OPEN ITEMS block below.** +### As of `4e2f488` (main, DEPLOYED + fingerprinted live), 2026-07-20. This file opens every future session. **Start with the CURRENT STATUS + OPEN ITEMS block below.** --- @@ -131,6 +131,99 @@ exist locally; harmless, the data restores completely. `specs/snapshot-retention.md` (Phase 2 report + schema) ยท `specs/audit-data/grade-collapse.md` ยท `specs/audit-data/gate-simulation.md`. +--- + +# ๐ŸŸข SESSION 67 โ€” PRICE LAYER GATED + WIRED (2026-07-20) + +## โš ๏ธ THE PREMISE WAS WRONG TWICE โ€” read before trusting a "wire the fields" order +1. **There is no `/api/slate`.** The board reads `GET /api/snapshot/:sport`. +2. **The snapshot already carried the price fields.** `book_odds`, `fair_odds`, + `model_odds`, `p_win`, `ev_pct`, `value`, `takeable`, `fair_prob`, + `devig_method` were all live. Nothing needed adding. +3. **`fairLine` does not exist** (zero hits repo-wide). The Option-A + "derive from fairLine" instruction had no referent โ€” `fair_odds` is already + a real de-vigged American price. + +## Phase 0.5 gates โ€” all PASS, verified numerically +- **Is it a price?** Yes. `fair_odds` = American odds from + `impliedProbToAmerican` inside `devigTwoWay`; `fair_prob` is the probability. + Both distinct from `line` (the stat threshold). +- **Numeric match?** **8/8 EXACT.** Recomputed `fair_odds`+`fair_prob` + independently from stored raw over/under prices; every value matched to the + integer and to 3dp. +- **Poison-independent on quarantine rows?** **YES, proven on the quarantined + cohort itself.** `devigTwoWay(over, under)` takes market prices only โ€” no + model term is reachable โ€” and the 8 rows recomputed above are all + `wrong_opponent_grade`. The poison is in the GRADE, not the price. So + **quarantine suppresses the MODEL leg only; the fair leg stands.** + +## ๐Ÿ”ด THE REAL FINDING โ€” the model price was PUBLIC +`GET /api/snapshot/:sport` is unauthenticated and was serving `model_odds`, +`p_win`, `ev_pct`, `value`, `takeable` to anonymous callers on **25/25 live +rows**. The Session-66 gate on `/api/analyze` was bypassed entirely. +**`/api/hero-prop` was a SECOND door** โ€” it reads Redis directly via +`heroPropService`, so the first fix didn't cover it. + +**`src/utils/snapshotGating.js` strips FIVE fields, not one** โ€” +`model_odds` is the price, **`p_win` IS the price in another base**, and +**`ev_pct` is INVERTIBLE** (ev = f(p_win, book_odds); book_odds is public, so +ev hands the price over). `value`/`takeable` bound it. Market legs +(`book_odds`, `fair_odds`, `fair_prob`, `overround`, `devig_method`) stay on +**every** tier โ€” **the fair leg is never the paywall**. +`src/utils/requestTier.js` resolves tier from a bearer token when present and +**FAILS CLOSED to `free`** on every error path, so a resolution failure can +only withhold, never leak. Responses now vary by entitlement โ†’ `/:sport` and +`/hero-prop` emit `private` Cache-Control for authenticated callers and both +Next proxies forward the bearer token. + +## Read card โ€” why it was empty, and the fix +A manual scan carries **no market** (`{player, stat, line, direction}`), so the +engine has no over/under to de-vig โ€” `book_odds`/`fair_odds` were legitimately +absent. `lookupSnapshotPrices` in the Next `/api/scan` route recovers them from +the pre-graded snapshot (the same cache-only read it already did for locked +odds + team). Join is EXACT on **player + stat + line + side** (`fair_odds` is +side-specific) and returns nothing unless book AND fair are both present โ€” a +user-chosen line the board never graded borrows no other line's price. + +## ๐Ÿ”ด LIVE INDUCTION CAUGHT A SECOND CLASS OF BUG +With the leg stripped, `LiveHeroProp` forwarded everything to `PriceTriplet` +**except `model_price_locked`** โ†’ `deriveValueState` fell to the +missing-model-price branch and the landing page told every anonymous visitor +**"MODEL READ WITHHELD"** โ€” quarantine's copy, which says our own data is +untrustworthy. Nothing was poisoned; it was the paywall. +**A paywall must never wear poison's face.** Unit tests and markup review both +passed this; only rendering the deployed page caught it. + +## Live fingerprint (anonymous, cache-busted) +- Snapshot: model fields `[]`, market fields intact, `model_price_locked: true` +- Read card `/api/scan`: `book -150 ยท fair -126 ยท model null ยท locked true` +- Landing hero renders: **BOOK โˆ’153 ยท โ—†FAIR โˆ’129 (amber) ยท MODEL [LOCK BAR]**, + verdict **"MODEL PRICE ON ANALYST"** + UNLOCK CTA +- `/dashboard`, `/ledger`, `/parlay` โ€” 200, no triplet, unchanged. No consumer + reads `ev_pct`/`model_odds`/`p_win`, so the strip broke nothing. + +## ๐Ÿ“Š FAIR-LEG ABSENCE: 0.0% +636 graded rows: 636 with book, 636 with fair, **0 one-sided**. The hero number +is not a sometimes-number on current data. + +## โš ๏ธ PRODUCT CALL PARKED FOR KEV +The landing hero is anonymous, so it now shows the LOCK instead of the full +triplet it showed this morning (`VALUE +21.1% VS FAIR`). That follows the +stated free-tier rule exactly, but trades a strong shop-window moment for gate +consistency. **Reversal is one line** โ€” add `model_price: true` to the free +tier in `src/config/tiers.js`, or special-case the hero route. + +## Still open +- **Quarantine flag is NOT available at snapshot build.** No service writes + `quarantine_reason` (manual SQL only); it's a retrospective judgement, so a + fresh row can never carry it. The component handles the state if it ever + arrives; wiring an always-null field was refused. +- **Slate row** still held โ€” `lib/marketBreadth.js` computes LINES only. +- **Ledger / public profile** still out โ€” no fair-odds column. +- Screenshots unavailable again (browser capture tool errored all session); + substituted computed-style readback per state. + + --- # ๐ŸŸข SESSION 66 โ€” PRICE-LAYER TOKENS + THE PRICE TRIPLET (2026-07-20)