claude-configs/skills/paper-dynasty/workflows/TROUBLESHOOTING.md
Cal Corum 8a1d15911f Initial commit: Claude Code configuration backup
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>
2026-02-03 16:34:21 -06:00

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

  1. Check database value:

    api.get('battingcards', params=[('player_id', 12785)])
    # Verify 'hand' field is correct
    
  2. 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
    
  3. If correct with new date → cache issue:

    • Regenerate all affected cards with cache-bust date
    • Upload to S3
    • Update player.image URLs
  4. 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

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:

  1. Defense CSV files missing or malformed
  2. Column name mismatch in defense data
  3. 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

  1. Fix defense CSV files
  2. Re-run retrosheet_data.py
  3. 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:

  1. Missing ratings data (LEFT JOIN preserves players without ratings)
  2. OPS threshold mismatch between years
  3. 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:PutObject
  • s3:GetObject
  • s3: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.