Syntrex Claude Sonnet 4.6 commited on
Commit
b00ec4c
·
1 Parent(s): 573fe1e

Card Lab Game Summary: fix empty selectors via statcast coverage filter

Browse files

Root cause: game_outcomes contains 2026/recent games with no matching
rows in statcast_event_core (historical data ends at 2025). Game pk
lookups returned 0 rows silently, leaving multiselects empty.

- get_recent_completed_games_for_card_lab: restrict dropdown to games
whose game_pk exists in statcast_event_core (CAST bigint AS STRING
for safe text comparison against game_outcomes.game_pk text column)
- get_game_players_for_card_lab: surface exceptions via _error key in
result dict instead of swallowing silently
- Debug expander: show raw game_pk type, statcast row/pitcher/batter
counts for selected game, and any helper exception text

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

visualization/card_lab_page.py CHANGED
@@ -335,7 +335,8 @@ def render_card_lab(conn) -> None:
335
 
336
  elif card_type == "Game Summary":
337
  if selected_game_row:
338
- st.write(f"**game_pk:** {selected_game_row.get('game_pk')}")
 
339
  st.write(f"**Hitters found:** {len(game_players.get('hitters', []))}")
340
  st.write(f"**Pitchers found:** {len(game_players.get('pitchers', []))}")
341
  st.write("**First 10 hitters:**", [h['display_name'] for h in game_players.get('hitters', [])[:10]])
@@ -346,6 +347,27 @@ def render_card_lab(conn) -> None:
346
  st.write("Selected hitters:", [h['display_name'] for h in game_selected_hitters])
347
  if game_selected_pitchers:
348
  st.write("Selected pitchers:", [p['display_name'] for p in game_selected_pitchers])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
349
 
350
  fmt = st.radio("Format", ["PNG", "JPG"], horizontal=True, key="cl_fmt")
351
 
 
335
 
336
  elif card_type == "Game Summary":
337
  if selected_game_row:
338
+ raw_gp = selected_game_row.get("game_pk")
339
+ st.write(f"**game_pk raw value:** {raw_gp!r} (type: {type(raw_gp).__name__})")
340
  st.write(f"**Hitters found:** {len(game_players.get('hitters', []))}")
341
  st.write(f"**Pitchers found:** {len(game_players.get('pitchers', []))}")
342
  st.write("**First 10 hitters:**", [h['display_name'] for h in game_players.get('hitters', [])[:10]])
 
347
  st.write("Selected hitters:", [h['display_name'] for h in game_selected_hitters])
348
  if game_selected_pitchers:
349
  st.write("Selected pitchers:", [p['display_name'] for p in game_selected_pitchers])
350
+ if selected_game_row and selected_game_row.get("game_pk"):
351
+ try:
352
+ _gp = int(selected_game_row["game_pk"])
353
+ _cnt = conn.execute(
354
+ text("SELECT COUNT(*) FROM statcast_event_core WHERE game_pk = :gp"),
355
+ {"gp": _gp},
356
+ ).scalar()
357
+ _p_cnt = conn.execute(
358
+ text("SELECT COUNT(DISTINCT pitcher) FROM statcast_event_core WHERE game_pk = :gp"),
359
+ {"gp": _gp},
360
+ ).scalar()
361
+ _b_cnt = conn.execute(
362
+ text("SELECT COUNT(DISTINCT batter) FROM statcast_event_core WHERE game_pk = :gp"),
363
+ {"gp": _gp},
364
+ ).scalar()
365
+ st.write(f"**statcast rows for game_pk {_gp}:** {_cnt}")
366
+ st.write(f"**Distinct pitchers:** {_p_cnt} | **Distinct batters:** {_b_cnt}")
367
+ except Exception as _e:
368
+ st.write(f"**Statcast row count error:** {_e}")
369
+ if game_players.get("_error"):
370
+ st.write(f"**get_game_players error:** {game_players['_error']}")
371
 
372
  fmt = st.radio("Format", ["PNG", "JPG"], horizontal=True, key="cl_fmt")
373
 
visualization/cards/card_queries.py CHANGED
@@ -370,10 +370,16 @@ def get_recent_completed_games_for_card_lab(conn, limit: int = 25) -> pd.DataFra
370
  """Recent completed games from game_outcomes for the Game Summary card type."""
371
  try:
372
  sql = text("""
373
- SELECT game_pk, away_team, home_team, away_score, home_score, graded_at AS game_date
374
- FROM game_outcomes
375
- WHERE away_score IS NOT NULL AND home_score IS NOT NULL
376
- ORDER BY graded_at DESC
 
 
 
 
 
 
377
  LIMIT :limit
378
  """)
379
  df = pd.read_sql(sql, conn, params={"limit": limit})
@@ -434,7 +440,7 @@ def get_game_players_for_card_lab(
434
 
435
  Each entry: {"display_name": str, "player_id": int|None, "team": str}
436
  """
437
- result: dict[str, list[dict]] = {"pitchers": [], "hitters": []}
438
  try:
439
  pitcher_rows = conn.execute(
440
  text("""
@@ -488,4 +494,5 @@ def get_game_players_for_card_lab(
488
  )
489
  except Exception as exc:
490
  logger.warning("[game_players] failed game_pk=%s: %s", game_pk, exc)
 
491
  return result
 
370
  """Recent completed games from game_outcomes for the Game Summary card type."""
371
  try:
372
  sql = text("""
373
+ SELECT go.game_pk, go.away_team, go.home_team, go.away_score, go.home_score,
374
+ go.graded_at AS game_date
375
+ FROM game_outcomes go
376
+ WHERE go.away_score IS NOT NULL
377
+ AND go.home_score IS NOT NULL
378
+ AND go.game_pk IN (
379
+ SELECT DISTINCT CAST(ec.game_pk AS STRING)
380
+ FROM statcast_event_core ec
381
+ )
382
+ ORDER BY go.graded_at DESC
383
  LIMIT :limit
384
  """)
385
  df = pd.read_sql(sql, conn, params={"limit": limit})
 
440
 
441
  Each entry: {"display_name": str, "player_id": int|None, "team": str}
442
  """
443
+ result: dict[str, list[dict]] = {"pitchers": [], "hitters": [], "_error": None}
444
  try:
445
  pitcher_rows = conn.execute(
446
  text("""
 
494
  )
495
  except Exception as exc:
496
  logger.warning("[game_players] failed game_pk=%s: %s", game_pk, exc)
497
+ result["_error"] = str(exc)
498
  return result