Files
vyndr/outputs/VYNDR-COMPLETION-MATRIX.md
T

785 lines
60 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# VYNDR — PRODUCT COMPLETION MATRIX
Canonical board. Supersedes STATE.md's narrative. Re-derived from repo (`b0a51c8`),
prod (`api.vyndr.app` / `vyndr.app`, checked 2026-07-27), and the design bundle
(`specs/design-reference/*`). Every cell cites a file, a route, or a prod check.
**DONE = all five YES:** DESIGNED (spec exists) · BUILT (code exists) · WIRED (a user
can reach it) · LIVE (serving in prod now) · HONEST (real data, not fabricated/inflated/
placeholder). A built-but-unrouted component is **WIRED: NO** regardless of code quality.
> **HONESTY PASS applied 2026-07-27 (6bc18d8):** every KNOWN live fabrication removed/hidden
> — see the "HONESTY PASS" section at the end. HONEST cells for rows 19/20/24 updated (✓).
## SURFACE MATRIX — 16 of ~26 fully done (Book Comparison wired 2026-07-29)
| # | Surface | DESIGNED | BUILT | WIRED | LIVE | HONEST | DONE | Evidence / what's missing |
|---|---|---|---|---|---|---|---|---|
| 1 | Landing / hero | YES | YES | YES | YES | YES | ✅ | `Landing.dc.html`; `app/page.tsx`; nav logo; prod `/`→200; Hero/TopSignals/ClaimMeter/ModelRecord all fetch real + self-hide |
| 2 | Dashboard / Slate | YES | YES | YES | YES | YES | ✅ | `Mobile.dc.html`; `Slate.tsx`+`vyndr/GameCard`; Nav "Slate"; prod `/dashboard`→200; snapshot grades real (wnba 25/mlb 5 today) |
| 3 | Scan flow (S6/S7) | YES | YES | YES | YES | YES | ✅ | `Scanner States.dc.html`; `scan/page.tsx`+`ProcessingGrade`; Nav "Read"; prod 200; real grade, honest `NoMarketState` |
| 4 | Grade result card | YES | YES | YES | YES | YES | ✅ | `System.dc.html` reveal; `GradeResultCard.tsx` (3 importers); `/scan`; real grade. Sub-sections (alt ladder, books) gated/absent — see #17/#18 |
| 5 | Grade display / badge | YES | YES | YES | YES | YES | ✅ | `HANDOFF.md:41`; `GradeBadge.tsx`; dashboard/scan/many; prod grades B/C real, no fake A |
| 6 | Ledger | YES | YES | YES | YES | YES | ✅ | `Intelligence.dc.html` S4; `ledger/page.tsx`+`ClvBadge`; Nav "Ledger"; prod 200; n≥20 gate honored |
| 7 | Tier-record | YES | YES | YES | YES | YES* | ✅ | `HANDOFF.md:33`; `TierRecord.tsx` (6 routes); n≥20 gate. *A-tier "edge glow" is ranking-as-credibility, not proven ROI (honest-but-thin) |
| 8 | Pricing | YES | YES | YES | YES | YES | ✅ | `Mobile.dc.html`; `Pricing.tsx`+`ClaimMeter`+`DeskShowcase`; Nav/Footer; prod 200; Stripe real, mocks removed |
| 9 | Public profile `/u` | YES | YES | YES | YES | YES | ✅ | `System.dc.html` /u; `PublicProfile.tsx`; OPEN_ROUTE share link; prod `/api/profiles/test`→404 (privacy honest) |
| 10 | Player profile | YES | YES | YES | YES | YES | ✅ | `Mobile.dc.html` PLAYER; `player/[name]`; reachable via `playerHref` links; prod `/api/stats/player`→found:true (archetype/propDNA/season) |
| 11 | Team hub | YES | YES | YES | YES | YES* | ✅ | `Mobile.dc.html` TEAM HUB; `TeamHub.tsx`; `TeamLink` on cards; prod `/api/team/NYY`→26 roster. *MLB real; NBA/WNBA partial roster |
| 12 | Explore | YES | YES | YES | YES | YES | ✅ | `Intelligence.dc.html`; `ExploreHub.tsx`+`FuturesBoard`/`NewsWire`; Nav; prod 200; real leaders/futures, "TRACKED·NOT GRADED" label |
| 13 | WIRE / ticker | YES | YES | YES | YES | YES | ✅ | `System.dc.html` WIRE; `vyndr/Ticker.tsx`; root layout; prod `/api/ticker`→30 real items |
| 14 | Streaks / hot list | YES | YES | YES | YES | YES | ✅ | `System.dc.html`; landing panels + Explore; prod `/api/streaks/mlb`→240 (computed), self-hide honest |
| 15 | Live tracking | PARTIAL | YES | YES | YES | YES | ⚠️ | `liveTrackingService`+`StatStrip.LiveTracker`; Slate polls `/api/live`; prod hasLive:false now (valid empty). DESIGNED: no dedicated bundle artboard |
| 16 | Parlay lab | PARTIAL | YES | YES | YES | YES | ⚠️ | `System.dc.html` PARLAY BUILDER (not named "Lab"); `parlay/page.tsx`+`ParlayPanel`; `#parlay` drawer; prod `/api/parlay/grade`→real A- |
| 17 | Alt-line ladder | PARTIAL | YES | PARTIAL | YES | YES | ❌ | Champion `alt_lines` real (prod: 5 rungs w/ edge_pct) but **Desk-tier only** (`tierGating.js:55`); proj-v1 `proj_ladder` ledger-only. DESIGNED: only Offseason grouping, no prop alt-stack |
| 18 | **Book comparison (S2)** | YES | YES | **YES✓** | YES | YES | ✅ | ✓WIRED 2026-07-29: `BookComparisonPanel` (self-fetches `/api/books`) on the GradeResultCard; renders per-book lines (books differ), single-book honest state, crown OFF (`BOOK_CROWN_ENABLED=false`, no best claim). Push-to-book + movement strip deliberately HELD |
| 19 | Price triplet | YES | YES | YES | YES | YES✓ | ❌ | ✓HONESTY PASS: null model/EV now NO_MODEL (honest-absent), no false "poisoned" copy. Still ❌: EV layer doesn't *produce* model_odds/ev (separate build) |
| 20 | **Compare (H2H)** | PARTIAL | in-dev | NO | YES | YES✓ | ❌ | ✓HONESTY PASS: fabrication removed → honest in-development state, pulled from Nav+BottomTabBar. Real two-player build pending (awaiting real build) |
| 21 | Newsletter | YES | YES | YES | PARTIAL | YES | ❌ | `NewsletterCapture.tsx` on `/`,`/welcome`; subscribe validates live; send internal-only. LIVE: Listmonk env config `CANNOT DETERMINE` from prod |
| 22 | Slip reader | PARTIAL | YES | PARTIAL | YES | YES | ❌ | `slip/page.tsx`; prod 200; **0 nav links → orphan** (deep-link only). DESIGNED: `a1-s9` spec, not the design bundle |
| 23 | Article media / share (S3) | YES | PARTIAL | NO | PARTIAL | YES | ❌ | `Intelligence.dc.html` ARTICLE MEDIA; `ShareCard.tsx` **0 real importers = DEAD**; OG `opengraph-image.tsx` IS live. In-article archetype figures not built |
| 24 | Calibration / edge board | YES | YES | NO | NO | YES✓ | ❌ | ✓HONESTY PASS: placeholder-edge% `MobileEdgeBoard` REMOVED from the Slate (phones show real cards). Component kept as dead code until a real edge feed exists |
| 25 | System / Intelligence terminal | YES | YES | **NO** | PARTIAL | YES | ❌ | `System.dc.html`/`Intelligence.dc.html`; `/terminal`→redirect to `/dashboard`; `/intelligence` REAL but **orphan (0 nav links)**; `/system` no page (prod 404) |
| 26 | Offseason hub (S-2) | YES | PARTIAL | NO | NO | — | ❌ | `Offseason.dc.html` full spec; **no `/offseason` page** (prod 404); logic only inline in `FuturesBoard`/`NewsWire` on Explore |
Prod endpoints confirmed LIVE + real: `/api/snapshot/{mlb,wnba}`, `/api/accuracy` (n=763),
`/api/ledger/accuracy`, `/api/ticker`, `/api/books/mlb`, `/api/streaks`, `/api/hotlist`,
`/api/live`, `/api/schedule`, `/api/stats/{player,leaders}`, `/api/team`, `/api/parlay/grade`.
## MODEL MATRIX — champion serves; every challenger is ledger-only
| Component | EXISTS | PROVEN | PROMOTED (serving) | USED (a surface reads it) | Evidence |
|---|---|---|---|---|---|
| Champion (engine1) | YES | PARTIAL→**promising** | YES | YES | `analyzeViaEngine1.js`; `enriched``snapshot`/`grades`. SKEW AUDIT 2026-07-29: on takeable MLB overs (n=62) champion p_win→CLV **partial r=0.375, SIG p≈0.003**; SURVIVES the mechanical baseline (no-edge CLV +1.5pt n=20 vs high-edge +8.6pt n=37 → **+7.1pt marginal**). De-vig clean (same-book pairing); close well-defined (DK/MGM r=0.92). PROMISING, NOT confirmed (thin n; lock-staleness check BLOCKED; 1 sig result among many) |
| arch-v1 | YES | NO | NO | NO | `challengerProjection.js`; rides `withChallenger`→**ledger only** (`:693`). "measured, never served" (`ledgerService.js:251`) |
| contact-v1 | YES | NO | NO | NO | `contactChallenger.js`; ledger col `p_win_contact` only |
| proj-v1 / v1.1 | YES | **NO (tested 2026-07-29)** | NO | NO | `projectionChallenger.js` (MLB-batting only). PROOF ORDER verdict: **NOT PROVEN** on n=45 takeable MLB overs — edge-CLV partial-r (controlling price) = 0.245 (n.s.); ~half the raw signal is the shared fair_prob_lock term (mechanical); and the CHAMPION out-predicts it (champ partial-CLV 0.380 sig, champ-edge→hit 0.25 vs proj 0.12). Ledger-only |
| Champion alt-ladder | YES | NO | YES | Desk-only | `analyzeViaEngine1.js:486`; real re-grades ±1 line; `gradeAdapter.js:100` maps to card **Desk-gated** |
| proj-v1 `proj_ladder` | YES | NO | NO | NO | `distribution.js:100`; ledger-only, reaches no card |
| Price gate / EV | YES | PARTIAL | PARTIAL | PARTIAL | fields on `enriched`; hero gates on `isTakeable`+`ev_pct` (`heroPropService.js:78`). **But prod grades show ev_pct/p_win/model_odds/value/takeable = NULL** — built, served-schema, not producing |
### Ladder question (Phase 2.6) — VERIFIED: proj-v1.1 DOES compute rungs above the line
`projection/distribution.js:100` `ladder()` computes `P(stat ≥ k)` for a fixed rung set
`k = 1..LADDER_MAX` (default 4), **independent of the listed line** — so for a line of 1.5
(tradedRung=2) it emits rungs 1 (below), 2 (at), **3 and 4 (ABOVE)**, each a real
negative-binomial survival prob (`projectionChallenger.js:183,200`). "Ladder-up **works**"
— sole cap is `LADDER_MAX=4`. **BUT `proj_ladder` is ledger-only and reaches no user
surface.** So "ladder up from the listed line to find value" is *computed and never wired*.
## HONEST-STATE SUMMARY
### 3.7 — What a PAYING USER sees right now that is not true
1. **`/compare` — fabricated grades, nav-linked + public.** Hardcoded Jokić A+ / Wembanyama A + fake "VYNDR VERDICT" (`compare/page.tsx:10-62`). No data behind it. **The single worst live lie.**
2. **FAQ — phantom processor.** "We use NexaPay" (`FAQ.tsx:28`); every legal/pricing page says Stripe. Also founder price inconsistency ($24.99 vs $19.99).
3. **FAQ + Features — Brier/CLV over-claim.** "Brier score and CLV… published / from day one · Public accuracy by tier" (`FAQ.tsx:498`, `Features.tsx:323`). No Brier surfaced anywhere; CLV held. `CANNOT DETERMINE` a live Brier surface — because none exists.
4. **Mobile edge board — placeholder edge%.** `MobileEdgeBoard.tsx:44` renders a miscalibrated edge feed, masking >40% to "—". The numbers ≤40% still come from a placeholder pipeline. Live on mobile Slate.
5. **Price triplet / EV markers advertised-and-absent.** Grade schema carries `ev_pct`/`p_win`/`model_odds`/`value`/`takeable`; all **NULL on live grades** — the "model price" leg and VALUE marker don't render though the design promises them.
Not inflated (verified honest): grades are B/C only with A/D/F below n≥20 → `pct:null` everywhere; `AccuracyBadge`/`ModelRecord`/`TierRecord`/ledger all honor the n≥20 gate and self-hide. Hit-rate (59%, n=763) shows **without ROI/CLV** (CLV frequently null) — thin, not false.
### 3.8 — The graveyard (built, no user can reach it)
1. **`BookComparison.tsx`** — 0 importers. Backend `/api/books` is live + honest; nothing renders it. (S2 headliner.)
2. **`ShareCard.tsx`** — 0 real importers (S3 share cards).
3. **`components/GameCard.tsx` (legacy)** — type-only import; superseded by `vyndr/GameCard`.
4. **proj-v1 `proj_ladder`** — the above-line probability ladder; computed, ledger-only, never served.
5. **arch-v1 + contact-v1** — challengers, ledger-only, never served ("measured, never served").
6. **`TerminalTemplates.tsx`** — all SAMPLE data; `/terminal` redirects → effectively unrouted.
7. **`DemoScan.tsx`** — defined, never rendered.
8. **`/intelligence`** — REAL signals feed, but 0 nav links (orphan; reachable only by typing the URL).
9. **`/soccer`, `/marketplace`** — REAL pages, 0 nav links (orphans).
10. **`/notifications`** — `RouteStub`, unreachable.
11. **Offseason hub** — full design spec, no page built (prod `/offseason`→404).
## FULLY DONE (all five YES) — 15
Landing · Dashboard/Slate · Scan flow · Grade result card · Grade badge · Ledger ·
Tier-record · Pricing · Public profile `/u` · Player profile · Team hub · Explore ·
WIRE/Ticker · Streaks/Hot list · Live tracking.
## NEAREST TO DONE (one column from YES) — the shortlist a single order could finish
| Surface | The one gap | Finish move |
|---|---|---|
| **Book comparison (S2)** | WIRED: NO | Route `BookComparison.tsx` onto the card from the live `/api/books` store (crown stays off — measured flat). *Backend already shipped.* |
| **Parlay lab** | DESIGNED: PARTIAL | Accept the System "PARLAY BUILDER" spec as the lab spec (functionally live) — a doc call, not a build. |
| **Compare (H2H)** | HONEST: NO | Replace the hardcoded SAMPLE with a real two-player fetch, or pull it from nav until real. |
| **Price triplet** | HONEST: PARTIAL | Make the price-aware EV layer actually produce `p_win`/`ev_pct`/`model_odds` on served grades (built, not firing). |
| **Newsletter** | LIVE: PARTIAL | Confirm/enable Listmonk env (config `CANNOT DETERMINE` from outside). |
| **Slip reader** | WIRED: PARTIAL | Add one nav/More-sheet link (page is live + honest). |
| **Calibration / edge board** | HONEST: NO | Fix the placeholder edge% feed (backend), or hide the board until real. |
Two-plus columns out (bigger builds): **Alt-line ladder** (design + wire the served
probability ladder), **System/Intelligence terminal** (wire the orphan `/intelligence`),
**Article media/S3** (build in-article figures; `ShareCard` dead), **Offseason hub**
(no page at all).
*Tags: all cells VERIFIED against repo/prod/bundle except — Newsletter LIVE (Listmonk env)
and a live Brier surface = CANNOT DETERMINE (none found). Nothing BLOCKED.*
---
# HONESTY PASS — applied 2026-07-27 (commit 6bc18d8, deployed)
Removed/hid every KNOWN live fabrication. REMOVE/HIDE only — no grade, snapshot,
scorer, pipeline, or real feature touched. Updated HONEST cells:
| Item | Was | Now |
|---|---|---|
| /compare (row 20) | HONEST: NO — hardcoded Jokić A+/Wembanyama A + fake VERDICT, nav-linked | Honest **in-development** state; removed from Nav + BottomTabBar. Real two-player build **pulled, awaiting real build**. |
| Pricing (founder copy) | $34.99 desk / struck $19.99 / FAQ $24.99 — wrong | Founder **Desk $44.99** (matches lib/checkout.js), **Analyst $14.99**; struck "regular" numbers removed; DeskShowcase $34.99→$44.99. First-100 counter is REAL (ClaimMeter→Stripe). No "first 50" desk claim (no such counter). |
| FAQ processor | "NexaPay" | **Stripe** (verified live: Next→Express→checkout.stripe.com). `nexapay.ts` + its webhook route were **PURGED 2026-07-27** (NexaPay Purge order) — cross-project contamination, never a real VYNDR path. Provider-side env/keys + the orphaned `user_profiles.nexapay_customer_id` column flagged for Kev. |
| FAQ + Features "Brier/CLV published from day one" | INFLATED (not surfaced) | Removed. Returns when Brier/CLV are actually surfaced. Backend Brier compute untouched. |
| Calibration / edge board (row 24) | HONEST: NO — MobileEdgeBoard placeholder edge% (masked >40%) | **Removed** from the Slate; phones show the real game cards. Component kept as dead code (hidden, not deleted) until a real edge feed exists. |
| Price triplet (row 19) | HONEST: PARTIAL — null model/EV rendered "MODEL READ WITHHELD · poisoned" (false quarantine) | New **NO_MODEL** honest-absent state: MODEL "—" / "NOT PRICED", no verdict. Fixes grade card + LiveHeroProp. EV layer still doesn't *produce* values (separate build). |
## KEPT ON THE BOARD (real work to finish — NOT cut)
- **Article media / S3 (row 23)** — real feature + free SEO/distribution. Finish, don't delete. Only the false "Brier/CLV" claim about it was corrected.
- **Newsletter / THE WIRE (row 21, 13)** — real. Capture live, honest.
## FUTURE MODEL INPUT (logged only — not built this order)
- **News / line-movement signal** — injuries, scratches, lineups, weather move props before books reprice. Wire later as a model input. This is **ADDITIVE** to the media surfaces, not a replacement for them.
## KNOWN HONESTY GAPS (not fixed this order — logged, not fabrication)
- **Hit rate 59% (n=763) shown without ROI/CLV** — thin, not false. ROI/CLV surfacing is a later build.
- **"0 pushes = mis-scoring" — RETIRED 2026-07-29 as a false alarm** (premise re-verified, report-only).
The displayed hit/miss denominators are NOT corrupted by a hidden push bug: the feed is still 100%
half-numbers (0 whole lines in 117,970 captured market lines / 6,050 snapshots / 1,141 ledger rows /
173 lock_lines), all 992 settled actuals are integers, and the smallest actual-vs-line gap in the
whole ledger is 0.5. Expected pushes = exactly 0. See the verdict block below.
- **CLV instrument REPAIRED 2026-07-28** (commit 6552281). Was: 59 usable closing_prob. Now: **406** (MLB 248, WNBA 158) — the collapse was `attachClosingProb`'s `.limit(50000)`/no-ORDER-BY read + write-once `market_unavailable`, NOT capture (95% per-prop coverage) or the join (0 key mismatches). **CLV finding, straight: MLB unders lag the close (mean 9.1 prob-pts, 74% lose); MLB overs +2.0; WNBA flat.** → the +4.57% MLB-C and over/under asymmetry are substantially stale-line artifacts. This UNBLOCKS the proof order (proj-v1.1), which gates promoting p_win/ev to served grades.
**Honest state after this order: "no KNOWN live fabrications" — not "provably none."** The audit was thorough (repo + prod), but absence of a claim of falsehood is not a proof of universal truth.
---
# proj-v1.1 TAKEABLE-EDGE PROOF — verdict 2026-07-29 (report-only, read-only)
**N-gate PASSED: overlap = 45** (settled ∩ proj-v1.1 ∩ MLB over ∩ CLV close ∩ fair_prob_lock ∩ takeable 160..+200). The CLV repair is what made n≥30 reachable. Edge basis = `proj_p_over_line proj_book_implied` (de-vigged fair, VERIFIED not raw book).
**VERDICT: NOT PROVEN.** proj-v1.1's takeable-edge does NOT beat the champion or clearly beat the close on MLB overs.
- Phase 1 buckets (descriptive; only the neg bucket clears ≥15): 6%+ edge (n=11) shows hit 70% / fair-ROI +0.57 / CLV +12.95pts — but even negative-edge rows show +2.7pt CLV (whole over-side is elevated = the stale-high concern).
- Phase 2 partial correlation (the real test): raw r(edge,CLV)=0.455 → **partial r(edge,CLV | price)=0.245, n.s.** at n=45 (t≈1.64, p≈0.11). ~half the raw signal is the shared fair_prob_lock term (mechanical). proj predicts the close itself only weakly (partial r(proj,close|lock)=0.281, n.s.).
- Phase 2.6 champion comparison (same 45 rows): **the CHAMPION out-predicts proj-v1.1** — champ-edge→hit r=0.250 vs proj 0.120; champ partial-CLV=0.380 (SIGNIFICANT, p≈0.01) vs proj 0.245 (n.s.). Positive-edge fair-ROI comparable (proj +0.39 n=19, champ +0.34 n=26).
- Shown, not judged: MLB unders (n=20) CLV 9.34pts, r(edge,CLV)=0.03 (contaminated, zero signal); WNBA — proj-v1.1 does not run (MLB-batting only), N/A.
**Conditional dependency (moot):** the verdict was to be conditional on the under-capture audit clearing the over-side. It's moot — proj-v1.1 fails Phase 2.6 (loses to the champion) BEFORE the audit applies, so NOT PROVEN regardless. The stale-high concern is corroborated (whole-over-side baseline +CLV; half of proj's signal mechanical).
**Notable:** the one statistically-defensible edge signal here is the **CHAMPION's** p_win predicting CLV on takeable MLB overs (partial 0.380, p≈0.01) — NOT proj-v1.1. That champion signal is itself still audit-gated (if MLB overs are whole-side stale-high, even it is suspect).
**What accrues a re-test:** ~20-25 more settled takeable MLB-over rows (to test proj's residual ~0.245 partial against zero), AND proj-v1.1 must demonstrate it beats the champion — which it currently does not. Promotion stays HELD.
---
# OVER-SIDE SKEW AUDIT — verdict 2026-07-29 (report-only, read-only)
Gates the champion's over-CLV signal (partial r=0.375, p≈0.003, n=62 takeable MLB overs — 0.2 CONFIRMED).
**THE THREE NUMBERS (Phase 4), n at each:**
- Mechanical baseline CLV (champ-edge ≤ 0, "no edge"): **+1.51 pts** (n=20)
- Champion high-edge CLV (champ-edge ≥ 0.05): **+8.64 pts** (n=37)
- **DIFFERENCE = the real edge: +7.14 pts**
**VERDICT: SURVIVES BASELINE.** The marginal (+7.1) is ~5× the mechanical floor (+1.5) and the price-controlled partial correlation stays significant. The skew is essentially ONE-SIDED (unders lag 7.0 overall; overs carry only a small +1.5 floor, NOT the +7 a symmetric two-sided over-skew would show). De-vig is CLEAN (`analyzeViaEngine1.js:539` pairs over+under from the same book/fetch — no fresh/stale pairing). Close is well-defined (draftkings vs betmgm over-prob r=0.921, n=151).
**→ GREENLIGHTS building the takeable-edge grade ON THE CHAMPION (engine1 p_win), NOT proj-v1.1** (which lost the proof). This is the project's first edge signal to survive an adversarial audit.
**FLAGGED — promising, NOT confirmed:**
- Thin n (62 overs / 37 high-edge / 20 baseline).
- Phase 2 lock-staleness check is **BLOCKED**: multi-book lines AT LOCK are not retained (`bookprices` is Redis current-only), so we cannot fully rule out that part of the baseline is lock-time staleness. The de-vig being clean + the small baseline make a large hidden skew unlikely, but it's not excluded.
- Sharp (pinnacle) reference covers only **8** props (sharp-CLV +3.17pt, directional hint only).
- This is one significant result among many computed this session — do not overstate.
**What would strengthen it:** retain multi-book at lock (enables the sharp/consensus lock-staleness check), and accrue more settled takeable MLB-over rows. Held: no promotion, no served p_win/ev, no capture fix — diagnosis only.
**UPDATE 2026-07-29 (commit c7067c8): the lock-multi-book gap is now CLOSED.** New `lock_lines` table (migration 033, applied+tracked) persists each graded prop's per-book lines at the lock moment (`lockLineCapture` in `snapshotService`, fenced RLS-service-role-only, grade byte-identical proven). This unblocks the staleness audit for FUTURE rows — it does NOT retroactively fix the existing 62. Confirmation still needs weeks of accrued lock+close+outcome. Populates from the next snapshot tick.
---
# HERO RANKING FIX — 2026-07-29 (commit 41b86e3, deployed)
The landing/hero (matrix row 1) selection was silently broken: it ranked on `ev_pct`, which is NULL on served grades, and **`Number(null) === 0`** made every prop tie at EV 0 → the "top read" was the FIRST takeable A/B prop in cache order — **arbitrary, dressed as ranked** (prod served Kelsey Mitchell, the #6 read by p_win). FIXED: rank by the **champion's p_win** (the only promising edge signal) among A/B **takeable-priced** reads (`isTakeable` 160..+200, same band as the proof/audit); strict-null guard; takeable filter excludes chalk; **no backfill** → honest empty state when nothing qualifies. p_win is ranking-only (never exposed; the route strips it). Display-only — reads caches, writes to nothing. No proven-edge/+EV/best-bet claim, no CLV/ROI/edge number. This makes the champion's p_win a real (display) consumer for the first time. Fingerprint VERIFIED: hero is the max-p_win read across sports (WNBA A), not old code's first-in-order MLB pick (Schanuel 135); untakeable chalk excluded. Visual auth-gated → data fingerprint.
---
# PUSH-SCORING PREMISE VERIFY — verdict 2026-07-29 (report-only, read-only)
Tested the standing ruling "push scoring is correct — do not touch." That ruling rested on
"100% half-number lines → pushes structurally impossible," which was true for the data it was
made on. If whole-number lines had entered the feed since, 0 pushes across settled rows would be
a real mis-scoring bug the ruling was shielding. **The premise HOLDS — the ruling stands.**
**Phase 1 — feed distribution, 4 independent populations, per sport AND per market (never blended):**
| population | what it covers | rows with a line | whole-number lines |
|---|---|---|---|
| `closing_captures` | raw captured market lines, 5 books, `book`+`sharp`, Jul 20-29 continuous | **117,970** | **0** |
| `model_snapshots` | every graded prop **incl. grader refusals** (not survivorship-filtered) | 6,050 | **0** |
| `ledger_entries` (public) | the settled public record, 11 markets | 1,141 | **0** |
| `lock_lines` | TODAY's lock-time per-book lines (freshest feed, migration 033) | 173 | **0** |
Per-market: MLB hits / doubles / rbi / total_bases / stolen_bases / runs / strikeouts / home_runs /
walks / earned_runs / outs / hits_allowed and WNBA points / rebounds / assists / threes — **every
market's min AND max line ends in `.5`** (e.g. MLB strikeouts 2.5-8.5, WNBA points 5.5-26.5, MLB
outs 3.5-19.5). No whole-number market is hiding inside a blended fraction.
**Phase 2 — the push branch would fire.** `outcomeService.js:151` `if (a === l) return 'push'`,
reached **after** `Number()` + `Number.isFinite` guards on both operands — a sound numeric compare,
not the `Number(null) === 0` string-vs-number class that hit the hero. It is the **single scoring
chokepoint** (`ledgerService.js:31` imports `settleResult`; no parallel hit/miss derivation exists
in `src/`), it is **unit-tested live** (`outcomeService.test.js:38`, `nbaSettlement.test.js:104`),
and both `ledger_entries.outcome` and `outcomes.result` CHECK constraints **include `'push'`** — a
real push would score, write, and persist end-to-end.
**Phase 2.6 — the decisive number.** Across 992 settled rows carrying an actual: **0 exact ties, 0
fractional actuals, and the smallest actual-vs-line gap is 0.5** — the arithmetic minimum between an
integer result and a half-number line.
**VERDICT: RULING HOLDS.** Expected push rate is **exactly 0 (P = 0), not "low"** — 0/992 is
*forced*, not chance. The "implausible" flag mistook an arithmetic impossibility for a suspicious
absence; the row closes honestly. Stale n corrected: the flag said 470 settled, it is now **1,097**
(593 hit / 399 miss / 105 void / 44 unsettled-today). Nothing modified — no scoring, settlement,
re-settle, or backfill.
**No latent bug either.** Because the branch is correct and covered, a whole-number market entering
later (NFL/NHL are code-wired but out of season; whole-number strikeout props exist at some books)
would be scored as a push automatically. The residual is a **monitoring** gap, not a scoring gap:
nothing alerts on the first whole-number line to enter the feed. Logged, not built.
---
# EDGE_PCT SCALE DIAGNOSIS — 2026-07-29 (report-only, read-only). Fork REPORTED, not chosen.
**What it is (0.1).** `analyzeViaEngine1.js:265-270``edge_pct = ((projection line) / line) × 100`,
signed by direction, where `projection = l5_avg ?? l20_avg ?? {stat}_per_90 ?? xg_per_90`.
**Independent of `p_win`** (so NOT tainted by the overconfidence that damns `ev_pct`) but it takes
**no price input at all**, so it cannot express a betting edge. **Arithmetically correct, MISLABELLED:**
honest as "% the projection differs from the line," **a lie at any scale as "EDGE."** Two independent
implementations — backend `edgePctFor` and `web/src/lib/gradeAdapter.js:25-31 computeEdge`; the grade
card renders the WEB one, so a backend-only fix would miss it.
**The cap (0.2).** `SANE_EDGE_MAX = 40` (`deskShowcaseService.js:31`: *"beyond this the (model-line)/line
value isn't a market edge"*), mirrored in `slateAdapter.js:613` and `MobileEdgeBoard.tsx:45`. A
self-declared plausibility bound from an earlier order, not a derived statistical one.
**Mechanism (0.3) = SMALL-DENOMINATOR EXPLOSION** — not units, not inversion, not a missing ×100.
`line` is the denominator and **86% of MLB rows (562/655) sit at line 0.5**. Max 620 = a ~3.6 projection
on a 0.5 line.
| population | n | >cap 40 | >100 | median | p95 | max | min |
|---|---|---|---|---|---|---|---|
| **MLB** | 655 | 65.8% (>50) | 13.6% | **60** | 180 | **620** | 86.7 |
| **WNBA** | 486 | 4.9% (>50) | **0%** | 12 | 49 | 77.8 | 51.7 |
| blended | 1,141 | **44.0% (502)** | 7.8% | — | — | 620 | — |
Per line (the proof): MLB 0.5 → 73.0% over cap, max 620 · MLB 1.5 → 43.8%, max 153 · WNBA 12.5 → 6.7%
· **WNBA 26.5 → max 1.9.** Matrix figures re-verified: **51.5% is stale → 44.0%; worst 620 is exact.**
**Shape: structurally broken for MLB, sane for WNBA** — and the scale is a *function of line size*, so
the metric is incomparable across markets **by construction**. No rescaling fixes that.
**Surfaces (Phase 2) — the "~13" count is NOT confirmed. Three surfaces RENDER it:**
| surface | live | access | role | user sees at 620 |
|---|---|---|---|---|
| `GradeResultCard.tsx:182,216,325` | YES (3 importers) | **auth-gated `/scan`****TAGGED FOR CHROME AUDIT** | display | **"+620% edge", raw + GREEN** |
| `DeskShowcase.tsx:40` | YES | **PUBLIC** `/pricing` | display | **"—"** (already honest) |
| `SoccerGradeResult.tsx:229` | YES | orphan `/soccer` (0 nav links, public by URL) | display | raw uncapped `X.X% edge` |
| `MobileEdgeBoard.tsx:47` | **DEAD** (0 importers) | — | sort+display | "—" (pulled in honesty pass) |
| `PropRow:45`, `GradeCard:32`, `ledger/page:40` | live components | — | **type-only, never rendered** | nothing |
| `contentTemplateService.js:164` | public `/api/content` | API | string | uncapped — **no page fetches it** |
**🔴 IT DRIVES TWO LIVE SORTS (the fork's load-bearing answer).**
1. `slateAdapter.selectTopGrades:469-471``grade → confidence → |edge| desc` → **dashboard TOP GRADES
top-10** (`dashboard/page.tsx:419`). **97.3% of rows (1110/1141) sit in a (date,sport,grade,confidence)
tie group of ≥2** (biggest 56), so |edge| is operative for essentially the whole slate — the **de facto
ordering** of that leaderboard.
2. `analyzeViaEngine1.js:506` — the Desk **alt-line ladder** is sorted by `edge_pct` desc.
**Two scale-INDEPENDENT defects inside that sort** (`Math.abs(numOr(g.edge, -Infinity))`): **(i) abs()**
on an already-direction-signed value ranks the model's strongest *disagreements* equal to its strongest
agreements (**177 negative-edge rows**: 58 B / 118 C / 1 F, worst 86.7); **(ii)** `Math.abs(-Infinity)
= Infinity` → a **missing edge sorts FIRST**. The `Number(null)` fabrication class again, new costume.
**Phase 4 correction — "nothing renders `ev_pct`" is WRONG.** `PriceTriplet.tsx:60,67,76` renders
`${pct(ev)} EV`, live and wired (scan → `gradeAdapter:143`). It shows nothing only because `ev_pct` is
NULL on served grades → `valueState.js:121` falls to **NO_MODEL honest-absent**. The right metric already
has a live honest render site, **starved of data, not unwired** — and the card's "EDGE" row sits exactly
where a price-aware number belongs.
**THE FORK (reported, not chosen).**
- **FIX** — dishonest: no rescaling turns a price-free projection gap into an edge (renaming, not fixing);
it silently re-ranks the dashboard top-10 (the hero-class bug just fixed); needs BOTH implementations.
- **HIDE** — cheap: 3 render sites, each already has a null branch (no layout breaks), and DeskShowcase
already proves the honest "—" pattern in-product. Not load-bearing for layout anywhere.
- **RECOMMENDED: HIDE the number and re-point the sort at `p_win`** — the hero order established p_win is
on 100% of recent ledger rows and is the only signal that survived an adversarial audit. Repairing a key
that is a 0.5-line artifact is not worth it. End state: **p_win ranks · ev_pct displays · edge_pct retires.**
The abs()/null-first sort defects deserve their own small order either way.
*Nothing changed: no edge_pct, scale, surface, sort, grade, ledger, or accruing edge touched.*
---
# GRADE-BOARD SORT FIX — 2026-07-29 (spec `specs/grade-board-sort.md`, shipped)
Display ORDERING only. Fixes two defects that were wrong at ANY scale, independent of edge_pct's
separate retirement (Order B, still held).
**Defects removed.** `selectTopGrades` ranked on `Math.abs(numOr(g.edge, -Infinity))`:
`abs()` on an already-direction-signed value ranked the model's strongest **disagreements** level with
its agreements (177 public ledger rows carry a negative edge); and `Math.abs(-Infinity) === Infinity`
made a **missing** signal sort **FIRST** — absent data as the top pick. Now: `grade → confidence →
takeable-gated p_win (nulls LAST) → SIGNED edge (nulls LAST) → input order`, scales never mixed.
The alt-line ladder (`analyzeViaEngine1:506`) no longer sorts by `edge_pct`; it is ordered
highest-p_win-first via the monotonic line rule (line-ASC for an over, line-DESC for an under) at zero
added compute.
**Three premise breaks found report-first.** (1) **`/api/props/top-graded` 404s in prod** — the
dashboard board's feed does not exist, so that board renders receipts/empty and the sort orders nothing
there today; the prior order's "97.3% of rows tie → the edge key decides the board" was a ledger
measurement wrongly extrapolated to it. (2) **p_win is stripped for unentitled tiers by design**
(`snapshotGating`, Session 67 — "shipping p_win is shipping the model price"); verified live, prod
`/api/snapshot` carries p_win on **0/8 MLB and 0/25 WNBA** grades, so the browser path uses the signed
edge and only entitled callers rank on p_win. (3) **Ladder rungs carry no per-rung price**, so the
hero's takeable gate is inapplicable there.
**Verified on real data, both sports, both paths.** Unentitled: WNBA (n=25) ordering CHANGED, MLB (n=8)
unchanged; signed edge non-increasing within every (grade,confidence) tie group — 20 pairs, 0
violations. Entitled: 40 real ledger rows with p_win+locked_odds — p_win-descending, untakeable chalk
not promoted, 36 pairs, 0 violations.
**Hero consistency, honestly:** same signal + same gate, different precedence by contract (board =
grade-tier-first "top GRADES"; hero = p_win-first "top read"). They agree exactly **within** the
leading tier (verified); across tiers the board may lead with an A the hero doesn't pick. Not a
contradiction — do not "fix" it by making the board ignore grade.
**Floor:** 310 suites / 3864 tests green, web build exit 0. **Post-deploy fingerprint (`b85b351`),
both halves verified:** the deployed `/dashboard` chunk was polled across the deploy boundary — attempts
1-3 carried the OLD `Math.abs(...-1/0)` key, attempt 4 flipped to the new comparator with the old one
GONE (before/after observed, not inferred); API health 200 on snapshot/mlb, snapshot/wnba, accuracy. The
backend ladder was **induced on demand** on live MLB game logs rather than waiting for a cron slot:
OVER @0.5 → `0.5•(C) 1(C) 1.5(F)` (line-ASC PASS), UNDER @1.5 → `2.5(C) 2(C) 1.5•(C) 1(C) 0.5(F)`
(line-DESC PASS). Only the *rendered* Desk card remains unverified anonymously → tagged for the Chrome
audit, no visual faked. **Held:** edge_pct rescale/display retirement, building
the missing `/api/props/top-graded` selector, exposing p_win to unentitled tiers.
---
# /api/props/top-graded SERVER SELECTOR — 2026-07-29 (spec `specs/top-graded-selector.md`, shipped)
The dashboard TOP GRADES board had no feed. **The handler NEVER existed in any commit** (searched
`git rev-list --all`) — so the three axios callers (cheatsheetGenerator, gradeOfTheDay, widget) plus
the Next proxy had always received `[]`. Contract recovered from those consumers, not guessed.
**The leak boundary — the whole point of doing it server-side.** The browser cannot rank on `p_win`
for all tiers because `stripModelPrice` deliberately withholds it from unentitled tiers ("shipping
p_win is shipping the price in a different base", S67). Order of operations:
`read cache → RANK with p_win (every tier) → map rows incl. model fields → stripModelPrice(rows, tier)
→ serialize`. A free caller gets the paid RANKING without the paid VALUES. Tier resolution FAILS
CLOSED to `free`; `Cache-Control` is `private` under a bearer token, `public` otherwise.
**Populated-path risk found and handled:** the board's populated branch had never run in prod, and
`dashboard/page.tsx:463` calls `g.stat.replace(/_/g,' ')` **unguarded**`toRow` requires string
`player`+`stat`, a finite `line`, uppercases `sport` for `SportPill`, and drops unrenderable rows.
**One shared ranking definition:** new `src/utils/gradeRanking.js`; `heroPropService` now imports
`takeablePWin` (was an inline copy, behaviour unchanged), the selector imports `rankGrades`, and the
web mirror is cross-checked by test. Board is grade-first ("top GRADES"), hero is p_win-first ("top
read") — they differ by design and agree within the leading tier.
**Honest limit:** the Next proxy forwards no Authorization and caches under a shared key, so via the
dashboard every viewer receives the free-tier payload — correct order, no paid values. That is the safe
default (forwarding auth into a shared cache is how paid payloads leak); per-tier delivery through the
proxy needs a tier-keyed cache and is NOT done here.
**Verified:** 311 suites / 3882 tests green (18 new, leak test on POPULATED p_win), web build exit 0.
**Post-deploy fingerprint (`72a14dc`) — the boundary proven in production:** 404→200 captured across the
deploy boundary; the anonymous live order is *1. Brionna Jones (edge 29.4) · 2. Rhyne Howard (edge 42.9)*
— an edge-only sort would lead with Howard (and the local induction over the stripped snapshot did), so
**server-side p_win ordered it** (Brionna .90 @106 > Howard .745 @120) while the payload carries
**PAID FIELDS: NONE**. A bogus bearer token also yields no paid fields (fail-closed proven in prod).
The board's proxy path now returns 10 props, so TOP GRADES **renders** instead of falling back to empty.
The rendered board is client-side → tagged for the Chrome audit, not faked.
---
# MODEL ARCHITECTURE RECOVERY MAP — 2026-07-30 (report-only) → `specs/model-architecture-recovery-map.md`
**The live grade uses 0 of the 3 specced layers.** Every audited metric (calibration, CLV, skew audit,
takeable floor, p_win→CLV r=0.375) is measured on the SHADOW model. Those findings stand — the shadow
model served every real grade — but none are evidence about the specced engine, which has never been
measured.
| Specced component | State |
|---|---|
| Layer 1 Similarity (`python/utils/similarity.py`, 101 ln) | BUILT · NOT WIRED · **NOT DEPLOYED** |
| Layer 2 Bayesian (`python/utils/bayesian.py`, 320 ln) | BUILT · NOT WIRED · **NOT DEPLOYED** — and its "sport-agnostic math / per-sport parameters" claim is TRUE of the built code |
| Layer 3 grade scale (`grade_thresholds.json`) | BUILT · **WIRED BACKWARDS** — the table maps PROBABILITY→GRADE; the live JS reads it in reverse to manufacture `confidence` from an already-chosen letter |
| Per-sport market-efficiency scaling | **SPECCED-BUT-ABSENT** |
| Live champion (`engine1` + `probabilityEstimator`) | BUILT · WIRED — but the letter is a factor-index with **zero probability input**, and `p_win` is computed separately and never feeds it |
**The Python engine is not in the deploy image at all** (no python/pip in `Dockerfile`; `app.js` only
health-checks it). **The sport boundary is NOT clean on the live path** — adding a sport is a ~10-file
core edit with four documented silent-failure modes, so "make a sport a module" is itself a prerequisite
build. **Per-sport records DO exist** (`sports.mlb` n=526/62% vs pooled `overall` n=937/58%, each with
its own n≥20 gate) — the rule to enforce is that a new sport renders `sports.{sport}`, never `overall`.
**Park×weather is a CHALLENGER, not the champion** ("measured, never served"); xwOBA and bullpen-leash
are absent entirely.
Recovery is dependency-ordered in the map: decide the grading basis → pick a runtime (recommend porting
Bayesian to Node) → wire Layer 2 → reconnect Layer 3 forward → Layer 1 → per-sport efficiency →
challenger promotion → sport-as-module → NFL/CFB. MLB is specced as the reference module.
---
# FULL-OUTPUT GRADE MAPPING + COLLAPSE COST — 2026-07-30 (report-only) → `specs/full-output-grade-mapping.md`
Track-B 1 of 3. The three-layer engine is **BUILT but NOT WIRED and NOT DEPLOYED** (re-verified), so no
posterior/CI is produced today. Measured instead against the collapse that actually exists — three of
them: estimator components dropped; **`p_win` excluded from the grade entirely** (the severe one — the
letter is a factor index with zero probability input); and `grade_thresholds.json` read backwards to
manufacture `confidence`. Market-efficiency scaling is never computed at all.
**THE MEASUREMENT (354 settled rows, locked pre-game p_win — forward, not lookahead):**
| basis | ALL (n=354) | MLB (n=224) | WNBA (n=130) |
|---|---|---|---|
| champion letter → outcome r | **0.0050** (p≈0.93, null) | 0.0686 (n.s.) | 0.0986 |
| probability letter → outcome r | **0.1313** (p≈0.013) | **0.2356** (p≈0.0004) | **0.1258** |
**The served letter is INVERTED between its only two populated tiers — B 52.4% (n=168) vs C 56.9%
(n=174).** Probability letters spread 30.8%→70.0%, use 10-11 of 11 letters (champion uses 3-4), and
split ROI 1.42% (A-family n=78) vs 26.62% (C-/D/F n=51).
**Verdict: costly on MLB, and un-collapsing does NOT help WNBA** (both correlations inverse there) —
so the full-output challenger must be **MLB-FIRST**. Five falsifiable mapping rules are specced (R2
"uncertainty grades down" stated explicitly and droppable if it fails). **Hard requirement on the build
order: persist per-row `n`, `SE`, and pre-adjustment `p`** — without them R2/R4 can never be adjudicated.
**Re-adjudication flagged:** p_win→CLV, the skew audit, **proj-v1.1's "NOT PROVEN" (judged against the
collapsed champion — not final)**, the C1 takeable floor, the calibration curves, and **ROI-by-grade —
with B/C inverted, "MLB-C +4.57%" is likely an artifact of a meaningless letter.**
---
# MARKET-EFFICIENCY SCALING CHECK — 2026-07-30 (report-only). **VERDICT: FLAT.**
**Premise correction first (measured):** the claim that "full-output and collapsed grades agree 100%"
does not hold — on 512 rows carrying both they agree **17.8%**, and **33.8% differ by 3+ tiers**. The
prior discrimination result stands (champion letter r=0.0050 null vs probability r=0.1313; MLB 0.0686
n.s. vs 0.2356 p≈0.0004). Repo unchanged between orders. **The collapse was not a phantom and the
re-adjudication list stays open.**
**0.1 `marketEfficiency.js` does not exist** — zero occurrences of `market_efficiency` /
`efficiency_score` anywhere. The spec's 0.85/0.60/0.55 values DO appear in `grade_thresholds.json` but
those are **probability bands**, a coincidental overlap, not efficiency scores.
**0.2 The base edge thresholds do not exist either**`engine1.js` has **zero `edge` references**; the
grade is an additive factor index, not an edge-vs-threshold comparison. So
`threshold = base × efficiency` has **no host**.
**Phase 1 dispositive: `engine1.js` has ZERO `sport` references.** Sport is not an input to
`computeFactors`, so per-market or per-sport scaling is structurally impossible in the live grader —
not merely unwired. Applies to the champion.
**Phase 2:** the matched-edge test is confounded (edge isn't the grading input — the same market emits
B and C at one edge). The discriminating aggregate: mean grade index **wnba points 4.71** (mean edge
10.2) vs **mlb hits 4.58** (69.5) vs **mlb total_bases 4.32** (84.9) — the efficient market earns the
highest grades on one-eighth the edge, the opposite of the spec.
**Scope:** a flat threshold is a grade-CALIBRATION gap — it does **not** touch the projection or the
CLV edge (which measured `p_win`, never the letter), so it is not a third shadow-model alarm. But it is
**not independently bounded**: with no threshold step to multiply, efficiency scaling presupposes
probability grading. It is rule **R4 of `specs/full-output-grade-mapping.md`** and belongs to that
MLB-first challenger.
---
# TAKEABLE TAGGING BUILT · EFFICIENCY CHALLENGER BLOCKED — 2026-07-31 → `specs/takeable-tagging.md`
**Champion grade byte-identical (verified by diff).** Additive tags only.
**BLOCKED — the efficiency challenger.** Review Zero found all three inputs ABSENT: efficiency scores
(zero occurrences anywhere), base edge thresholds (`engine1.js` has zero `edge` references — the grade
is not edge-vs-threshold), and the claimed ±0.05 additive nudge (the only 0.05s on the grade path are a
teammate-absence feature, a bvp cutoff, and the shrink-toward-0.5 term). With no additive scaling to
swap, no threshold to multiply, and **zero `sport` references in `engine1.js`**, a
differs-in-exactly-one-thing challenger cannot be constructed. It needs **R1 probability grading**
first (`specs/full-output-grade-mapping.md`); shipping R1+R4 together would attribute an R1-driven
re-letter to the efficiency fix. Coverage compounds it: **9 of 11 live markets have no specced score.**
**BUILT — ledger takeable tagging (deferred C2).** `src/config/takeableStandard.js`: floor on the minus
side, **uncapped plus** — deliberately NOT `valueEngine.isTakeable` (the 160..+200 promotion band). A
+400 prop is not promotable but IS takeable; a test locks the divergence. Absent price → `null`, never
`false`. The floor is **policy, not derived**, and each row records `takeable_floor` so a re-derivation
can re-tag. Migration 034 applied + tracked. **Backfill: 1,254 rows → 1,246 tagged (781 takeable / 465
below floor), 8 NULL with `null_despite_price = 0`; settled 1,163 and graded 1,254 unchanged.**
**NOT applied — the model-version boundary tag:** no scaling change shipped, so no boundary exists;
stamping one would record a model transition that never happened.
312 suites / 3,890 tests green, web build exit 0.
---
# EDGE-SHADING CHALLENGER — built + measured 2026-07-31 → `specs/edge-shading-challenger.md`
Challenger only; champion byte-identical; nothing promoted. The mechanic is sound and built
(`adjusted = raw_edge × f(e)`, `f` bounded to (0,1], one fixed bar that never moves; same raw 6% edge
**A** in soft `mlb:total_bases`, **B** in sharp `nba:points`, unit-proven).
**But the measurement says the flooding is NOT fixed:** on 1,250 live rows the challenger grades
**79.0% A / 80.9% A-or-B** (MLB 93.4% A) vs champion 0.2% A.
**Why — two findings.** (1) **The shading is a no-op on the live board: 0 of 1,250 rows are actually
shaded.** 96.5% are unscored (f=1) and the one scored market present is the anchor (f=1.0 by
construction); `mlb:strikeouts` and `nba:points` are absent from the ledger entirely (our basketball is
`wnba`). (2) **The input scale is the bug, not the placement.** Against a fixed 5% bar the RAW edge
already clears A on 100% of MLB doubles and 89.6% of hits, with MLB's median raw edge at 60% — twelve
times the bar. **Applying the sharpest score in the spec (f=0.647) to every row still leaves 75.8%
clearing A.** A multiplier bounded ≤1 cannot close a 12× overshoot.
`edge_pct` is a price-free `(projline)/line` gap whose scale is a function of line size — not a
betting edge, so no fixed betting-edge bar is meaningful against it. **Unblocking needs the input
replaced (`p_win` vs `fair_prob`, both already stored), not the multiply moved**, plus scores fit from
our own record for the 9 of 11 live markets that have none.
313 suites / 3,899 tests green, web build exit 0.
---
# PROMOTION GATE NOT PASSED · ORDER B SHIPPED — 2026-07-31 → `specs/edge-pct-display-retirement.md`
**No flip.** Champion grade byte-identical; projection/p_win/CLV untouched.
**Gate: 3 of 4 prerequisites fail.** Scores are estimated priors (and the premise's NBA 0.72 / WNBA
0.68 are not in the code — there is no WNBA score); **the version-boundary tag never landed**
(`modelEras.js` has zero shading refs); **no rollback flag exists**. Takeable tags did land (034).
**The approved delta is wrong.** Approved 43.6% re-letter, efficient tighten / soft hold. Measured on
1,250 rows: **97.4% change, 79.8% UP**, → **79.0% A-family (MLB 93.4%)** vs champion 0.2%, with
**0 rows actually shaded**. The re-letter is entirely the grading-basis switch, not efficiency shading
(inert: 96.5% of markets unscored, the one scored market is the f=1 anchor). Flipping would mint A's
across 79% of an append-only record on a letter with r ≈ 0.005 vs outcomes.
**Order B shipped:** edge_pct display retired from GradeResultCard (strip, EDGE cell → `—`, ladder
rung) and SoccerGradeResult; DeskShowcase kept; **computation + signed-edge sort fallback survive**
(deleting them re-breaks the 07-29 sort fix). Two build-breakers fixed; two pre-existing sign-colour
tests superseded by the stronger "no edge figure renders at all".
314 suites / 3,908 tests green, web build exit 0.
---
# MATRIX REFRESH — 2026-07-31 → full re-derivation in `specs/pre-audit-status-pull.md`
Re-derived from repo `10aaaeb` + live prod probes (nothing inherited). **15 of 26 fully done.**
**No promotion has occurred.** The shading challenger is imported by zero production files and live
grades carry **0.0% A-family** (MLB `{B:1,C:4}`, WNBA `{B:15,C:10}`). Neither the "92.9%" nor the
"43.6%" re-letter figure was ever measured here; the challenger's real numbers were 97.4%
would-change / 79.8% up / 79.0% A, with **0 of 1,250 rows actually shaded**.
**Changed since the last matrix:** row 18 **Book comparison → DONE** (`BookComparisonPanel` routed to
the grade card — the headline dead component is resolved); row 4 **Grade card HONEST improved**
(edge_pct display retired, `EDGE` renders `—`); row 17 ladder rung % also retired.
**Still dead code:** `ShareCard` (0 real importers), `MobileEdgeBoard` (0, correctly hidden),
`DemoScan` (0). **Still orphaned (live, 0 nav links):** `/intelligence`, `/soccer`, `/marketplace`,
`/notifications`, `/slip`, `/compare`, `/parlay` (drawer-only). **404:** `/system`, `/offseason`.
**LIVE-but-not-HONEST: none found.**
**Design is NOT complete:** Live tracking, Slip reader and Newsletter are shipped but have **no design
artboard** — design is the gap, not build. Offseason is the reverse (designed, never built).
**Chrome audit manifest: 11 items**, four of which need an **entitled Desk session** (grade card
entitled half, alt-line ladder, entitled top-graded board, ledger).
---
# BOUNDARY NOT WRITTEN + BUILD TRIAGE — 2026-07-31 → `specs/incomplete-surface-triage.md`
**No promotion exists, so no recalibration boundary was written** (writing one would fabricate a model
transition in an append-only record). Proofs: every deployed `code_sha` in the last 5 days is a
documented session commit stamped `engine1@2026-07-20`; daily A-family share 07-24→07-30 is flat at
0.0-1.6% with no step change; `efficiencyShading` has zero production importers. Neither the 92.9% nor
the 43.6% re-letter figure is attested — the only measured numbers (full board, 1,250 rows) were 97.4%
would-change / 79.8% up / 79.0% A, with **0 rows actually shaded**.
**Triage: 14 surfaces, 5 waves.** W1 wiring (`/intelligence`, `/slip`, `/parlay`, `/marketplace` after a
copy pass) · W2 design-only artboards (Live tracking, Slip reader, Newsletter — built/live/honest,
DESIGN is the only gap) · W3 self-contained (`/compare`, ShareCard host, `/notifications`) · W4
model-gated (price-triplet MODEL leg + edge board — need `p_win` vs `fair_prob`; `edge_pct` would
re-ship the 620% lie) · W5 quota/sport-gated (`/soccer` blocked on odds-api 0/500, `/system`,
Offseason).
---
# WAVE 1 WIRED — 2026-07-31 → `specs/wave1-wiring.md`
Three surfaces **proven to work with real data, then linked**; `/marketplace` completed honestly.
No grade/ledger/model/scoring change.
- **`/intelligence`** → nav-linked + **added to GATED_ROUTES** (its feed 401s signed-out). Gating is
server-side by tier (desk 50 / non-desk 8), never blur-over-full-data. **`/system` is NOT a
duplicate to build** — `System.dc.html` is a multi-surface artboard whose INTELLIGENCE section is
already this page; the 404 is correct.
- **`/slip`** → nav-linked after parsing a real DraftKings slip **3/3 legs**. Layout-rigid: an
unsupported layout returns **zero legs, never wrong ones**; real-world hit-rate CANNOT DETERMINE yet.
- **`/parlay`** → **direct nav link** (was drawer-hash only); stays OPEN as the free parlay funnel.
- **`/marketplace`** → every item now states **"Not built yet."**; subhead: *not a purchase, not a
pre-order, not a promise of a ship date*; **no profit claim**; the waitlist capture was already real.
Matrix effect: rows 16 (Parlay lab), 22 (Slip reader) and 25 (`/intelligence` half) move from
**WIRED: NO → YES**. 315 suites / 3,920 tests green, web build exit 0.
---
# WAVE 3 — 2026-07-31 → `specs/wave3-compare-and-resolution-tail.md`
**`/compare` BUILT** (row 20 → real). A same-market head-to-head on the live player feed: rows aligned
on measures both sides share, `NO DATA` for an unresolved side, `—` never 0 for a one-sided measure,
refusal when neither resolves, and **NO VERDICT**. Live-verified: Judge vs Ohtani, 5 of 5 shared
measures; bogus name → NO DATA.
**Resolution tail — ALL FIVE outputs scoped, none shipped** (rows 23 ShareCard, `/notifications`,
result posts, recap): share-card generation **SPEC'D-NOT-BUILT** (absent from the resolve fanout;
renderer has zero callers) · push/Telegram/Discord **BUILT-NOT-FIRING** (env-gated; `push_subscriptions`
and `user_notifications` both **0 rows**) · recap **SPEC'D-NOT-BUILT** (no file). **And nothing calls
`/api/grading/resolve` — there is no ESPN poller in the repo**, so the tail is unreachable regardless.
The live settle path emits ops alerts only, with zero user-facing output.
316 suites / 3,930 tests green, web build exit 0.
---
# DESIGN-vs-BUILD GAP AUDIT — 2026-07-31 → `specs/design-vs-build-gap-audit.md`
**61 implementable items** enumerated from `specs/design-reference/` (Jul 22) against the current repo:
**BUILT-TO-SPEC 20 · BUILT-BUT-DRIFTED 7 · PARTIAL 16 · ABSENT 18.** The design is ahead of the build;
the gap is implementation, not design.
**Biggest gap:** the glyph library — **38 of 83 SVGs wired (46%)**, and the design implies **74 display
archetypes vs the registry's 41**.
**Drift on recently-built surfaces:** book comparison (wired 07-29) has **no crown, no disagreement
axis, no SPLIT chip, no movement strip**; the mobile tab bar lacks the designed **READ-FAB**;
calibration gates at **n≥20 vs the designed N30**.
**Correction to the earlier status pull:** the **Newsletter IS designed** (S5 "The Report") →
design-exists-needs-build. Only **Live tracking** and **Slip reader** are genuinely design-missing.
**Six-wave ordered build list:** self-contained (glyphs, primitives, boundary-channel blue) → scanner-
nudge-gated → model-gated (Price Triplet EV leg, calibration curve) → **resolution-pipeline-gated
(share-card masters — the tail has no generation step and no trigger)** → licensing-gated (book logos,
push-to-book) → large surface builds (Offseason, S3 media, The Report, S2 primitives).
---
# D1-A SHIPPED — 2026-07-31 (design self-contained wave, part A)
Backend untouched. **Glyphs:** 6 classifier-backed combat marks wired from the package SVGs
(GLYPHS 38→44), replacing emoji fallbacks; 39 package SVGs with no classifier deliberately NOT wired
(they'd render nothing) and 2 classifier-backed archetypes have no package SVG — both held for D1-B.
**Boundary channel completed:** PriceTriplet's `NO_MODEL` was the last boundary state rendering in
neutral text; it now uses `--priced-out`, so the blue law covers every "can't hand you this" state.
**Reaction primitives** (`lib/reactions.js` + keyframes) at exact HANDOFF timings, with `nudge()`
refusing a no-op so it can never run as an idle loop. **READ-FAB** at exact geometry (50px /
translateY(-14px) / 6px ring). Audit correction: the `#0E0E14` card token was already tokenised.
317 suites / 3,946 tests green, web build exit 0. **Not done, carried in D1:** row-hover rationale,
IntersectionObserver reveal, team-gradient chips.
---
# D1 FINISH — 2026-07-31 (row anatomy: rationale · reveal · team chips)
Backend untouched. Three pure modules, unit-locked:
- **`rowRationale.js`** — the hover "why" is the grade's OWN `reasoning` + `kill_conditions_triggered`
(VERIFIED present on live grades, built from real l5/l20/gap/home/defense/rest), or **NULL**. No
generic fallback; a locked/tier-gated reasoning counts as absent rather than paraphrased.
- **`reveal.js`** — IntersectionObserver, fires **once then unobserves**, reuses D1-A's `bootDelayMs`
(one source of truth for the 60ms stagger), and reveals immediately when the API is absent so
content is never hidden.
- **`teamChips.js`** — Rev-3 chip geometry + the 1/.86/.64/.48 ramp. **Colour coverage is 10 of ~80
teams** (the artboard's full set, verbatim); every other team renders honest-neutral rather than a
guessed colour.
318 suites / 3,961 tests green, web build exit 0. **Mounting the modules into the live row components
is a follow-up**; the visuals go to the Chrome audit.
---
# TIER REDESIGN SPEC — 2026-07-31 → `specs/tier-redesign-spec.md`
Option 2 (settled-free / live-paid) designed, not built. **FREE** = full data aggregator + the
**complete settled record** (letter, reasoning, edge, outcome — browsable) as the proof hook.
**ANALYST $14.99→$24.99** = tonight's live grades + reasoning + edge. **DESK $44.99→$59.99** = +
alt ladder, Kelly, portfolio, engine2.
**The gate already has its discriminator:** `/api/snapshot` merges per-grade `outcome` (live WNBA:
5 of 25 settled), so `outcome != null ⇒ free`, `null ⇒ paid`, with no new pipeline. Filter whole
grades server-side, never infer resolution from time, fail closed to LIVE.
**Two findings that reshape the plan:** (a) founder pricing is gated by **code + expiry, not seat
count** — the real counter (`/api/founders/count`, live 0/100) only displays and is cached 300s, so
making it a transactional gate is a genuine build; (b) the user base is **3 free, 0 paid**, so the
migration is a courtesy note, not a mass event — effort belongs on the settled-record proof surface.
---
# BUILD 1 — THE SETTLED/LIVE GATE (shipped 2026-07-31)
Unresolved = paid (Analyst+), resolved = free. Serving/gating only; `src/services/` untouched.
Resolution is read **only from a written outcome** (never time or game status), `void`/`unrecoverable`
count as resolved, and `isResolved` **fails closed to LIVE** so a settle failure withholds rather than
exposes. Free gets **settled grades in full including reasoning** — the proof product — which also
turns the old unenforced board-reasoning leak into a deliberate rule. Live grades become a **shell**:
judgment stripped, real data kept (incl. `fair_odds`, which is never the paywall), `locked: true`
stamped. The tease is **aggregate only** (`live_locked {count, tiers}`) and no gated row carries a
grade, so nobody can tell which prop is the A.
**Live anonymous fingerprint:** 25 grades → **5 settled free-full, 20 locked**, `live_locked
{"count":20,"tiers":{"B":13,"C":7}}`, **judgment-field leak: NONE**. 319 suites / 3,971 tests green,
web build exit 0.
---
# BUILD 1 CORRECTED — itemized grades are PAID, live AND settled (2026-07-31)
The resolution-flip shipped earlier the same day was **replaced**: freeing grades at settlement made
the free tier a one-day-delayed feed of the whole product. No per-grade flip now — every itemized
grade is Analyst+.
**Free:** data aggregator + the **aggregate record that already existed** (`/api/accuracy` n=937,
byGrade, per-sport; `/api/ledger/accuracy`, both honoring the n≥20 hollow law with `pct:null`) + a
**capped, day-rotated 3-call sample** (resolved only) + the locked shell of tonight's reads
(`live_locked {count, tiers}`, aggregate-only, never joinable to a row).
**Live anonymous, cache-busted:** 25 grades, **judgment leak NONE**, every row `locked`, tease
`{count:20, tiers:{B:13,C:7}}`, `free_sample` 3 of 5 settled — **exploit dead**. `outcome` is kept on
gated rows because a result is a fact, not a judgment.
**Verification note:** the first post-deploy read was a CDN-cached pre-deploy body and falsely showed
a leak; `max-age=30` on this endpoint means post-deploy checks must bust the cache.
319 suites / 3,970 tests green, web build exit 0.
---
# FREE PROOF SURFACE — `/record` (shipped 2026-07-31)
Tier-record-forward, presentation-only (`src/` untouched). Reads `/api/accuracy` + `/api/ledger/model`
and prints them as-is: **B 60% n512, C 57% n413 with C honestly below B; A/D/F hollow with real
samples**. Sport slicing is client-side (the endpoints ignore `?sport=`).
**The rule that matters:** a withheld percentage stays null — A is 1/2 and a test asserts we do **not**
derive 50%. **CLV renders an honest absence**: `beat_close_pct` is null behind the capture-reliability
guard, so the panel says NOT PUBLISHED YET and explains why, and tests forbid the computable-but-wrong
34/937 = 3.6% fallback. Calibration and accuracy-over-time are **named as held**, not faked — no honest
source exists yet.
Cache-busted fingerprint: page served, CLV honest-absent, guard named, held pieces named, **no "3.6"**,
**no hard-coded percentage in the markup**. The hollow-explanation line is client-conditional → Chrome
audit. 320 suites / 3,986 tests green, web build exit 0.