Version control Claude Code configuration including: - Global instructions (CLAUDE.md) - User settings (settings.json) - Custom agents (architect, designer, engineer, etc.) - Custom skills (create-skill templates and workflows) Excludes session data, secrets, cache, and temporary files per .gitignore. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
159 lines
5.2 KiB
Python
Executable File
159 lines
5.2 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""
|
|
Database Validation Script for Paper Dynasty Card Generation
|
|
|
|
Checks for common errors in card database before uploading:
|
|
- Negative groundball_b values (causes gameplay crashes)
|
|
- Invalid percentage ranges (>100 or <0)
|
|
- NULL values in required fields
|
|
|
|
Usage:
|
|
python validate_database.py <database_path>
|
|
"""
|
|
|
|
import sqlite3
|
|
import sys
|
|
from pathlib import Path
|
|
from typing import List, Tuple, Dict
|
|
|
|
|
|
class ValidationError:
|
|
def __init__(self, table: str, issue: str, count: int, examples: List[Dict]):
|
|
self.table = table
|
|
self.issue = issue
|
|
self.count = count
|
|
self.examples = examples
|
|
|
|
def __str__(self):
|
|
lines = [f"❌ {self.table}: {self.issue} ({self.count} records)"]
|
|
for example in self.examples[:5]: # Show max 5 examples
|
|
lines.append(f" - {example}")
|
|
if self.count > 5:
|
|
lines.append(f" ... and {self.count - 5} more")
|
|
return "\n".join(lines)
|
|
|
|
|
|
def validate_batting_cards(cursor: sqlite3.Cursor) -> List[ValidationError]:
|
|
"""Validate batting cards table"""
|
|
errors = []
|
|
|
|
# Check 1: Negative groundball_b values
|
|
cursor.execute("""
|
|
SELECT player_name, card_id, groundball_b, rarity
|
|
FROM batting_cards
|
|
WHERE groundball_b < 0
|
|
ORDER BY groundball_b ASC
|
|
LIMIT 10
|
|
""")
|
|
negative_gb = cursor.fetchall()
|
|
if negative_gb:
|
|
count = cursor.execute("SELECT COUNT(*) FROM batting_cards WHERE groundball_b < 0").fetchone()[0]
|
|
examples = [
|
|
f"{name} (ID: {card_id}, GB-B: {gb}, Rarity: {rarity})"
|
|
for name, card_id, gb, rarity in negative_gb
|
|
]
|
|
errors.append(ValidationError("batting_cards", "Negative groundball_b values", count, examples))
|
|
|
|
# Check 2: Invalid percentage ranges (0-100)
|
|
# Adjust column names based on actual schema
|
|
percentage_columns = ['strikeout', 'walk', 'homerun'] # Add more as needed
|
|
for col in percentage_columns:
|
|
try:
|
|
cursor.execute(f"""
|
|
SELECT player_name, card_id, {col}
|
|
FROM batting_cards
|
|
WHERE {col} < 0 OR {col} > 100
|
|
LIMIT 10
|
|
""")
|
|
invalid_pct = cursor.fetchall()
|
|
if invalid_pct:
|
|
count = cursor.execute(f"SELECT COUNT(*) FROM batting_cards WHERE {col} < 0 OR {col} > 100").fetchone()[0]
|
|
examples = [f"{name} (ID: {card_id}, {col}: {val})" for name, card_id, val in invalid_pct]
|
|
errors.append(ValidationError("batting_cards", f"Invalid {col} percentage", count, examples))
|
|
except sqlite3.OperationalError:
|
|
# Column might not exist - skip
|
|
pass
|
|
|
|
return errors
|
|
|
|
|
|
def validate_pitching_cards(cursor: sqlite3.Cursor) -> List[ValidationError]:
|
|
"""Validate pitching cards table"""
|
|
errors = []
|
|
|
|
# Check: Invalid percentage ranges
|
|
percentage_columns = ['strikeout', 'walk', 'homerun'] # Add more as needed
|
|
for col in percentage_columns:
|
|
try:
|
|
cursor.execute(f"""
|
|
SELECT player_name, card_id, {col}
|
|
FROM pitching_cards
|
|
WHERE {col} < 0 OR {col} > 100
|
|
LIMIT 10
|
|
""")
|
|
invalid_pct = cursor.fetchall()
|
|
if invalid_pct:
|
|
count = cursor.execute(f"SELECT COUNT(*) FROM pitching_cards WHERE {col} < 0 OR {col} > 100").fetchone()[0]
|
|
examples = [f"{name} (ID: {card_id}, {col}: {val})" for name, card_id, val in invalid_pct]
|
|
errors.append(ValidationError("pitching_cards", f"Invalid {col} percentage", count, examples))
|
|
except sqlite3.OperationalError:
|
|
# Column might not exist - skip
|
|
pass
|
|
|
|
return errors
|
|
|
|
|
|
def get_card_counts(cursor: sqlite3.Cursor) -> Dict[str, int]:
|
|
"""Get total card counts"""
|
|
batting_count = cursor.execute("SELECT COUNT(*) FROM batting_cards").fetchone()[0]
|
|
pitching_count = cursor.execute("SELECT COUNT(*) FROM pitching_cards").fetchone()[0]
|
|
return {"batting": batting_count, "pitching": pitching_count}
|
|
|
|
|
|
def main():
|
|
if len(sys.argv) != 2:
|
|
print("Usage: python validate_database.py <database_path>")
|
|
sys.exit(1)
|
|
|
|
db_path = Path(sys.argv[1])
|
|
if not db_path.exists():
|
|
print(f"❌ Database not found: {db_path}")
|
|
sys.exit(1)
|
|
|
|
print(f"🔍 Validating database: {db_path}")
|
|
print()
|
|
|
|
# Connect to database
|
|
conn = sqlite3.connect(db_path)
|
|
cursor = conn.cursor()
|
|
|
|
# Get card counts
|
|
counts = get_card_counts(cursor)
|
|
print(f"📊 Total Cards:")
|
|
print(f" - Batting: {counts['batting']}")
|
|
print(f" - Pitching: {counts['pitching']}")
|
|
print()
|
|
|
|
# Run validations
|
|
all_errors = []
|
|
all_errors.extend(validate_batting_cards(cursor))
|
|
all_errors.extend(validate_pitching_cards(cursor))
|
|
|
|
# Report results
|
|
if all_errors:
|
|
print("❌ VALIDATION FAILED")
|
|
print()
|
|
for error in all_errors:
|
|
print(error)
|
|
print()
|
|
print(f"Total issues: {len(all_errors)}")
|
|
sys.exit(1)
|
|
else:
|
|
print("✅ VALIDATION PASSED")
|
|
print("No errors found in database")
|
|
sys.exit(0)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|