Closes#19
The conditional `0.0 if PLAYER_DESCRIPTION == 'Live' else 0.0` is dead
code: both branches evaluate to the same value. Simplified to a direct
assignment.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
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>
Closes#10
Replace `except Exception: pass` with `except KeyError: pass` so only
the expected missing-attribute case (`cell["data-append-csv"]` not
present) is silently skipped. Network errors, encoding issues, and
other unexpected exceptions will now propagate instead of being hidden.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Closes#24
Pins the two unpinned dependencies in requirements.txt:
- peewee (unversioned → 3.19.0)
- polars (unversioned → 1.36.1)
All other dependencies were already pinned with ==.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Closes#15
`any` (lowercase) refers to the builtin function, not `typing.Any`.
Added `Any` to the `typing` imports in both files and updated the
`cardset` parameter annotation accordingly.
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>