- agents: issue-worker.md and pr-reviewer.md updated for standard branch naming (issue/<number>-<slug> instead of ai/<repo>#<number>) - paper-dynasty: updated SKILL.md, generate_summary, smoke_test, validate_database scripts; added ecosystem_status.sh and plan/ - plugins: updated marketplace submodules and blocklist - sessions: rotate session files, add session-analysis/ - settings: updated settings.json Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
158 lines
4.8 KiB
Python
Executable File
158 lines
4.8 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""
|
|
Database Validation Script for Paper Dynasty Card Generation
|
|
|
|
Checks for common errors in card data via the API before deployment:
|
|
- Missing batting or pitching cards for a cardset
|
|
- Players with no corresponding card record
|
|
- Rarity distribution sanity check
|
|
|
|
Usage:
|
|
python validate_database.py [--cardset-id 24] [--env prod]
|
|
"""
|
|
|
|
import sys
|
|
import argparse
|
|
from pathlib import Path
|
|
from typing import List, Dict
|
|
|
|
sys.path.insert(0, str(Path(__file__).parent.parent))
|
|
from api_client import PaperDynastyAPI
|
|
|
|
|
|
class ValidationError:
|
|
def __init__(self, entity: str, issue: str, count: int, examples: List[str]):
|
|
self.entity = entity
|
|
self.issue = issue
|
|
self.count = count
|
|
self.examples = examples
|
|
|
|
def __str__(self):
|
|
lines = [f"❌ {self.entity}: {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 get_card_counts(api: PaperDynastyAPI, cardset_id: int) -> Dict[str, int]:
|
|
"""Get total card counts for the cardset from the API"""
|
|
batting = api.get("battingcards", params=[("cardset_id", cardset_id)])
|
|
pitching = api.get("pitchingcards", params=[("cardset_id", cardset_id)])
|
|
return {
|
|
"batting": batting.get("count", 0),
|
|
"pitching": pitching.get("count", 0),
|
|
}
|
|
|
|
|
|
def validate_card_counts(api: PaperDynastyAPI, cardset_id: int) -> List[ValidationError]:
|
|
"""Check that batting and pitching cards exist for the cardset"""
|
|
errors = []
|
|
counts = get_card_counts(api, cardset_id)
|
|
|
|
if counts["batting"] == 0:
|
|
errors.append(ValidationError(
|
|
"battingcards", f"No batting cards found for cardset {cardset_id}", 0, []
|
|
))
|
|
if counts["pitching"] == 0:
|
|
errors.append(ValidationError(
|
|
"pitchingcards", f"No pitching cards found for cardset {cardset_id}", 0, []
|
|
))
|
|
return errors
|
|
|
|
|
|
def validate_player_coverage(api: PaperDynastyAPI, cardset_id: int) -> List[ValidationError]:
|
|
"""Check that every player in the cardset has at least one card"""
|
|
errors = []
|
|
|
|
try:
|
|
players = api.list_players(cardset_id=cardset_id)
|
|
except Exception as e:
|
|
errors.append(ValidationError("players", f"Could not fetch players: {e}", 0, []))
|
|
return errors
|
|
|
|
if not players:
|
|
errors.append(ValidationError(
|
|
"players", f"No players found for cardset {cardset_id}", 0, []
|
|
))
|
|
return errors
|
|
|
|
batting_data = api.get("battingcards", params=[("cardset_id", cardset_id)])
|
|
pitching_data = api.get("pitchingcards", params=[("cardset_id", cardset_id)])
|
|
|
|
batting_player_ids = {
|
|
c["player"]["player_id"]
|
|
for c in batting_data.get("cards", [])
|
|
if c.get("player")
|
|
}
|
|
pitching_player_ids = {
|
|
c["player"]["player_id"]
|
|
for c in pitching_data.get("cards", [])
|
|
if c.get("player")
|
|
}
|
|
all_card_player_ids = batting_player_ids | pitching_player_ids
|
|
|
|
uncovered = [
|
|
p for p in players
|
|
if p["player_id"] not in all_card_player_ids
|
|
]
|
|
|
|
if uncovered:
|
|
examples = [
|
|
f"{p.get('p_name', 'Unknown')} (ID: {p['player_id']}, rarity: {p.get('rarity', {}).get('name', '?') if isinstance(p.get('rarity'), dict) else p.get('rarity', '?')})"
|
|
for p in uncovered
|
|
]
|
|
errors.append(ValidationError(
|
|
"players", "Players with no batting or pitching card", len(uncovered), examples
|
|
))
|
|
|
|
return errors
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(
|
|
description="Validate Paper Dynasty card data via the API"
|
|
)
|
|
parser.add_argument(
|
|
"--cardset-id", type=int, default=24,
|
|
help="Cardset ID to validate (default: 24, the live cardset)"
|
|
)
|
|
parser.add_argument(
|
|
"--env", choices=["prod", "dev"], default="prod",
|
|
help="API environment (default: prod)"
|
|
)
|
|
args = parser.parse_args()
|
|
|
|
api = PaperDynastyAPI(environment=args.env)
|
|
|
|
print(f"🔍 Validating cardset {args.cardset_id} ({args.env})")
|
|
print()
|
|
|
|
counts = get_card_counts(api, args.cardset_id)
|
|
print(f"📊 Total Cards:")
|
|
print(f" - Batting: {counts['batting']}")
|
|
print(f" - Pitching: {counts['pitching']}")
|
|
print()
|
|
|
|
all_errors = []
|
|
all_errors.extend(validate_card_counts(api, args.cardset_id))
|
|
all_errors.extend(validate_player_coverage(api, args.cardset_id))
|
|
|
|
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")
|
|
sys.exit(0)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|