Skip to content

Salvage v2 engine onto main + wire into Today page - #19

Merged
gmalbert merged 6 commits into
mainfrom
salvage/v2-core
Aug 15, 2026
Merged

Salvage v2 engine onto main + wire into Today page#19
gmalbert merged 6 commits into
mainfrom
salvage/v2-core

Conversation

@gmalbert

Copy link
Copy Markdown
Owner

Selectively ports the v2 data/model engine from the frontier-enhancements experiment onto main, then wires it into the legacy Today page game cards. No v2 pages or navigation changes.

Engine (salvage/v2-core):

  • Contracts, features, markets, backtesting, decisions, catalog, quality, monitoring, labels, normalization, pipelines (orchestrator + deterministic replay)
  • Manifest-backed training, model registry, calibration, baselines
  • Generative plate-appearance model + coherent game simulator (plate_appearance, game_simulator, prop_coherence, pa_outcome_model)
  • Real MLB Stats API ingestion (lineups, pitcher availability), raw store, content-addressed silver archive
  • Gold artifact publisher (deterministic, fail-closed)
  • Migrations, config contracts, CI workflow, 102 passing tests

Today page wiring:

  • One coherent score distribution per game drives moneyline, run line, and O/U (reconcile by construction)
  • Run rates fed from each team's real runs-scored/allowed per game
  • Fail-closed O/U: no fabricated edges when prices are missing
  • Fixed ESPN odds parsing (floats) and legacy page errors (secrets crash, pyarrow mixed-type, pandas FutureWarnings)

Verified: 102 tests pass, deterministic replay, live-feed screenshots show coherent card numbers.

gmalbert and others added 6 commits August 14, 2026 21:24
Selectively port the v2 data/model platform from the frontier-enhancements
branch onto main's base, deliberately excluding the v2 pages, the
st.navigation changes, and the product-surface work.

Brings over, from the v2 tip:
- src/contracts, src/features, src/markets, src/backtesting,
  src/decisions, src/catalog, src/quality, src/monitoring, src/labels,
  src/normalization, src/pipelines (orchestrator + deterministic replay),
  src/pick6, src/api, src/ui helpers
- Manifest-backed training, model registry, calibration, and baselines
- Generative plate-appearance model and coherent game simulator
  (plate_appearance, game_simulator, prop_coherence, pa_outcome_model)
- Ingestion lineups/pitcher-availability with real MLB Stats API shapes,
  raw store, and content-addressed silver archive
- Gold artifact publisher (deterministic, fail-closed) + run_gold_publish
- Migrations, config contracts, CI workflow, and 102 passing tests

Adds pyproject + uv.lock with statsmodels for the legacy pages' lowess
trendlines. Legacy pages/predictions/page_utils are untouched.

Co-authored-by: CommandCodeBot <noreply@commandcode.ai>
Ignore the v2 lakehouse artifacts (data/bronze, data/silver, data/gold)
and the uv cache (.tmp) so regenerated outputs never clutter git status.

Co-authored-by: CommandCodeBot <noreply@commandcode.ai>
First engine integration on the salvage branch: the home page's game cards
now derive run line and over/under from one coherent joint score
distribution anchored to the legacy team-strength moneyline, so all three
markets reconcile instead of using separate ad-hoc formulas.

- predictions.py: add _coherent_game_distribution(home_prob) which builds
  an independent-Poisson ScoreDistribution via bisection on the home/away
  run-rate ratio; run line uses dist.run_line_probabilities(-1.5) and O/U
  uses dist.total_probabilities(posted)
- Fail-closed O/U: missing or unparseable prices now mean no O/U
  recommendation instead of a fabricated 50/50 implied edge
- Fix ESPN odds parsing: totals odds arrive as floats (-106.0); _parse and
  _parse_american now coerce through float, so real O/U prices are read
  (previously every totals price failed to parse and showed unavailable)
- Update the game-card caption to describe the coherent-distribution method

Verified: 102 tests pass; live-feed screenshot shows Over 8.0 at -106 with
the engine's coherent probability, moneyline and run line unchanged.

Co-authored-by: CommandCodeBot <noreply@commandcode.ai>
Replace the W% logistic moneyline anchor with team-stats-driven run rates,
so the moneyline, run line, and totals all fall out of one coherent
distribution built from actual per-season runs scored/allowed.

- predictions.py: add _team_run_rate() blending a team's RS_per_G offense
  with the opponent's RA_per_G defense (geometric mean, regressed toward
  league average); _coherent_game_distribution() now takes the two team
  names and the standings, builds the Poisson distribution directly, and
  drops the bisection entirely
- The win-probability bar and moneyline now use dist.home_moneyline()
  instead of _estimate_win_prob; remove the now-dead W% logistic call
- Update the card caption to describe the team-stats method

Verified: 102 tests pass; live screenshot shows the Cardinals@Cubs card
flip from the W%-logistic 73/27 to a team-stats 53/47 with the run line
and over/under reconciling to the same distribution.

Co-authored-by: CommandCodeBot <noreply@commandcode.ai>
Three runtime errors surfaced when running the app in a browser:

- pages/1_Today.py: st.secrets.get() raised StreamlitSecretNotFoundError
  when no secrets.toml exists, crashing the Today page. Read ODDS_API_KEY
  from the environment only (.env feeds it via src.ingestion.config).
- page_utils.py: _fetch_pitcher_stats returned mixed str/int values, so the
  Stat/Value dataframe failed pyarrow serialization with ArrowTypeError.
  Coerce every value to str.
- page_utils.py: silence pandas FutureWarnings - add observed=False to
  groupby calls and include_groups=False to groupby.apply, so a future
  pandas version does not change behavior or break.

Verified: 102 tests pass; the game-context cache builds with
-W error::FutureWarning; the Today page renders with zero exceptions.

Co-authored-by: CommandCodeBot <noreply@commandcode.ai>
The v2 CI runs ruff format --check and ruff check over the whole tree, but
main's legacy pages, scripts, and page_utils were never ruff-conformant, so
the PR's CI failed on formatting.

- ruff format over src tests scripts predictions.py pages page_utils.py
- ruff check --fix: remove unused imports/variables, sort import blocks
- Restore the add_betting_oracle_footer re-export in page_utils (used by
  tests/test_runline_favorite.py) with a noqa so ruff keeps it
- Rename ambiguous single-letter variable l -> losses in _fetch_team_standings

Verified: ruff check + format clean across the tree, 102 tests pass, mypy
clean, deterministic replay passes, compileall clean.

Co-authored-by: CommandCodeBot <noreply@commandcode.ai>
@gmalbert
gmalbert merged commit c3291c6 into main Aug 15, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant