CRITICAL BUG FIX: Removed code that was appending asterisks to left-handed players' names and hash symbols to switch hitters' names in production. ## Changes ### Core Fix (retrosheet_data.py) - Removed name_suffix code from new_player_payload() (lines 1103-1108) - Players names now stored cleanly without visual indicators - Affected 20 left-handed batters in 2005 Live cardset ### New Utility Scripts - fix_player_names.py: PATCH player names to remove symbols (uses 'name' param) - check_player_names.py: Verify all players for asterisks/hashes - regenerate_lefty_cards.py: Update image URLs with cache-busting dates - upload_lefty_cards_to_s3.py: Fetch fresh cards and upload to S3 ### Documentation (CRITICAL - READ BEFORE WORKING WITH CARDS) - docs/LESSONS_LEARNED_ASTERISK_REGRESSION.md: Comprehensive guide * API parameter is 'name' NOT 'p_name' * Card generation caching requires timestamp cache-busting * S3 keys must not include query parameters * Player names only in 'players' table * Never append visual indicators to stored data - CLAUDE.md: Added critical warnings section at top ## Key Learnings 1. API param for player name is 'name', not 'p_name' 2. Cards are cached - use timestamp in ?d= parameter 3. S3 keys != S3 URLs (no query params in keys) 4. Fix data BEFORE generating/uploading cards 5. Visual indicators belong in UI, not database ## Impact - Fixed 20 player records in production - Regenerated and uploaded 20 clean cards to S3 - Documented to prevent future regressions 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
67 lines
2.1 KiB
Python
67 lines
2.1 KiB
Python
"""
|
|
Check all player names in cardset 27 for asterisks/hash symbols
|
|
"""
|
|
import asyncio
|
|
from db_calls import db_get
|
|
|
|
CARDSET_ID = 27
|
|
|
|
async def check_names():
|
|
print(f"Fetching all players from cardset {CARDSET_ID}...")
|
|
|
|
# Get all players from cardset
|
|
response = await db_get('players', params=[('cardset_id', CARDSET_ID), ('page_size', 500)])
|
|
|
|
if 'players' in response:
|
|
all_players = response['players']
|
|
elif 'results' in response:
|
|
all_players = response['results']
|
|
else:
|
|
print(f"Error: Unexpected response structure. Response keys: {response.keys()}")
|
|
return
|
|
|
|
print(f"Found {len(all_players)} players\n")
|
|
|
|
# Check for symbols
|
|
players_with_asterisk = []
|
|
players_with_hash = []
|
|
|
|
for player in all_players:
|
|
player_id = player['player_id']
|
|
name = player['p_name']
|
|
|
|
if '*' in name:
|
|
players_with_asterisk.append((player_id, name))
|
|
if '#' in name:
|
|
players_with_hash.append((player_id, name))
|
|
|
|
# Report findings
|
|
print(f"{'='*60}")
|
|
print(f"RESULTS")
|
|
print(f"{'='*60}")
|
|
|
|
if players_with_asterisk:
|
|
print(f"\n⚠️ Found {len(players_with_asterisk)} players with asterisks (*):")
|
|
for pid, name in players_with_asterisk[:20]: # Show first 20
|
|
print(f" Player {pid}: {name}")
|
|
if len(players_with_asterisk) > 20:
|
|
print(f" ... and {len(players_with_asterisk) - 20} more")
|
|
else:
|
|
print(f"\n✅ No players with asterisks (*) found")
|
|
|
|
if players_with_hash:
|
|
print(f"\n⚠️ Found {len(players_with_hash)} players with hash symbols (#):")
|
|
for pid, name in players_with_hash[:20]: # Show first 20
|
|
print(f" Player {pid}: {name}")
|
|
if len(players_with_hash) > 20:
|
|
print(f" ... and {len(players_with_hash) - 20} more")
|
|
else:
|
|
print(f"\n✅ No players with hash symbols (#) found")
|
|
|
|
print(f"\n{'='*60}")
|
|
print(f"Total clean players: {len(all_players) - len(players_with_asterisk) - len(players_with_hash)}/{len(all_players)}")
|
|
print(f"{'='*60}")
|
|
|
|
if __name__ == '__main__':
|
|
asyncio.run(check_names())
|