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
This commit is contained in:
Kev
2026-07-19 18:13:06 -04:00
parent 669479097c
commit 3fe840ab83
2 changed files with 208 additions and 0 deletions
+19
View File
@@ -176,6 +176,25 @@ Full arc definitions live in the Session-63 order. Status only here; update as e
| **U-deg** MLB degradation | ✅ **STATUS REPORTED** | `projection==0` leak **already closed** (0 occurrences since 07-18). `edge_pct` scale still broken. |
| **U-fp** Arc 1 fingerprint | open | Do it on the first deploy this train ships. |
### 🔶 OPEN DECISION — FLEX BAND ENFORCEMENT (Kev, 2026-07-19)
**Ruling:** build `EDGE_FLEX_WALL` (250) + `EV_FLEX_THRESHOLD` (default **4 %**, = 2×
`VALUE_EV_THRESHOLD`) but ship with **`EV_FLEX_ENFORCE=0`**. Flex-band props
(161…−250) **grade exactly as they do today — the band is NOT cut.** The ledger shows
it is our most profitable segment (**+2.2 % ROI, n=70**) and we will not restrict a
proven-profitable band on an unvalidated threshold. Record `ev_pct` on every flex prop
now so real in-production data accumulates.
**TRIGGER TO REVISIT:** once ~2 weeks of production `ev_pct` data exists on the
161…−250 band, report the **`ev_pct` distribution vs settled outcomes for that band**,
then Kev decides the threshold — or whether to enforce at all.
**Do NOT flip `EV_FLEX_ENFORCE=1` without that report and explicit sign-off.** It comes
back as a data-backed decision, never a silent flip.
**Unaffected — these ship and enforce normally:** `HARD_JUICE_WALL` (250, never grades),
`LADDER_ODDS_MAX` (+400), `MIN_RUNG_PROBABILITY` (0.25), the no-odds refusal, and the
folded `projection > 0` check.
### Backtest harness
**None exists** (grep-verified). `migrations/006` defines `grade_outcomes` +
`player_calibrated_weights` and **no code reads or writes them**. The G-b/C-cal replay was