Commit Graph

3 Commits

Author SHA1 Message Date
builtbykev 3fe840ab83 Diagnose grade collapse + find the DEAD probability layer (report only)
Kev's call: investigate the B/C grade collapse before building. Report
only — no grade logic, thresholds, or engine code touched.

FINDING 1 — the collapse is real, live and structural. Across 604 ledger
rows and both sports the engine has emitted exactly TWO grades (B, C) and
NINE confidence values (63/57/55/52/47/45/35/25/20), ceiling 63. Still
true today on both sports. Confidence does NOT determine the letter:
conf 45 -> B while 47 and 52 -> C (non-monotonic), so the surfaced
confidence is not the quantity the letter came from. Edge scale still
broken: 311/604 rows exceed the frontend's sane cap of 40, 39 exceed 100,
worst 620.

FINDING 2 (bigger) — the entire probability layer is DEAD in production.
Live /api/snapshot/mlb: p_win, kelly, ev_pct, model_odds and value are
absent on 0/8 grades, while alt_lines (Desk-gated) IS present 8/8 —
proving nothing is tier-stripped, they are simply never computed.

Root cause: gameLogService.pythonPath returns null for MLB by
construction and the Python service is offline for NBA/WNBA, so
meta.gameLogs is [] for every sport; estimateProbability returns
p_over null; every field guarded by `if (pWin != null)` is skipped.
This is the S46 bug in a second location — that fix added an MLB branch
to featureCache.gameLogFeatures (which is why grades/projections still
work) but never to the estimator path.

Consequences: EV — the Model Train's whole ranking signal — has never
been computed on a live prop. Hero v2 matches nothing and always falls
through to the recent-read fallback (live /api/hero-prop returns
is_recent:true). Quarter-Kelly, sold on the pricing page and listed BUILT
in PROMISE-AUDIT.md, never runs. The value triplet is a duet live.

Recommend re-sequencing: revive the probability layer BEFORE G-a and
C-led (C-led would persist a column of nulls; G-a's EV_FLEX_THRESHOLD
would gate on a permanently-null value — Kev's EV_FLEX_ENFORCE=0 ruling
accidentally prevented an outage). featureCache:206-226 already has both
adapter branches and is the template.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SmNjJAwEnqHPtXbvSZR8kA
2026-07-19 18:13:06 -04:00
builtbykev 669479097c Model Train G-b/C-cal: gate simulation + calibration report (docs only)
REPORT-FIRST per the arc order. G-a is HELD — the data changes the
recommended dials. No engine code touched.

Replayed against live ledger_entries (576 rows, 6 game days, 470 settled)
because the "30 days of stored snapshots" does not exist: snapshot Redis
keys are latest/previous only at 24h TTL, and no backtest harness exists
anywhere in the repo.

Findings that change the plan:
- The -400 floor shipped this morning was the whole win: past -400 hit
  80.3% against an 86.9% breakeven = -13.29u / -7.7% ROI on 173 settled.
- Arc 2's incremental cut over the live gate is ~11 props in 6 days. The
  only material change is gating the flex band behind 2x EV.
- The flex band (-161..-250) is our BEST band (+2.2% ROI, n=70) and the
  takeable band is flat (-0.3%, n=209) — the opposite of the assumption
  behind EDGE_FLEX_WALL. Recommend shipping the knob with enforcement
  OFF until EV is persisted and measured.
- ev_pct/p_win are on NO ledger row, so the EV half of the gate cannot be
  replayed at all. C-led (persist EV) is now the highest-leverage item.
- Confidence is monotonic but understates hit rate by ~20-25 points, and
  the entire public ledger contains only B and C grades — zero A/A+.
  That breaks hero v2 (isAB) and undermines "A-RATED" copy. Escalated.
- L-a answered: alt_lines carry NO odds and the feed has no alternate
  markets. L-b is blocked on a data source, not engine work.
- C-led needs no odds backfill (locked_odds 99.1% populated).
- U-deg: the projection==0 leak is already closed (0 since 07-18).
- C4 confirmed in data (359/376 MLB closes == the lock). Stays suppressed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SmNjJAwEnqHPtXbvSZR8kA
2026-07-19 18:04:29 -04:00
builtbykev 18bf3ecb51 Reconcile the record: STATE.md header + Model Train arc 1 spec (docs only)
Arc 1 (7a925f4) shipped without a spec and without a STATE.md entry — the
plan lived only in a session context that was lost. Both written from the
code on disk, not from memory.

- STATE.md: header was stale at a8e383e; now 7a925f4 (pushed, NOT yet
  deploy-fingerprinted). New top section records de-vig + EV + takeable/
  value gates + hero v2 + the value triplet, the real config values, and
  the 274/3289 -> 276/3306 test baseline.
- specs/model-train.md (NEW, per CLAUDE.md rule #1): every knob and its
  ACTUAL default (TAKEABLE_ODDS_CEILING -160, TAKEABLE_ODDS_MAX +200,
  VALUE_EV_THRESHOLD 2, JUICE_ODDS_FLOOR -400, RARE_EVENT_LINE_MAX 0.5);
  the gate AS BUILT (flat price-only refusal at -400 pre-feature, NOT
  edge-aware, no -250 wall; the -160..+200 band never refuses a grade and
  is enforced on the hero alone); the triplet + hero v2; and a checklist
  of what is NOT built.

Recorded honestly rather than assumed: EDGE_FLEX_WALL, HARD_JUICE_WALL,
LADDER_ODDS_MAX and MIN_RUNG_PROBABILITY do not exist in the codebase; no
frontend reads ev_pct/fair_odds/model_odds/book_odds/suppressed_reason yet;
the value fields are ungated to free tier; a second EV implementation
(processing/EVCalculator.js) still coexists with devig.evPct.

No engine code touched.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SmNjJAwEnqHPtXbvSZR8kA
2026-07-19 17:56:09 -04:00