#!/usr/bin/env python3 """ Comprehensive validation script to check for negative values in batting cards. Checks all numeric fields that should never be negative. """ import asyncio from db_calls import db_get async def validate_batting_cards(cardset_id=27): """Check all batting cards for negative values in any field.""" print(f'Checking batting cards for cardset {cardset_id}...') print('=' * 70) # Get all batting cards for the cardset directly batting_cards_response = await db_get('battingcards', params=[('cardset', cardset_id)]) if not batting_cards_response: print(f'❌ No response from battingcards endpoint for cardset {cardset_id}') return False # Extract batting cards list - API returns 'cards' key batting_cards = batting_cards_response.get('cards', []) if not batting_cards: print(f'❌ No batting cards found for cardset {cardset_id}') return False print(f'Found {len(batting_cards)} batting cards in cardset') print() # Check all cards all_errors = [] cards_checked = 0 for card in batting_cards: cards_checked += 1 card_id = card.get('id', 'Unknown') # Extract player info player_info = card.get('player', {}) player_name = player_info.get('p_name', 'Unknown') player_id = player_info.get('player_id', 'Unknown') # Check all numeric fields for field, value in card.items(): # Skip non-numeric or None values if value is None or not isinstance(value, (int, float)): continue # Skip IDs and other fields that can be negative or are not relevant if field in ['id', 'player_id', 'cardset', 'variant']: continue # Check for negative values in fields that should be non-negative if value < 0: # Most baseball stats should be >= 0 all_errors.append({ 'card_id': card_id, 'player_name': player_name, 'player_id': player_id, 'field': field, 'value': value }) print(f'Checked {cards_checked} batting cards') print() if all_errors: print(f'❌ VALIDATION ERRORS FOUND: {len(all_errors)} negative values') print('=' * 70) # Group by player by_player = {} for error in all_errors: player_key = f"{error['player_id']} - {error['player_name']}" if player_key not in by_player: by_player[player_key] = [] by_player[player_key].append(error) print(f'\nAffected players: {len(by_player)}') print() for player_key, player_errors in sorted(by_player.items()): print(f"{player_key}:") for error in player_errors: print(f" - Card {error['card_id']}: {error['field']} = {error['value']}") print() print('=' * 70) print('🛑 DO NOT PROCEED WITH S3 UPLOAD') print('These negative values will cause gameplay crashes!') print() print('Next steps:') print('1. Identify root cause in card generation code') print('2. Fix the calculation bug') print('3. Re-run card generation (Step 2)') print('4. Re-run this validation') return False else: print('✅ No negative values found in any batting card fields') print('✅ DATABASE VALIDATION PASSED') print() print('Safe to proceed with S3 upload (Step 6)') return True if __name__ == '__main__': result = asyncio.run(validate_batting_cards(27)) exit(0 if result else 1)