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

60 KiB
Raw Permalink Blame History

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; enrichedsnapshot/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 withChallengerledger 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. /notificationsRouteStub, 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-270edge_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 /scanTAGGED 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-471grade → confidence → |edge| descdashboard 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,' ') unguardedtoRow 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 eitherengine1.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 buildSystem.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.
  • /parlaydirect 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.