Closes#16
Deleted test_positions_df which called an async function synchronously
(returning a coroutine, not a DataFrame) and asserted True == True.
Zero coverage. Also removed the now-unused pd_positions_df import.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Switch hitters batting vs LHP hit right-handed (pull=lf, oppo=rf).
Switch hitters batting vs RHP hit left-handed (pull=rf, oppo=lf).
Copy-paste error had both pull_side branches returning the same value.
Closes#5
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The second `elif "DO*" in data_string` was dead code — the first always
matched, so `spaces -= 2` for the DO** variant was silently skipped.
Fix: check "DO**" first (spaces -= 2), then "DO*" (spaces -= 1).
Closes#6
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Closes#7
The fallback branch of create_pit_position() used `int(df_data["key_bbref"])`
which always raises ValueError for string IDs like 'verlaju01'. The exception
was silently swallowed, causing pitchers without defensive stats to receive no
position record at all.
Fix: use `int(float(df_data["player_id"]))` to match the pattern used in
create_pitching_card() on the same file.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Replace hardcoded PD API bearer token in db_calls.py with dotenv/env var
- Delete scripts/supabase_doodling.py (dead scratch file with hardcoded Supabase JWT)
- Add python-dotenv dependency and .env.example template
- Consolidate check_prod_missing_ratings.py to import AUTH_TOKEN from db_calls
- Hard fail if PD_API_TOKEN is missing to prevent silent auth failures
Fixes#2, Fixes#3
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Allow upload scripts to target a local API server instead of the remote
production server, enabling 32x+ concurrency for dramatically faster
full-cardset uploads (~30-45s vs ~2-3min for 800 cards).
- pd_cards/core/upload.py: add api_url param to upload_cards_to_s3(),
refresh_card_images(), and check_card_images()
- pd_cards/commands/upload.py: add --api-url CLI option to upload s3
- check_cards_and_upload.py: read PD_API_URL env var with prod fallback
- Update CLAUDE.md, CLI reference, and Phase 0 project plan docs
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
get_event_loop() is deprecated in Python 3.10+ when called inside
a running coroutine. get_running_loop() is the correct replacement.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Pickoffs were using min(pick_cap, hold_num) which let high pickoff counts
completely override bad CS%, giving 31% of pitchers a -3 hold rating.
Now pickoffs act as a 1-3 point bonus on top of the CS%-based rating.
Pitchers with no CS data default to +2 (capped at -1 with pickoff bonus)
instead of the old +9.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Documents current branch state, what's built, what's left,
known bugs, and decision points so the next session can pick
up without re-investigating.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The FullCard migration requires offense_col and player_id on each player's
DataFrame row. The retrosheet pipeline calculates ratings before posting,
so both fields were missing — causing silent card layout builder failures.
Adds a three-tier resolution: CSV cache → API bulk fetch → deterministic
hash fallback. Also includes player_id fallback in both calcs modules.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Fix duplicate elif branch in HR overflow cascade that prevented
single_one from receiving excess chances, and reorder single_two
secondary dispatch to check flyout full_name before groundout
short_name to prevent false 'B' matches on fly ball results.
Also add missing new_ratings.flyout_cf_b increment.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The extracted batting and pitching models used malformed SLG equations that double-counted and omitted outcomes, skewing slash lines. Align formulas with canonical weighting and add regression tests to prevent recurrence.
Co-Authored-By: Claude GPT-5.3-Codex <noreply@anthropic.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Move each ratings model class (and, for batters, the helper functions it
depends on) into a dedicated models.py so that calcs_*.py can import from
card_builder.py at module level without circular imports.
- batters/models.py: BattingCardRatingsModel + bp_singles, wh_singles,
one_singles, bp_homeruns, triples, two_doubles, hit_by_pitch, strikeouts,
flyout_a, flyout_bq, flyout_b, groundball_a, groundball_c
- pitchers/models.py: PitchingCardRatingsModel (no helper deps needed)
- batters/calcs_batter.py: imports model + build_batter_full_cards at top
- pitchers/calcs_pitcher.py: imports model + build_pitcher_full_cards at top
- batters/card_builder.py: imports from batters.models
- pitchers/card_builder.py: imports from pitchers.models
- tests/test_batter_calcs.py: import bp_singles, wh_singles from batters.models
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- card_layout.py: Port PlayResult, PLAY_RESULTS, EXACT_CHANCES, get_chances(),
CardResult, CardColumn, FullCard, FullBattingCard, FullPitchingCard from
database/app/card_creation.py. card_output() uses col_* key names.
get_chances() always returns Decimal to avoid float/Decimal type errors.
- batters/card_builder.py: Port get_batter_card_data() algorithm as
build_batter_full_cards(ratings_vl, ratings_vr, offense_col, player_id, hand).
assign_bchances() returns float tuples for compatibility with float-based
BattingCardRatingsModel fields.
- pitchers/card_builder.py: Port get_pitcher_card_data() algorithm as
build_pitcher_full_cards(). assign_pchances() returns float tuples.
Includes card.add_fatigue() at end of each card iteration.
- batters/calcs_batter.py: Integrate card builder in get_batter_ratings().
After computing raw ratings, call build_batter_full_cards() and merge
9 col_* rendered column fields into each ratings dict. Lazy import to
avoid circular dependency.
- pitchers/calcs_pitcher.py: Same integration for get_pitcher_ratings().
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
790 players (397 batters, 393 pitchers) processed from Retrosheet data
through 2005-08-15 with 0.728 season percentage. Includes updated scouting
reports, card deltas, and FanGraphs scrape script.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Documents proposed architecture for moving card-building logic upstream
to Python, including:
- Executive summary with problem statement and migration path
- CardBuilder sketch with contract system for pluggable placement strategies
- Support for different card "personalities" (Standard, Clutch, Power Heavy, etc.)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add `pd-cards scouting upload` command to upload scouting CSVs to database server via SCP
- Update CLAUDE.md with critical warning: scouting must always run for ALL cardsets
- Document full workflow: `pd-cards scouting all && pd-cards scouting upload`
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add FRANCHISE_NORMALIZE dict and helper function
- Update FRANCHISE_LIST to return city-agnostic values
- Update mlbteam_and_franchise() to normalize franchise
Ensures new cards use normalized franchise format for AI roster matching
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Regenerated scouting CSVs for all cardsets (6211 batters, 7070 pitchers)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add --create/-c flag to create new players directly from YAML profiles
- Skip MLBPlayer creation (not needed for custom players)
- Auto-populate required API fields (cost, rarity, mlbclub, etc.)
- Update YAML profile with player_id and card_id after creation
- Add Adm Ball Traits custom player profile
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add --last-week-ratio, --last-twoweeks-ratio, --last-month-ratio flags
- Auto-enable 0.2 recency bias for last 2 weeks on Live series after May 30
- Fix main() call to pass empty args list (legacy parameter required)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Migrated all major card creation workflows to pd-cards CLI:
live-series:
- update: Full FanGraphs/BBRef card generation with CLI options
- status: Show cardset status from database
retrosheet:
- process: Historical Retrosheet data processing
- arms: Generate outfield arm ratings from play-by-play
- validate: Check for position anomalies in cardsets
- defense: Fetch defensive stats from Baseball Reference
scouting:
- batters: Generate batting scouting reports
- pitchers: Generate pitching scouting reports
- all: Generate all reports at once
upload:
- s3: Upload card images to AWS S3
- check: Validate cards without uploading
- refresh: Re-generate and re-upload card images
Updated CLAUDE.md with comprehensive CLI documentation.
Legacy scripts remain available but CLI is now the primary interface.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>