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>
9.4 KiB
Paper Dynasty Card Troubleshooting Guide
Load this context only when debugging card issues
Use this guide when:
- Cards display incorrect data despite correct database values
- Switch hitter handedness shows wrong
- Positions appear incorrect on cards
- Rarity calculations seem off
- Images won't regenerate
Card Caching Issues
Symptom
Database has correct values but card images show old/incorrect data
Root Cause
The Paper Dynasty API caches generated card images by date parameter. Once generated for a specific date, the cached image is served even if database data changes.
Solution
Use a future date to force regeneration:
# Instead of today
/v2/players/{id}/battingcard?d=2025-11-11 # ❌ Returns cached image
# Use tomorrow or future date
/v2/players/{id}/battingcard?d=2025-11-12 # ✅ Forces fresh generation
Verification Steps
-
Check database value:
api.get('battingcards', params=[('player_id', 12785)]) # Verify 'hand' field is correct -
Test with tomorrow's date:
curl "https://pd.manticorum.com/api/v2/players/12785/battingcard?d=2025-11-12&html=true" # Check if handedness displays correctly -
If correct with new date → cache issue:
- Regenerate all affected cards with cache-bust date
- Upload to S3
- Update player.image URLs
-
If still wrong → code or database issue:
- Check card rendering code in
/mnt/NV2/Development/paper-dynasty/database/app/card_creation.py - Verify database field is being read correctly
- Check card rendering code in
Switch Hitter Handedness
Common Issues
Issue 1: Shows 'R' instead of 'S'
Cause: Cached card image from before handedness was corrected
Fix:
from workflows.card_utilities import regenerate_cards_for_players
switch_hitters = [12785, 12788, 12854, ...] # List of affected IDs
regenerate_cards_for_players(
player_ids=switch_hitters,
cardset_id=27,
cache_bust_date="2025-11-12", # Tomorrow
upload_to_s3=True,
update_player_records=True
)
Issue 2: Database has wrong handedness
Cause: Card creation code didn't detect switch hitter correctly
Check:
# Look at raw FanGraphs data
import pandas as pd
vrhp = pd.read_csv('data-input/2005 Live Cardset/vrhp-basic.csv')
vlhp = pd.read_csv('data-input/2005 Live Cardset/vlhp-basic.csv')
player = vrhp[vrhp['key_bbref'] == 'willibe02']
# Check if PA counts are similar vs both sides
Fix location: /mnt/NV2/Development/paper-dynasty/card-creation/batters/creation.py
- Look for handedness detection logic around PA vs L/R comparisons
Issue 3: Player name has "#" suffix
Symptom: Player shows as "Bernie Williams #" in database
Cause: CSV had duplicate player names, script added "#" to dedupe
Impact: May affect handedness detection if logic uses name parsing
Fix: Remove "#" suffix from player names in database
Position Assignment Problems
Symptom
Outfielders show as DH, or positions seem wrong on cards
Root Cause
Usually one of:
- Defense CSV files missing or malformed
- Column name mismatch in defense data
- Defensive calculation logic error
Diagnostic Steps
Step 1: Check cardpositions table
api = PaperDynastyAPI(environment='prod')
positions = api.get('cardpositions', params=[('player_id', 12854)])
# Should show LF, CF, RF for outfielders
# If all show DH → defensive ratings didn't calculate
Step 2: Verify defense CSV files exist
cd /mnt/NV2/Development/paper-dynasty/card-creation/data-input/2005\ Live\ Cardset/
ls defense_*.csv
# Should have: defense_c.csv, defense_1b.csv, defense_2b.csv,
# defense_3b.csv, defense_ss.csv, defense_lf.csv,
# defense_cf.csv, defense_rf.csv
Step 3: Check defense CSV column names
import pandas as pd
df = pd.read_csv('defense_cf.csv')
print(df.columns.tolist())
# Required columns:
# - key_bbref (player ID)
# - Inn_def (innings at position)
# - tz_runs_total (or bis_runs_total)
# - fielding_perc
# - For catchers: caught_stealing_perc
# - For others: PO (putouts)
Step 4: Check retrosheet_data.py logic
Look for column name checks around lines 889, 926, 947:
# WRONG - checks if column exists in batter row
if 'tz_runs_total' in row: # ❌
# CORRECT - checks if column exists in defense dataframe
if 'tz_runs_total' in pos_df.columns: # ✅
Common Fixes
Fix 1: Column name mismatch
# In retrosheet_data.py or similar
# Change from:
of_run_rating = 'tz_runs_outfield' # ❌ Column doesn't exist
# To:
of_run_rating = 'bis_runs_outfield' if 'bis_runs_outfield' in pos_df.columns else 'tz_runs_total'
Fix 2: Regenerate with correct defense files
- Fix defense CSV files
- Re-run
retrosheet_data.py - Verify positions with:
./scripts/check_positions.sh 27
Fix 3: Clear old cardpositions
The post_positions() function now DELETEs all existing cardpositions before posting new ones, preventing stale DH positions from persisting.
Rarity Calculation Issues
Symptom
Players have wrong rarity or show as Common when they should be higher
Root Cause
Usually one of:
- Missing ratings data (LEFT JOIN preserves players without ratings)
- OPS threshold mismatch between years
- Ratings DataFrame merge corrupted dictionary columns
Diagnostic Steps
Step 1: Check if player has ratings
api.get('battingcardratings', params=[('battingcard_id', 5977)])
# Should return 2 records (vs L and vs R)
Step 2: Check OPS calculation
# In card creation logs, look for:
# "WARNING: Player {id} has no ratings, assigning default"
# Players without ratings get:
# - Batters: Common rarity (5), OPS 0.612
# - Pitchers: Common rarity (5), OPS-against 0.702
Step 3: Verify year-specific thresholds
Check /mnt/NV2/Development/paper-dynasty/card-creation/rarity_thresholds.py:
# 2024 and earlier use different thresholds than 2025+
if SEASON <= 2024:
BATTER_THRESHOLDS = {6: 1.050, 5: 0.900, ...}
else:
BATTER_THRESHOLDS = {6: 1.000, 5: 0.850, ...}
Common Fixes
Fix 1: Regenerate ratings
If ratings are missing, re-run card creation to calculate them
Fix 2: Check DataFrame merge
In card creation code, when merging ratings:
# WRONG - merges entire DataFrame, corrupts dict columns
full_card_df = full_card_df.merge(ratings_df)
# CORRECT - merge only needed columns
full_card_df = full_card_df.merge(
ratings_df[['key_bbref', 'player_id', 'battingcard_id']]
)
Image Won't Generate
Symptom
API returns 404 or error when requesting card image
Possible Causes
Cause 1: No batting/pitching card record
# Check if card exists
api.get('battingcards', params=[('player_id', 12785)])
# Should have count > 0
Fix: Run card creation script to generate card records
Cause 2: Missing ratings
# Check ratings exist
api.get('battingcardratings', params=[('battingcard_id', 5977)])
# Should return 2 records (vs L and vs R)
Fix: Ratings are usually created during card generation. Re-run creation script.
Cause 3: Wrong card type
Using /battingcard for a pitcher or vice versa
Fix: Check player positions to determine card type
Cause 4: Variant doesn't exist
Most players have variant 0, but some may not
Fix: Try variant=0 explicitly: /battingcard?variant=0&d=2025-11-11
S3 Upload Failures
Symptom
Local card generated successfully but S3 upload fails
Diagnostic Steps
Step 1: Check AWS credentials
aws sts get-caller-identity
# Should show your AWS account info
Step 2: Test S3 access
aws s3 ls s3://paper-dynasty/cards/cardset-027/ --region us-east-1
# Should list existing cards
Step 3: Check IAM permissions
Required permissions:
s3:PutObjects3:GetObjects3:ListBucket
Common Fixes
Fix 1: Configure AWS credentials
aws configure
# Or set environment variables:
export AWS_ACCESS_KEY_ID=xxx
export AWS_SECRET_ACCESS_KEY=xxx
export AWS_DEFAULT_REGION=us-east-1
Fix 2: Wrong bucket/region
Verify:
- Bucket:
paper-dynasty - Region:
us-east-1
Fix 3: File permissions
Ensure local file is readable:
ls -la /tmp/switch_hitter_cards/player-12785-battingcard.png
chmod 644 /tmp/switch_hitter_cards/player-12785-battingcard.png
Verification Tools
Check Positions Script
cd /mnt/NV2/Development/paper-dynasty/card-creation
./scripts/check_positions.sh 27
# Flags issues like:
# - Too many DHs (should be <5 for full season)
# - Missing outfield positions
# - Mismatches between player.pos_X and cardpositions
Verify Switch Hitters
from workflows.card_utilities import verify_switch_hitters
results = verify_switch_hitters(cardset_id=27, environment='prod')
# Shows which switch hitters need card refresh
Check Rarity Distribution
cd /mnt/NV2/Development/paper-dynasty/card-creation
python analyze_cardset_rarity.py
# Shows player counts by rarity (should follow expected distribution)
When to Load This Guide
Load this troubleshooting context when:
- User reports cards showing incorrect data
- Debugging card generation failures
- Investigating position assignment issues
- Verifying switch hitter detection
- Troubleshooting S3 uploads
- User asks about card caching behavior
Otherwise, keep this context unloaded to save tokens.