# M3 Phase 1 Ship Summary

Phase 1 is shipped as a schema-normalization layer across the six betting market families. The important outcome is not that every Palantir / Fangorn / Valinor lane is complete; it is that every daily market output now has a shared lane contract, honest coverage status fields, and dual-written source columns so the UI can migrate without breaking existing pages.

## Ladder Summary

| Step | Status | Primary artifact |
|---|---|---|
| Step 0: Model lane contract | Shipped | `docs/projections_m3_model_lane_contract.md` |
| Step 1: Home Runs | Shipped with all three lanes populated | `outputs/betting/home_run_edges/<date>/home_run_edges_<date>.json` |
| Step 2: Strikeouts | Shipped with Palantir production, Fangorn research lane, Valinor missing | `outputs/betting/strikeout_value_board/<date>/strikeout_value_board_<date>.json` |
| Step 3: Total Bases | Shipped with Palantir production, Fangorn selective over/under lane, Valinor missing | `outputs/betting/total_base_site_board/<date>/total_base_site_board_<date>.json` |
| Step 4: Hits | Shipped with Palantir production; Fangorn / Valinor honestly missing | `outputs/betting/hits_edges/<date>/hits_edges_<date>.json` |
| Step 5: Pitcher Outs | Shipped with Palantir production; Fangorn / Valinor honestly missing | `outputs/betting/pitcher_outs_edges/<date>/pitcher_outs_edges_<date>.json` |
| Step 6: Futures | Shipped with Palantir production; Fangorn / Valinor honestly missing | `data/derived/betting/futures_edges_<YYYYMMDD>.parquet` |
| Step 7: Verification | Shipped | This document |

## Commits Shipped

| Step | Commit | Description |
|---|---|---|
| 0 | `5275cce` | Model lane contract spec |
| 1 | `2160b73` | Home Runs lane contract |
| 2 | `82fca9a` | Strikeouts lane contract |
| 3 | `054f549` | Total Bases lane contract |
| 4 | `414b4b4` | Hits lane contract |
| 5 | `9e2b016` | Pitcher Outs lane contract |
| 6 | `b9a46ce` | Futures lane contract |
| 7 | current verification commit | Verification and ship summary |

## Coverage Matrix

| Model lane | Home Runs | Strikeouts | Total Bases | Hits | Pitcher Outs | Futures |
|---|---|---|---|---|---|---|
| Palantir | production | production | production | production | production | production |
| Fangorn | production | rebadged_research | rebadged_research | missing | missing | missing |
| Valinor | rebadged_research | missing | missing | missing | missing | missing |

This matrix is the real net result of Phase 1. HR is the only market where all three lanes are populated. Strikeouts and Total Bases have a research/selective Fangorn lane, but no Valinor lane. Hits, Pitcher Outs, and Futures are honestly Palantir-only today.

## Verification

Forced scheduler cycle:

- Command: `python scripts/ops/schedule.py --force --once`
- Cycle artifact: `outputs/ops/scheduler_cycle_20260428T104411.json`
- Result: cycle completed, health check returned non-zero because of carried operational failures listed below.

| Task | Status | Metric | Notes |
|---|---:|---:|---|
| `fetch_chadwick_register` | success | 539420 | Wrote `register_20260428.parquet` |
| `fetch_savant_leaderboards` | success | 3654 | Existing Savant ABS caveat remains carried debt |
| `fetch_futures_markets` | success | 332 | Wrote `futures_markets_20260428.parquet` |
| `run_season_projection_pipeline` | failed | 1208 | Environment failure: `ModuleNotFoundError: No module named 'mlflow'` |
| `build_futures_fair_price_gaps` | success | 332 | Wrote `futures_edges_20260428.parquet` |
| `update_scorecard` | success | 1634 | Wrote `scorecard_live.parquet` |
| `fetch_daily_odds_fanduel` | success | 543 | Daily odds pull succeeded |
| `fetch_strikeout_props_sportsgameodds` | success | 66 | No longer zero in the final forced cycle |
| `run_daily_sportsbook_ingestion` | success | 1936 | Sportsbook ingestion succeeded |
| `build_clv_foundation_snapshot` | success | 1135 | CLV foundation artifact written |
| `build_clv_history_summary` | success | 12 | CLV history artifact written |
| `build_clv_market_structure_report` | success | 5 | CLV structure artifact written |
| `run_home_run_daily_production` | success | 0 | Existing health threshold expects non-zero; task still produced current HR play artifact |
| `run_total_base_daily_production` | success | 165 | Current-day TB board produced |
| `run_strikeout_edge_refresh` | success | 20 | Current-day K board produced |
| `build_hits_board` | failed | 0 | Scheduler reached it, but no `2026-04-28` upstream hits projection artifact exists |
| `build_pitcher_outs_board` | failed | 0 | Scheduler reached it, but no `2026-04-28` upstream pitcher-outs projection artifact exists |
| `run_daily_mithrandir` | success | 0 | Health threshold flags `metric_below_min<1`; carried operational state |

The two newly wired tasks were reached by the scheduler. Their same-day failures are upstream-artifact availability issues, not lane-contract schema failures. Known-good artifact-date runs still validate and render: Hits on `2026-04-01`, Pitcher Outs on `2026-03-30`.

## Contract Column Verification

| Market | Artifact rows | Required missing | Old source missing | Coverage status | Lane count bad | Spread bad |
|---|---:|---|---|---|---:|---:|
| Home Runs | 315 | none | none | Palantir production; Fangorn production; Valinor rebadged_research | 0 | 0 |
| Strikeouts | 20 | none | none | Palantir production; Fangorn rebadged_research; Valinor missing | 0 | 0 |
| Total Bases | 165 | none | none | Palantir production; Fangorn rebadged_research; Valinor missing | 0 | 0 |
| Hits | 10 | none | none | Palantir production; Fangorn missing; Valinor missing | 0 | 0 |
| Pitcher Outs | 6 | none | none | Palantir production; Fangorn missing; Valinor missing | 0 | 0 |
| Futures | 332 | none | none | Palantir production; Fangorn missing; Valinor missing | 0 | 0 |

All six markets retain old source columns while also writing the new Palantir / Fangorn / Valinor lane families. `model_lane_count`, `model_spread`, and `model_agreement_label` reconcile cleanly against the non-null lane probabilities.

## HR Consensus Signal Preview

Home Runs are the proof-of-concept market for a future consensus surface because all three lanes are populated.

Agreement label distribution on `2026-04-28`:

| Agreement label | Rows |
|---|---:|
| mixed | 288 |
| aligned | 15 |
| disagreement | 12 |

Sample rows by label:

| Label | Player | Team | Pitcher | Palantir | Fangorn | Valinor | Spread |
|---|---|---:|---|---:|---:|---:|---:|
| aligned | Daniel Schneemann | CLE | Nick Martinez | 0.0905 | 0.0908 | 0.0682 | 0.0226 |
| mixed | Shohei Ohtani | LAD | Janson Junk | 0.1562 | 0.1721 | 0.1302 | 0.0419 |
| disagreement | Yoan Moncada | LAA | Davis Martin | 0.0725 | 0.1721 | 0.1292 | 0.0996 |

Top 5 aligned rows by average lane probability:

| Player | Team | Opp | Pitcher | Book | Palantir | Fangorn | Valinor | Spread | Average |
|---|---:|---:|---|---|---:|---:|---:|---:|---:|
| Daniel Schneemann | CLE | TB | Nick Martinez | DraftKings | 0.0905 | 0.0908 | 0.0682 | 0.0226 | 0.0832 |
| Daniel Schneemann | CLE | TB | Nick Martinez | FanDuel | 0.0905 | 0.0908 | 0.0682 | 0.0226 | 0.0832 |
| Daniel Schneemann | CLE | TB | Nick Martinez | BetMGM | 0.0905 | 0.0908 | 0.0682 | 0.0226 | 0.0832 |
| Luke Keaschall | MIN | SEA | Logan Gilbert | FanDuel | 0.0260 | 0.0281 | 0.0211 | 0.0070 | 0.0251 |
| Luke Keaschall | MIN | SEA | Logan Gilbert | BetMGM | 0.0260 | 0.0281 | 0.0211 | 0.0070 | 0.0251 |

Important read: the current aligned set is not necessarily a list of strong plays. It is a convergence signal. Phase 2 should combine alignment with price gap, market confidence, and minimum-probability rules before surfacing it as a fan-facing consensus board.

## Site Smoke Test

All tested `/betting/*` and `/models/*` GET routes returned 200 via Flask test client:

- `/betting`
- `/betting/custom-combo-analyzer`
- `/betting/fangorn`
- `/betting/futures`
- `/betting/hits`
- `/betting/hits/2026-04-01`
- `/betting/home-run-edges`
- `/betting/home-run-edges/2026-04-28`
- `/betting/home-run-edges/analytics`
- `/betting/home-run-edges/history`
- `/betting/home-run-hub`
- `/betting/home-run-plays`
- `/betting/market-watch`
- `/betting/pitcher-outs`
- `/betting/pitcher-outs/2026-03-30`
- `/betting/strikeout-edges`
- `/betting/strikeout-value-board`
- `/betting/strikeout-value-board/2026-04-28`
- `/betting/strikeouts`
- `/betting/strikeouts/2026-04-28`
- `/betting/total-base-value-board`
- `/betting/total-base-value-board/2026-04-28`
- `/betting/total-bases`
- `/betting/total-bases/2026-04-28`
- `/models`
- `/models/palantir`
- `/models/fangorn`
- `/models/fangorn/2026-04-28`
- `/models/valinor`

## Tests

Lane-contract tests:

```text
Ran 27 tests in 0.029s
OK
```

Command:

```powershell
python -m unittest tests.test_home_run_model_lane_contract tests.test_strikeout_model_lane_contract tests.test_total_base_model_lane_contract tests.test_hits_model_lane_contract tests.test_pitcher_outs_model_lane_contract tests.test_futures_model_lane_contract tests.test_futures_gap_engine
```

## Fixes Not In The Original Plan

- `build_hits_board` was wired into the scheduler after the audit showed it was production-page reachable but not scheduler-verified.
- `build_pitcher_outs_board` was wired into the scheduler for the same reason.
- `PyYAML` was added to `pyproject.toml` during Phase 1 support work.
- HR Valinor was standardized on `hr_prob_rf_safe_logistic_anchor`, because it is the safest challenger shape available: RF-safe signal with logistic anchoring, not a pure unstable RF fork.
- Hits, Pitcher Outs, and Futures were intentionally left with missing Fangorn / Valinor lanes because the available candidates were not genuinely different model epistemologies.

## Methodology Decisions

- Palantir remains the stable production lane across all six market families.
- Fangorn is not a synonym for "higher confidence Palantir." It must be nonlinear, selective, or structurally different. That stricter rule is why Hits and Pitcher Outs are missing rather than rebadged from confidence filters.
- Valinor is not a spare column for any alternate output. It should be calibration/refinement or challenger logic. HR has a defensible Valinor candidate; non-HR markets generally do not yet.
- Futures are Palantir-only because there is currently no alternate scenario simulator or challenger futures methodology.

## What Phase 1 Does Not Do

- No new model training.
- No UI migration to the new lane columns.
- No removal or renaming of old source columns.
- No promotion of research lanes to production.
- No guarantee that same-day Hits or Pitcher Outs artifacts exist until their upstream projection jobs are made date-current.

## Carried Debts And Phase 2 / Phase 3 Scope

- Schema is ready, but most non-HR markets only have Palantir populated honestly.
- The corrected three-lane vision is bigger than the original audit assumed. Because Palantir, Fangorn, and Valinor are independent epistemologies rather than selectivity tiers, Phase 3 likely requires 10+ real model builds.
- Add a Phase 1.5 methodology audit before UI-heavy Phase 2. Define what Fangorn and Valinor should be for Strikeouts, Total Bases, Hits, Pitcher Outs, and Futures before training or rebadging anything else.
- Phase 2 should ship a per-board model switcher and a new `/betting/consensus` surface that highlights aligned rows where multiple lanes converge.
- Fix the local environment dependency gap: `run_season_projection_pipeline` currently fails because `mlflow` is not installed in the active venv.
- Resolve same-day upstream artifact generation for Hits and Pitcher Outs, or schedule those boards against the latest available upstream projection date instead of blindly using today's date.
- Revisit `run_daily_mithrandir` and HR health thresholds. Both can succeed operationally while emitting a zero metric that fails the current health gate.
- Pre-existing dirty worktree remains unresolved from earlier visual/data work. Before Phase 2 starts, decide whether to commit, stash, or revert those unrelated changes. Do not let them bleed into the lane-contract migration.

## Honest Ship Read

Phase 1 did what it was supposed to do: it made the betting outputs legible as a model-lane system without pretending the missing models already exist. The next product win is not another rebadge pass. It is a UI pass that lets users understand Palantir / Fangorn / Valinor where they exist, plus a methodology pass that defines the real missing lanes before we train them.
