Skip to content

Add bulk player-season hitting ingestion #60

Description

@Mattsface

Summary

Add a season-wide player hitting ingestion workflow so player stats can be viewed from the local database without manually importing each player with import_player_season.py --player-id ....

The existing one-player importer should remain available as a targeted repair/debug tool.

Motivation

The current player data flow requires an explicit command per player before that player's hitting statistics are available locally. That does not scale to a usable Player UI.

For an MLB season with roughly 1,400+ cataloged players, the application needs a bulk ingestion path that can populate season hitting statistics efficiently and deterministically.

Proposed command

poetry run python scripts/import_player_hitting_season.py --season 2026

Proposed behavior

  1. Require or verify the player catalog for the requested season.
  2. Fetch season-wide MLB hitting statistics using the bulk stats endpoint exposed by python-mlb-statsapi.
  3. Paginate through the complete result set using the supported limit / offset parameters.
  4. Normalize bulk rows into the existing PlayerSeasonHitting domain model where possible.
  5. Upsert all valid season hitting rows into SQLite.
  6. Do not refetch player identity for every player; identity should come from the already-imported player catalog.
  7. Record enough ingestion/completeness state to distinguish a complete refresh from a partial or failed import.
  8. Print a concise summary of fetched, inserted, updated, unchanged, skipped, and failed rows.

Investigation required

Before implementation, perform a live audit of the bulk MLB stats response and document:

  • response pagination behavior and practical page size;
  • whether traded players return:
    • one full-season aggregate row,
    • team-specific splits,
    • or both;
  • how players with no usable hitting statistics are represented;
  • whether duplicate player-season rows can appear;
  • whether all rows contain the counting-stat fields required by PlayerSeasonHitting.

The importer should refuse ambiguous response shapes rather than silently choosing an arbitrary split.

Architecture constraints

  • Browser requests remain database-only.
  • MLB network access remains explicit ingestion work.
  • Reuse service-layer functions rather than putting baseball normalization logic in the CLI script.
  • Keep scripts/import_player_season.py as a targeted single-player import/repair command.
  • Bulk ingestion must be idempotent.
  • Missing or unavailable hitting data must not be silently converted to zero.

Acceptance criteria

  • Add a documented bulk player hitting ingestion design/audit.
  • Add scripts/import_player_hitting_season.py.
  • Support --season <year>.
  • Use season-wide bulk MLB stats retrieval rather than one network request per player.
  • Implement complete pagination.
  • Reuse existing catalog identity data rather than refetching identity per player.
  • Correctly handle traded-player aggregate/split behavior based on audited MLB response shape.
  • Skip or explicitly classify players with no hitting statistics.
  • Persist player hitting rows idempotently.
  • Persist/derive explicit completeness state for the season-wide hitting import.
  • Exit non-zero when the season-wide refresh cannot be considered complete.
  • Add offline deterministic tests for pagination, normalization, duplicates/ambiguity, partial failure, and reruns.
  • Update README/player documentation with the new preferred ingestion command.

Future integration

Once this exists, the season bootstrap workflow from #59 can incorporate it:

migrations
→ league/team data
→ player catalog
→ bulk player hitting

The intended developer experience becomes:

poetry run python scripts/bootstrap_season.py --season 2026
poetry run uvicorn app.main:app --reload

After bootstrap, selecting a hitter in the UI should not require any additional MLB API call or manual per-player import.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions