Commit Graph

208 Commits

Author SHA1 Message Date
Cal Corum
a0d5d49724 fix: address review feedback (#52)
Guard bulk ID queries against empty lists to prevent PostgreSQL
syntax error (WHERE id IN ()) when batch POST endpoints receive
empty request bodies.

Affected endpoints:
- POST /api/v3/transactions
- POST /api/v3/results
- POST /api/v3/schedules
- POST /api/v3/battingstats

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-17 16:29:58 -05:00
Cal Corum
b0fd1d89ea fix: eliminate N+1 queries in batch POST endpoints (#25)
Replace per-row Team/Player lookups with bulk IN-list queries before
the validation loop in post_transactions, post_results, post_schedules,
and post_batstats. A 50-move batch now uses 2 queries instead of 150.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-17 16:29:58 -05:00
Cal Corum
5ac9cce7f0 fix: replace bare except: with except Exception: (#29)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-17 16:29:21 -05:00
Cal Corum
0e132e602f fix: remove unused imports in standings.py and pitchingstats.py (#30)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-17 16:28:25 -05:00
Cal Corum
d92bb263f1 fix: invalidate cache after PlayerService write operations (#32)
Add finally blocks to update_player, patch_player, create_players, and
delete_player in PlayerService to call invalidate_related_cache() using
the existing cache_patterns. Matches the pattern already used in
TeamService.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-17 16:28:07 -05:00
Cal Corum
9558da6ace fix: remove empty WEEK_NUMS dict from db_engine.py (#34)
Dead code - module-level constant defined but never referenced.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-17 16:28:07 -05:00
Cal Corum
6d1b0ac747 perf: push limit/offset to DB in PlayerService.get_players (#37)
Apply .offset() and .limit() on the Peewee query before materializing
results, instead of fetching all rows into memory and slicing in Python.
Total count is obtained via query.count() before pagination is applied.
In-memory (mock) queries continue to use Python-level slicing.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-17 16:28:07 -05:00
Cal Corum
a351010c3c fix: calculate lob_2outs and rbipercent in SeasonPitchingStats (#28)
Both fields were hardcoded to 0.0 in the INSERT. Added SQL expressions
to the pitching_stats CTE to calculate them from stratplay data, using
the same logic as the batting stats endpoint.

- lob_2outs: count of runners stranded when pitcher recorded the 3rd out
- rbipercent: RBI allowed (excluding HR) per runner opportunity

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-17 16:28:07 -05:00
cal
40a71c6f90 Merge pull request 'chore: pin all Python dependency versions in requirements.txt (#62)' (#63) from ai/major-domo-database-62 into main
All checks were successful
Build Docker Image / build (push) Successful in 1m8s
Reviewed-on: #63
2026-03-10 14:04:20 +00:00
Cal Corum
d076b7604c chore: pin all Python dependency versions in requirements.txt (#62)
All checks were successful
Build Docker Image / build (pull_request) Successful in 3m3s
- Pin all direct dependencies to exact versions captured from production
  via `docker exec sba_db_api pip freeze`
- Explicitly pin starlette==0.52.1 (root cause of 2026-03-09 outage)
- Move pytest/pytest-asyncio to new requirements-dev.txt

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-10 00:32:41 -05:00
cal
43a6ed1c74 Merge pull request 'fix: standardize all collection POST routes to use trailing slash' (#61) from fix/standardize-post-trailing-slashes into main
All checks were successful
Build Docker Image / build (push) Successful in 58s
Reviewed-on: #61
2026-03-10 00:41:19 +00:00
Cal Corum
9ec69f9f2c fix: standardize all collection POST routes to use trailing slash
All checks were successful
Build Docker Image / build (pull_request) Successful in 3m38s
aiohttp follows 307 redirects but converts POST to GET, silently
dropping the request body. Standardize all @router.post('') to
@router.post('/') so the canonical URL always has a trailing slash,
preventing 307 redirects when clients POST with trailing slashes.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 19:34:28 -05:00
cal
bc36970aeb Merge pull request 'fix: case-insensitive team_abbrev filter in transactions endpoint' (#60) from fix/transaction-team-filter-case-insensitive into main
All checks were successful
Build Docker Image / build (push) Successful in 54s
Reviewed-on: #60
2026-03-08 22:37:45 +00:00
Cal Corum
6af278d737 fix: case-insensitive team_abbrev filter in transactions endpoint
All checks were successful
Build Docker Image / build (pull_request) Successful in 2m7s
The team_abbrev filter uppercased input but compared against mixed-case
DB values (e.g. "MKEMiL"), causing affiliate roster transactions to be
silently dropped from results. Use fn.UPPER() on the DB column to match.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 17:35:12 -05:00
cal
ddf5f77da4 Merge pull request 'fix: raise HTTPException in recalculate_standings on failure (#23)' (#41) from ai/major-domo-database-23 into main
All checks were successful
Build Docker Image / build (push) Successful in 50s
Reviewed-on: #41
2026-03-03 03:47:29 +00:00
Cal Corum
4b288c1e67 fix: raise HTTPException in recalculate_standings on failure (#23)
All checks were successful
Build Docker Image / build (pull_request) Successful in 2m2s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-03 03:44:52 +00:00
cal
a0d27031b4 Merge pull request 'fix: assign order_by() return value in GET /api/v3/games (#24)' (#39) from ai/major-domo-database-24 into main
All checks were successful
Build Docker Image / build (push) Successful in 2m9s
Reviewed-on: #39
2026-03-03 01:29:27 +00:00
Cal Corum
8143913aa2 fix: assign order_by() return value in GET /api/v3/games (#24)
All checks were successful
Build Docker Image / build (pull_request) Successful in 4m41s
Peewee's order_by() returns a new queryset and does not sort in place.
Both branches were discarding the result, so the sort parameter had no
effect. Assign back to all_games so the query is actually ordered.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-02 19:03:21 -06:00
cal
a44aafc940 Merge pull request 'ci: Use shared composite actions from cal/gitea-actions' (#18) from ci/shared-actions into main
All checks were successful
Build Docker Image / build (push) Successful in 54s
Reviewed-on: #18
2026-02-18 19:47:54 +00:00
Cal Corum
4d1352ace8 ci: retrigger workflow after REQUIRE_SIGNIN_VIEW fix
All checks were successful
Build Docker Image / build (pull_request) Successful in 2m55s
2026-02-18 13:40:48 -06:00
Cal Corum
cc5e746247 Fix act_runner auth: short-form local actions + full GitHub URLs
Some checks failed
Build Docker Image / build (pull_request) Failing after 2m6s
DEFAULT_ACTIONS_URL=self requires local actions use short form
(cal/gitea-actions/...) so the runner passes its auth token, and
GitHub actions use full URLs (https://github.com/...) to bypass
local resolution.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 13:32:10 -06:00
Cal Corum
a1af8ea665 ci: trigger workflow re-run
Some checks failed
Build Docker Image / build (pull_request) Failing after 11s
2026-02-18 12:04:45 -06:00
Cal Corum
9e70c633bd ci: Use shared composite actions from cal/gitea-actions
Some checks failed
Build Docker Image / build (pull_request) Failing after 8s
Replace inline CalVer generation, Gitea tag creation, and Discord
notification steps with reusable composite actions. Standardizes
webhook secret name from DISCORD_WEBHOOK_URL to DISCORD_WEBHOOK.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 11:49:35 -06:00
cal
f9594a5c86 Merge pull request 'feat/stratplay-sbaplayer' (#17) from feat/stratplay-sbaplayer into main
All checks were successful
Build Docker Image / build (push) Successful in 56s
Reviewed-on: #17
2026-02-17 23:56:41 +00:00
Cal Corum
86f8495284 feat: Add group_by=sbaplayer to batting, pitching, and fielding endpoints
All checks were successful
Build Docker Image / build (pull_request) Successful in 2m32s
Enables career-total aggregation by real-world player identity (SbaPlayer)
across all seasons. JOINs StratPlay → Player to access Player.sbaplayer FK,
groups by that FK, and excludes players with null sbaplayer. Also refactors
stratplay router from single file into package and adds integration tests.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 17:42:14 -06:00
Cal Corum
90893aa774 feat: Add sbaplayer_id filter to /plays batting, pitching, and fielding endpoints
Enables cross-season stat queries by MLB player identity (SbaPlayer) without
requiring callers to look up every season-specific Player ID first. Filters
via Player subquery since StratPlay has no direct FK to SbaPlayer.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 17:42:14 -06:00
cal
345fa7a96d Merge pull request 'fix: Use Gitea API for tag creation instead of git push' (#16) from fix/ci-tag-creation into main
All checks were successful
Build Docker Image / build (push) Successful in 46s
Reviewed-on: #16
2026-02-17 23:41:47 +00:00
Cal Corum
67f14daf7f fix: Use Gitea API for tag creation instead of git push
All checks were successful
Build Docker Image / build (pull_request) Successful in 46s
git push --tags fails on protected main branch since the runner's
token lacks push permissions. Switch to Gitea REST API call which
bypasses branch protection. Also removes unnecessary VERSION file
commit since CalVer is derived from tags.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 17:40:36 -06:00
cal
eba6cb30c7 Merge pull request 'ci/calver' (#15) from ci/calver into main
Some checks failed
Build Docker Image / build (push) Failing after 56s
Reviewed-on: #15
2026-02-17 23:35:02 +00:00
Cal Corum
49911c53ac ci: Switch to CalVer (YYYY.MM.BUILD) with auto-generated versions
All checks were successful
Build Docker Image / build (pull_request) Successful in 2m23s
Remove manual semver validation from PR checks. Versions are now
auto-generated on merge to main by counting existing monthly tags.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 17:32:36 -06:00
Cal Corum
bcdde572e8 docs: Add subdirectory CLAUDE.md files for routers, stratplay, and services
Provide targeted context for each app subdirectory so Claude Code
understands local patterns without relying on the root CLAUDE.md.
Also simplifies root CLAUDE.md dev/prod environment sections.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 17:32:25 -06:00
Cal Corum
2eab484ffb chore: bump version to 2.7.0
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 17:31:43 -06:00
Cal Corum
d95af4ed90 Optimize CLAUDE.md from 116 to 37 lines
Remove boilerplate, directory tree listing, and discoverable architecture docs.
Keep commands, key patterns, env vars, and important gotchas.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 08:30:37 -06:00
cal
7434f69a59 Merge pull request 'fix: Replace fragile locals() pattern in PATCH endpoints' (#11) from fix/patch-endpoint-locals-bug into main
All checks were successful
Build Docker Image / build (push) Successful in 2m43s
Reviewed-on: #11
2026-02-12 15:37:10 +00:00
cal
113b76ec9a Merge pull request 'ci: switch Docker build cache to type=registry' (#12) from ci/registry-cache into main
All checks were successful
Build Docker Image / build (push) Successful in 3m54s
2026-02-11 22:14:21 +00:00
cal
16408a973e ci: switch Docker build cache from type=gha to type=registry
Some checks failed
Build Docker Image / build (pull_request) Failing after 19s
The gha cache backend silently fails on Gitea Actions due to Docker
networking issues between the Buildx builder container and the
act_runner cache server. Registry-based caching stores layers on
Docker Hub, which is more reliable for self-hosted runners.
2026-02-11 22:12:15 +00:00
cal
e257a96a8a Update VERSION
All checks were successful
Build Docker Image / build (pull_request) Successful in 3m16s
2026-02-11 21:55:34 +00:00
Cal Corum
31b14ec709 fix: Replace fragile locals() pattern in PATCH endpoints with explicit field dicts
Some checks failed
Build Docker Image / build (pull_request) Failing after 15s
The teams PATCH endpoint included the `data` variable itself when
building the update dict via locals(), causing Peewee to fail with
"type object 'Team' has no attribute 'data'". The players endpoint
had the same pattern with a workaround that was order-dependent.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 15:54:39 -06:00
cal
e7ec6c94ff Merge pull request 'fix/standings-streak-sort-order' (#10) from fix/standings-streak-sort-order into main
All checks were successful
Build Docker Image / build (push) Successful in 2m46s
Reviewed-on: #10
2026-02-10 21:05:40 +00:00
Cal Corum
126ce53951 fix: Sort games chronologically in standings recalculation for accurate streaks
Some checks failed
Build Docker Image / build (pull_request) Failing after 20s
The standings recalculate function was processing games in arbitrary database
order, causing win/loss streaks to be calculated incorrectly. Added explicit
ordering by week and game_num (ascending) to ensure games are processed
chronologically.

This fixes inconsistent streak values that were reported due to the streak
logic depending on processing games in the correct temporal sequence.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-10 14:44:58 -06:00
cal
8fb8f82433 Merge pull request 'Optimize player search endpoint for 30x performance improvement' (#9) from perf/optimize-player-search into main
All checks were successful
Build Docker Image / build (push) Successful in 52s
Reviewed-on: #9
2026-02-06 13:33:51 +00:00
Cal Corum
099286867a Optimize player search endpoint for 30x performance improvement
All checks were successful
Build Docker Image / build (pull_request) Successful in 2m13s
**Problem:**
The /players/search endpoint with all_seasons=True was taking 15+ seconds,
causing Discord autocomplete timeouts (3-second limit). The endpoint was
loading ALL players from ALL seasons into memory, then doing Python string
matching - extremely inefficient.

**Solution:**
1. Use SQL LIKE filtering at database level instead of Python iteration
2. Limit query results at database level (not after fetching all records)
3. Add functional index on LOWER(name) for faster case-insensitive search

**Performance Impact:**
- Before: 15+ seconds (loads 10,000+ player records)
- After: <500ms (database-level filtering with index)
- 30x faster response time

**Changes:**
- app/services/player_service.py: Use Peewee fn.Lower().contains() for SQL filtering
- migrations/2026-02-06_add_player_name_index.sql: Add index on LOWER(name)
- VERSION: Bump to 2.6.0 (minor version for performance improvement)

**Testing:**
Test with: https://sba.manticorum.com/api/v3/players/search?q=trea%20t&season=0&limit=30

Fixes Discord bot /player autocomplete timeout errors (error code 10062)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-06 07:25:49 -06:00
cal
8feed5b104 Merge pull request 'Set default sort on teams' (#7) from fix/team-default-sort into main
All checks were successful
Build Docker Image / build (push) Successful in 1m9s
Reviewed-on: #7
2026-02-06 03:00:47 +00:00
Cal Corum
7a538d7f12 Set default sort on teams
Some checks failed
Build Docker Image / build (pull_request) Failing after 19s
2026-02-05 20:59:50 -06:00
cal
70f1918484 Merge pull request 'fix: Respect short_output parameter in player search endpoint' (#6) from fix/player-search-respect-short-output into main
All checks were successful
Build Docker Image / build (push) Successful in 1m5s
Reviewed-on: #6
2026-02-06 02:11:21 +00:00
cal
1216bec287 Update VERSION
All checks were successful
Build Docker Image / build (pull_request) Successful in 3m2s
2026-02-06 02:08:02 +00:00
Cal Corum
39bc99b0dd fix: Respect short_output parameter in player search endpoint
Some checks failed
Build Docker Image / build (pull_request) Failing after 15s
The search_players() method was hardcoding short_output=True when
converting query results to dicts, ignoring the function parameter.
This caused the /api/v3/players/search endpoint to always return
team_id as an integer instead of nested team objects, even when
short_output=False was specified.

Impact:
- Discord bot's /injury clear command was crashing because
  player.team was None (only team_id was populated)
- Any code using search endpoint couldn't get full team data

Fix:
- Changed line 386 to use the short_output parameter value
- Now respects short_output parameter: False returns full team
  objects, True returns just team IDs

Root cause analysis from production logs:
- Error: AttributeError: 'NoneType' object has no attribute 'roster_type'
- Location: commands/injuries/management.py:647
- Cause: player.team was None after search_players() call

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-05 19:43:50 -06:00
cal
86dbe871a1 Merge pull request 'chore/cleanup-legacy-files' (#5) from chore/cleanup-legacy-files into main
All checks were successful
Build Docker Image / build (push) Successful in 1m9s
Reviewed-on: #5
2026-02-05 19:33:31 +00:00
Cal Corum
92e3517225 chore: Move documentation to .claude/
All checks were successful
Build Docker Image / build (pull_request) Successful in 7m1s
2026-02-05 13:14:09 -06:00
Cal Corum
927fbe96e3 Bump version 2026-02-05 13:12:55 -06:00