# Late swap & max +EV playbook

CourtEdge R&D — **MLB now**, **NFL when season starts**. This doc is the source of truth for product build order.

---

## Two different problems

| Mode | When | Goal | CourtEdge today |
|------|------|------|-----------------|
| **Max +EV (betting)** | Pre-lock, all day | Highest `ev_per_100` on the board; book + line shopping | Strong — `/api/edges`, `/picks`, `select_daily_picks` |
| **Late swap (DFS)** | After lineups lock, before first game | Replace OUT / bad chalk with playable pivots under salary cap | **Not built** — labs optimize fantasy ROI, not swap engine |

Do not confuse them: a +EV prop is not always a good DK swap, and a good DFS pivot is not always the top EV bet.

---

## MLB — tomorrow’s most +EV plays (use tonight)

### 1. Board settings (members `/picks`)

For the **full +EV tail** (not the desk’s diversified five):

1. Open [Members desk](/picks.html) → **Live board**.
2. Sport: **MLB**.
3. Click **Max EV** (or set manually):
   - **Max +odds:** empty or `999` (default `280` hides long prices).
   - **Min win %:** `42–45` (default `48` trims thin model edges).
   - **Sort:** `ev_per_100` descending.
4. Confirm **book** and **line** at the book before bet — board is model vs sharp fair, not a guarantee.

### 2. CLI snapshot (owner)

```bash
cd ~/courtedge-deploy
# Requires SUPABASE_URL + SUPABASE_SERVICE_ROLE_KEY in env (same as Pages)
node scripts/top-ev-plays-today.mjs --sport mlb --limit 25
node scripts/top-ev-plays-today.mjs --sport mlb --tomorrow --min-ev 8
```

Output: ranked table + JSON under `data/ev-desk-latest.json` for quick share / Discord.

### 3. How we pick the “desk five” vs “max EV”

`select_daily_picks` (9 AM ET lock) intentionally **does not** take the top 5 by EV alone:

- Max 2 **game lines** (totals/spreads).
- Max 2 per **prop family** (e.g. not five K props).
- De-correlation across matchups.
- Longshot cap unless model prob is high.

**Max EV for you** = board sort + relaxed filters. **Desk five** = diversified public card.

### 4. Pre-lock “soft late swap” for MLB DFS (manual, today)

Until we ship a swap engine:

1. **Morning:** build MME pool in [MLB DK lab](/mlb-dk-lineup-lab.html) from fresh slate JSON.
2. **News window (T-90 → T-15):** `Reload slate` after scratches; check `Status` / OUT column.
3. **Re-run** GPP build or export CSV again — treat as “rebuild,” not DK late swap file.
4. Cross-check **edges** for games with lineup uncertainty (sitters often move totals K props).

Scripts: `docs/SLATE-OPS.md`, `docs/FTN-MLB-IMPORT.md`, `data/mlb-sp-overrides.json`.

---

## NFL — late swap techniques (build target: Aug 2026)

DraftKings **Classic** late swap: change players in locked lineups until each player’s game starts.

### Architecture we will ship

```
┌─────────────────┐     ┌──────────────────┐     ┌─────────────────────┐
│ Import DK CSV   │────▶│ Lock-time graph  │────▶│ Swap suggestions    │
│ (your entries)  │     │ per player/game  │     │ (salary + stack safe) │
└─────────────────┘     └──────────────────┘     └─────────────────────┘
         │                        │                         │
         │                        ▼                         ▼
         │               ┌──────────────────┐     ┌─────────────────────┐
         └──────────────▶│ News / inactive  │     │ Optional: +EV tie-in │
                         │ (ESPN / official)│     │ for showdown props  │
                         └──────────────────┘     └─────────────────────┘
```

### Swap decision rules (GPP)

1. **OUT / doubtful** → must swap before lock expires for that slot.
2. **Chalk bust risk** (wind, backup QB news) → swap to same-salary tier with higher ceiling projection.
3. **Preserve stacks** — prefer same-game swaps (QB+WR) unless breaking stack gains >X projected points.
4. **Leverage** — in large fields, swap off mega-chalk to sub-5% owned if projection within 10% and game env improved.
5. **Salary leftover** — upgrade one flex if news bumps a value play into lineup.

### NFL data we need

| Input | Source | Notes |
|-------|--------|------|
| Slate + salaries | DK export / FTN | `nfl-dk-slate.json` (new) |
| Projections | FTN + internal sim | Extend `nfl-game-sim` pattern from MLB |
| Inactives | ESPN scoreboard / official | 90-min refresh in swap window |
| Ownership | FTN / STOKASTIC paste | For leverage swaps |
| Vegas | `game_edges` | Totals/spreads for game environment |

### Product surfaces (phased)

| Phase | Deliverable |
|-------|-------------|
| **NFL-0** | `nfl-dk-lineup-lab.html` — classic builder, no swap |
| **NFL-1** | Import DK entries CSV → show lock countdown per player |
| **NFL-2** | Single-lineup “best swap” given OUT flag |
| **NFL-3** | MME batch: rank 150 lineups by swap urgency, export swap map |
| **NFL-4** | Showdown CPT late swap (different cap math — mirror PGA R2 CPT lab) |

---

## Bridging +EV → DFS (future)

Ideas to prototype after NFL-1:

- **Game environment flag:** if `game_total` OVER is top-5 EV and wind &lt; 10 mph → boost pass catchers in swap scorer.
- **Pitcher outs prop steam:** if published pick steams (`alert_pick_line_moves`) → downgrade opposing stack in DFS swap scorer.
- **Correlation guard:** never suggest swap that violates user’s “max 4 per team” rule.

---

## Ops checklist (daily)

| Time (ET) | Action |
|-----------|--------|
| 8:00 | `sync-mcp-live-edges` healthy; spot-check `/api/edges` |
| 9:00 | `select_daily_picks` lock; verify `/api/picks/today` |
| Pre-slate | `node scripts/top-ev-plays-today.mjs --sport mlb` |
| Post-games | `./scripts/grade-last-night.sh` |
| NFL season | Swap window cron + inactive poll every 15m Sun/Mon/Thu |

---

## Code map (build from here)

| Piece | Path |
|-------|------|
| Edges API | `functions/api/edges.js` |
| Daily five | `supabase/functions/select_daily_picks/index.ts` |
| MLB lab | `mlb-dk-lineup-lab.html`, `js/mlb-dk-build-engine.js` |
| Line-move alerts | `supabase/functions/alert_pick_line_moves/index.ts` |
| Top EV script | `scripts/top-ev-plays-today.mjs` |
| NFL roadmap | `docs/NFL-DFS-ROADMAP.md` |

---

## Open questions (decide before NFL-1)

1. Do members **upload DK CSV** in browser or paste into textarea?
2. Showdown-only swap vs Classic-only for v1?
3. Charge swap tool on **Advanced** tier only?

Document owner decisions at top of `docs/NFL-DFS-ROADMAP.md` when set.
