Commit Graph

84 Commits

Author SHA1 Message Date
Cal Corum
556a30c397 fix: re-fetch existing transactions on each validation
The TransactionBuilder cached pre-existing transactions on first load
and never refreshed them. This meant transactions submitted by other
sessions (or newly visible after API fixes) were invisible for the
lifetime of the builder session, causing incorrect roster projections.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 08:10:22 -05:00
cal
b6b997c15e Merge pull request 'fix: reuse persistent aiohttp.ClientSession in GiphyService (#26)' (#66) from ai/major-domo-v2-26 into next-release
Reviewed-on: #66
2026-03-07 03:31:02 +00:00
cal
f048a3c04b Merge pull request 'fix: update roster labels to use Minor League and Injured List (#59)' (#63) from ai/major-domo-v2-59 into next-release
Reviewed-on: #63
2026-03-07 03:26:15 +00:00
Cal Corum
e9dd318e5a perf: reuse persistent aiohttp.ClientSession in GiphyService (#26)
All checks were successful
Build Docker Image / build (pull_request) Successful in 1m5s
Both get_disappointment_gif and get_gif previously created a new
ClientSession per call. Replace with a lazily-initialised shared
session stored on the instance, eliminating per-call TCP handshake
and DNS overhead.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-05 01:32:52 -06:00
Cal Corum
346e36bfc6 fix: update roster labels to use Minor League and Injured List (#59)
All checks were successful
Build Docker Image / build (pull_request) Successful in 1m10s
- Add section headers (Active Roster, Minor League, Injured List) to the
  main summary embed in _create_roster_embeds so each roster section is
  clearly labeled for users
- Fix incorrect docstring in team_service.get_team_roster that had the
  shortil/longil mapping backwards

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-04 22:04:57 -06:00
Cal Corum
ffa0366441 refactor: invalidate roster cache after submission instead of force-refreshing
Simplify review found that force_refresh=True on every validate_transaction()
call caused redundant API fetches on every embed render and button press.

Instead, invalidate the roster cache after successful submit_transaction() so
the next operation fetches fresh data. This preserves the cache for normal
interaction flows while still preventing stale data after submissions.

Also adds type annotation for roster_svc DI parameter.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 21:06:00 +00:00
Cal Corum
c70669d474 fix: refresh roster data before validation to prevent stale cache
TransactionBuilder cached roster data indefinitely via _roster_loaded flag,
causing validation to use stale counts when builders persisted across multiple
/ilmove invocations. Now validate_transaction() always fetches fresh roster
data. Also adds dependency injection for roster_service to improve testability.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 21:06:00 +00:00
Cal Corum
858663cd27 refactor: move 42 unnecessary lazy imports to top-level across codebase
Codebase audit identified ~50 lazy imports. Moved 42 unnecessary ones to
top-level imports — only keeping those justified by circular imports,
init-order dependencies, or optional dependency guards. Updated test mock
patch targets where needed. See #57 for remaining DI candidates.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 13:35:23 -06:00
Cal Corum
aa27769ed6 fix: roster validation now includes org affiliate transactions (closes #49)
load_existing_transactions only queried for the base team abbreviation
(e.g. "POR"), missing trades involving MiL/IL affiliates ("PORMIL",
"PORIL"). This caused false "too many players" errors when a pending
trade would have cleared a roster spot.

- get_team_transactions now accepts Union[str, List[str]] for team_abbrev
- load_existing_transactions queries all org affiliates [BASE, BASEMiL, BASEIL]
- Added 5 tests covering the fix and backwards compatibility

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 10:45:21 -06:00
Cal Corum
d1a6b57ccd fix: scorebug stale data, win probability parsing, and read-failure tolerance (closes #39, #40)
All checks were successful
Build Docker Image / build (pull_request) Successful in 1m14s
#40: ScorecardTracker cached data in memory at startup — background task never
saw newly published scorecards. Fixed by reloading from disk on every read.

#39: Win percentage defaulted to 50% when unavailable, showing a misleading
50/50 bar. Now defaults to None with "unavailable" message in embed. Parsing
handles decimal (0.75), percentage string, and empty values. Also fixed
orientation bug where win% was always shown as home team's even when the
sheet reports the away team as the leader.

Additionally: live scorebug tracker now distinguishes between "all games
confirmed final" and "sheet read failures" — transient Google Sheets errors
no longer hide the live scores channel.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-20 14:14:23 -06:00
Cal Corum
9cd577cba1 fix: batch quick-wins — 4 issues resolved (closes #37, #27, #25, #38)
- #37: Fix stale comment in transaction_freeze.py referencing wrong moveid format
- #27: Change config.testing default from True to False (was masking prod behavior)
- #25: Replace deprecated asyncio.get_event_loop() with get_running_loop()
- #38: Replace naive datetime.now() with timezone-aware datetime.now(UTC) across
  7 source files and 4 test files to prevent subtle timezone bugs

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-20 11:48:16 -06:00
Cal Corum
f64fee8d2e fix: remove 226 unused imports across the codebase (closes #33)
Ran `ruff check --select F401 --fix` to auto-remove 221 unused imports,
manually removed 4 unused `import discord` from package __init__.py files,
and fixed test import for DISAPPOINTMENT_TIERS to reference canonical location.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-20 11:35:04 -06:00
Cal Corum
f4be20afb3 fix: address 7 security issues across the codebase
- Remove hardcoded Giphy API key from config.py, load from env var (#19)
- URL-encode query parameters in APIClient._add_params (#20)
- URL-encode Giphy search phrases before building request URLs (#21)
- Replace internal exception details with generic messages to users (#22)
- Replace all bare except: with except Exception: (#23)
- Guard interaction.guild access in has_player_role (#24)
- Replace MD5 with SHA-256 for command change detection hash (#32)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-20 09:54:53 -06:00
Cal Corum
f29cccd3ab fix: roster validation now includes pending trades and fixes sWAR field name
Some checks failed
Build Docker Image / build (pull_request) Failing after 15s
RosterValidation used total_wara instead of total_sWAR, causing /legal
to silently fail. Transaction embed and submit validation now pass
next_week to validate_transaction() so pending trades are included in
roster count projections. Moved lazy imports to top-level in
transaction_embed.py. Fixed dropadd integration test fixtures that
exceeded sWAR cap.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 22:57:06 -06:00
Cal Corum
1d08dc1755 Raise exception on spreadsheet errors instead of silently skipping
**Problem:**
The _is_spreadsheet_error() check was logging a warning and silently skipping
rows with formula errors (#REF!, #N/A, etc.). This could lead to incomplete
game data being submitted without the user knowing.

**Solution:**
Raise SheetsException immediately when spreadsheet errors are detected,
providing:
- Exact row number and field name
- Actual error value found in the cell
- Common error type explanations
- Clear action required to fix

**Impact:**
- Users get immediate feedback about spreadsheet errors
- No partial/incomplete data submitted to API
- Clear instructions on what needs to be fixed
- Better data integrity

**Example Error Message:**
```
 Spreadsheet Error Detected

**Location:** Row 7, Column 'pitcher_id'
**Value Found:** `#REF!`

This cell contains a formula error that must be fixed before submission.

**Action Required:** Fix cell pitcher_id in row 7 and resubmit.
```

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

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-06 07:54:33 -06:00
Cal Corum
92eb9055f1 fix: Validate and sanitize pitching decision data from Google Sheets
Some checks failed
Build Docker Image / build (pull_request) Failing after 19s
Added robust validation to handle spreadsheet errors and invalid data
when reading pitching decisions from scorecards.

Problem:
- POST /api/v3/decisions was failing with 422 errors
- Google Sheets cells containing "#N/A" were passed directly to API
- API correctly rejected invalid team_id values like "#N/A" string
- No validation of integer fields or required fields

Root Cause:
- sheets_service.py:read_pitching_decisions() read values without
  validation or type checking
- Spreadsheet formula errors (#N/A, #REF!, etc.) passed through
- Invalid data types not caught until API validation failed

Solution:
1. Added _is_spreadsheet_error() to detect formula errors
2. Added _sanitize_int_field() to validate and convert integers
3. Enhanced read_pitching_decisions() to:
   - Detect and skip rows with spreadsheet errors
   - Validate integer fields (pitcher_id, team_id, etc.)
   - Ensure required fields (pitcher_id, team_id) are present
   - Log warnings for invalid data with row numbers
   - Only return valid, sanitized decision data

Impact:
- Prevents 422 errors from bad spreadsheet data
- Provides clear warnings in logs when data is invalid
- Gracefully skips invalid rows instead of crashing
- Helps identify scorecard data entry errors

Testing:
- Handles #N/A, #REF!, #VALUE!, #DIV/0! and other errors
- Converts "123.0" strings to integers correctly
- Validates required fields before sending to API
- Logs row numbers for debugging bad data

Production logs showed:
  "Input should be a valid integer, unable to parse string as
   an integer", input: "#N/A" for team_id field

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-05 21:44:06 -06:00
Cal Corum
060287b7ca Fix API parameter name: use 'demotion_week' instead of 'dem_week'
The API expects 'demotion_week' as the query parameter name, not 'dem_week'.
Updated service to send correct parameter name and tests to verify.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2026-02-01 21:27:52 -06:00
Cal Corum
be3dbf1f8d Add dem_week parameter to player team updates
- Add optional dem_week parameter to PlayerService.update_player_team()
- Transaction freeze sets dem_week to current.week + 2
- /ilmove command sets dem_week to current.week
- Draft picks (manual and auto) set dem_week to current.week + 2
- Backwards compatible - admin commands don't set dem_week
- Add 4 unit tests for dem_week scenarios
- Enhanced logging shows dem_week values

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

Co-Authored-By: Claude <noreply@anthropic.com>
2026-02-01 21:12:06 -06:00
Cal Corum
b5365f01f9 Fix custom command delete permission check using wrong ID field
Changed from command.creator_id (database ID) to command.creator.discord_id
to properly compare against the deleter's Discord user ID.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-28 16:10:52 -06:00
Cal Corum
2881207ca4 Update CLAUDE.md docs for all-season player search feature
- Document new autocomplete behavior (deduplicated, all-season search)
- Add PlayerService.search_players() method signature with all_seasons parameter
- Update search logic flow documentation

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

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-23 14:36:03 -06:00
Cal Corum
bf079eab83 Add all-season player search with deduplicated autocomplete
- PlayerService.search_players() now supports all_seasons=True to search across all 13 seasons
- Autocomplete shows unique player names (most recent season's team) instead of duplicates
- Command defaults to most recent season when no season parameter specified
- Users can specify season parameter for historical data

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

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-23 14:23:16 -06:00
Cal Corum
ee434c98f1 Fix weekly freeze/thaw automation - API params not being sent
Root cause: league_service.update_current_state() was calling self.patch()
without use_query_params=True. The API expected query params but received
JSON body, so database updates for week/freeze silently failed.

Changes:
- Add use_query_params=True to league_service.py:99
- Fix service layer violation in transaction_freeze.py - now uses
  player_service.update_player_team() instead of direct API client
- Bump version to 2.25.8

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-13 14:00:54 -06:00
Cal Corum
889b3a4e2d Fix sWAR cap validation for /ilmove and /dropadd commands
- Add sWAR cap validation to TransactionBuilder.validate_transaction()
- Use team-specific salary_cap from Team.salary_cap field
- Fall back to config.swar_cap_limit (32.0) if team has no custom cap
- Add major_league_swar_cap field to RosterValidationResult
- Update major_league_swar_status to show / with cap limit
- Add 4 new tests for sWAR cap validation

This fixes a bug where IL moves could put a team over their sWAR cap
because the validation only checked roster counts, not sWAR limits.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-06 13:17:05 -06:00
Cal Corum
37bf797254 Fix critical week rollover bugs causing 60x freeze message spam
Three bugs identified and fixed:

1. Deduplication logic tracked wrong week (transaction_freeze.py:216-219)
   - Saved freeze_from_week BEFORE _begin_freeze() modifies current.week
   - Prevents re-execution when API returns stale data

2. _run_transactions() bypassed service layer (transaction_freeze.py:350-394)
   - Added get_regular_transactions_by_week() to transaction_service.py
   - Now properly filters frozen=false and cancelled=false
   - Uses Transaction model objects instead of raw dict access

3. CRITICAL: Hardcoded current_id=1 (league_service.py:88-106)
   - Current table has one row PER SEASON, not a single row
   - Was patching Season 3 (id=1) instead of Season 13 (id=11)
   - Now fetches actual current state ID before patching

Root cause: The hardcoded ID caused every PATCH to update the wrong
season's record, so freeze was never actually set to True on the
current season. This caused the dedup check to pass 60 times (once
per minute during hour 0).

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-22 14:15:26 -06:00
Cal Corum
a942475950 Fix pending transaction check to use week_start parameter
The API was returning keepers transactions (week=0) when querying for
week 2 transactions. Changed from 'week' to 'week_start' parameter to
properly filter out earlier weeks.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-21 22:03:19 -06:00
Cal Corum
3cbc904478 Add pending transaction validation for /dropadd command
Prevents players who are already claimed in another team's pending
transaction (frozen=false, cancelled=false) from being added to a new
transaction for the same week.

Changes:
- Add is_player_in_pending_transaction() to TransactionService
- Make TransactionBuilder.add_move() async with validation
- Add check_pending_transactions flag (default True for /dropadd)
- Skip validation for /ilmove and trades (check_pending_transactions=False)
- Add tests/conftest.py for proper test isolation
- Add 4 new tests for pending transaction validation

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-21 17:13:43 -06:00
Cal Corum
62541ac750 Add injury log posting and fix view interaction permissions
Features:
- Post injury announcements to #sba-network-news when injuries are logged
- Update #injury-log channel with two embeds:
  - All injuries grouped by Major League team with return dates
  - All injuries grouped by return week, sorted ascending
- Auto-purge old messages before posting updated injury log

Bug Fixes:
- Fix BaseView interaction_check logic that incorrectly rejected command users
  - Old: Rejected if (not user_id match) OR (not in responders)
  - New: Allow if (user_id match) OR (in responders)
- Filter None values from responders list (handles missing gmid2)

Changes:
- services/injury_service.py: Add get_all_active_injuries_raw() method
- utils/injury_log.py: New utility for injury channel posting
- views/modals.py: Call injury posting after successful injury logging
- views/base.py: Fix interaction authorization logic
- config.py: Update to Season 13 Players role

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-19 00:08:11 -06:00
Cal Corum
1af7c82353 Fix off-by-one error in draft recent picks display
The get_recent_picks service method was subtracting 1 from overall_end,
but callers were already passing currentpick - 1. This caused the "Last 5
picks" list on the OnTheClock embed to skip the most recently completed
pick (showing picks 2-6 before current instead of 1-5).

Removed the extra subtraction in the service method since callers already
handle the exclusivity of the overall_end parameter.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-12 19:14:53 -06:00
Cal Corum
e3122fa23a Fix sWAR display precision and draft team role pings
- Change sWAR formatting from 1 decimal to 2 decimal places across all displays
- Draft on-clock announcements now ping team role (via team.lname) instead of GM

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-12 18:41:46 -06:00
Cal Corum
a814aadd61 Optimize draft sheet batch writes to single API call
- Changed write_picks_batch() from 105 individual API calls to 1 batch call
- Builds 2D array covering full pick range and writes in single update_values()
- Eliminates Google Sheets 429 rate limiting during resync operations
- Reduces resync time from ~2 minutes to seconds

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-12 15:01:48 -06:00
Cal Corum
ff62529ee3 Add draft pause/resume functionality
- Add paused field to DraftData model
- Add pause_draft() and resume_draft() methods to DraftService
- Add /draft-admin pause and /draft-admin resume commands
- Block picks in /draft command when draft is paused
- Skip auto-draft in draft_monitor when draft is paused
- Update status embeds to show paused state
- Add comprehensive tests for pause/resume

When paused:
- Timer is stopped (set to False)
- Deadline is set far in future
- All /draft picks are blocked
- Auto-draft monitor skips processing

When resumed:
- Timer is restarted with fresh deadline
- Picks are allowed again

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-11 19:58:37 -06:00
Cal Corum
9093055bb5 Add Google Sheets integration for draft pick tracking
- Add DraftSheetService with write_pick(), write_picks_batch(),
  clear_picks_range(), and get_sheet_url() methods
- Integrate sheet writes in /draft command (fire-and-forget pattern)
- Integrate sheet writes in draft_monitor.py for auto-draft picks
- Add /draft-admin resync-sheet command for bulk recovery
- Add sheet link to /draft-status embed
- Add draft_sheet_keys config with env var overrides per season
- Add get_picks_with_players() to draft_pick_service for resync
- Add 13 unit tests for DraftSheetService (all passing)
- Update CLAUDE.md documentation files

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-11 11:18:27 -06:00
Cal Corum
8f486a8424 Add skipped pick support to /draft command
Teams can now make up missed draft picks when not on the clock:
- Added get_skipped_picks_for_team() to draft_pick_service
- /draft checks for skipped picks when user isn't on the clock
- Uses earliest (lowest overall) skipped pick first
- Shows footer noting "Making up skipped pick" on success
- Does NOT advance draft when using skipped pick
- Fixed duplicate embed when command run in ping channel

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-10 23:16:10 -06:00
Cal Corum
ada4feef3e Add draft monitor auto-start and on-clock announcement embed
- Start draft monitor when timer enabled via /draft-admin timer
- Auto-start monitor when /draft-admin set-pick is used with active timer
- Add _ensure_monitor_running() helper for consistent monitor management
- Create on-clock announcement embed with:
  - Team name, pick info, and deadline
  - Team sWAR and cap space
  - Last 5 picks
  - Top 5 roster players by sWAR
- Implement smart polling intervals:
  - 30s when >60s remaining
  - 15s when 30-60s remaining
  - 5s when <30s remaining
- Add get_top_free_agents() to player service
- Fix DraftAdminGroup to accept bot parameter

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-10 23:04:39 -06:00
Cal Corum
483f1f492f Fix draft pick API parsing and enhance admin command feedback
Root Cause Fixes:
- Add _extract_items_and_count_from_response() override to DraftPickService
  to handle API returning 'picks' key instead of 'draftpicks'
- Add custom from_api_data() to DraftPick model to handle API field mapping
  (origowner/owner/player -> origowner_id/owner_id/player_id)

Enhancements:
- Add timer status to /draft-admin set-pick success message
  - Shows relative deadline timestamp when timer active
  - Shows "Timer Inactive" when timer not running

Also includes related draft module improvements from prior work.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-10 15:33:52 -06:00
Cal Corum
5a5da37c9c Add comprehensive draft services test suite and API fixes (v2.23.0)
- Fix DraftPickService to send full model body on PATCH (API requirement)
- Fix DraftListService to use client-side sorting (API doesn't support sort param)
- Fix parameter names: round_start/end -> pick_round_start/end
- Add 53 tests covering DraftService, DraftPickService, DraftListService
- Add draft model tests for DraftData, DraftPick, DraftList
- Add OpenAPI spec URL to CLAUDE.md for API reference

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-09 15:11:51 -06:00
Cal Corum
b8b55e90a3 Add trade acceptance workflow with transaction logging (v2.22.0)
- Add multi-team trade acceptance system requiring all GMs to approve
- TradeBuilder tracks accepted_teams with accept_trade/reject_trade methods
- TradeAcceptanceView with Accept/Reject buttons validates GM permissions
- Create transactions when all teams accept (frozen=false for immediate effect)
- Add post_trade_to_log() for rich trade embeds in #transaction-log
- Trade embeds show grouped player moves by receiving team with sWAR
- Add 10 comprehensive tests for acceptance tracking methods
- All 36 trade builder tests pass

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-04 13:46:10 -06:00
Cal Corum
55c56bee76 Add configurable roster limits with offseason support
- Add expand_mil_week config (default: 15) for MiL expansion timing
- Add early/late ML and MiL roster limits as config items
- Add offseason roster limits (69/69) for relaxed roster building
- Fix free_agent_team_id to correct value (547)
- Transaction builder now uses config values instead of hard-coded limits

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-04 11:06:36 -06:00
Cal Corum
9aba3074c6 Add multi-GM trade access via dual-key indexing
Previously, only the trade initiator could access the trade builder
because lookups used their Discord user ID. Now any GM whose team
participates in a trade can add players, view, and manage the trade.

Changes:
- Add _team_to_trade_key secondary index mapping team IDs to trade keys
- Add get_trade_builder_by_team() for team-based lookups
- Add clear_trade_builder_by_team() for team-based clearing
- Update add_team/remove_team to maintain secondary index
- Refactor 5 trade commands to use team-based lookups
- Add 9 new tests for multi-GM access functionality

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-04 10:36:48 -06:00
Cal Corum
1d6fef51ab Consolidate season config variables to single source (v2.21.0)
Remove redundant sba_current_season and pd_current_season config values.
All code now uses sba_season and pd_season, which properly read from
environment variables. Fixes /team command defaulting to Season 12.

- Remove duplicate *_current_season constants from config.py
- Update 100+ references across commands, services, and utils
- sba_season defaults to 13, pd_season defaults to 10
- Environment variables SBA_SEASON/PD_SEASON now work correctly

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-02 16:12:16 -06:00
Cal Corum
5133dc3d0f Add /branding command for team color/logo management (v2.20.0)
Implemented comprehensive team branding management system allowing team owners
to update colors and logos for major league, minor league, and dice rolls.

Features:
- Modal-based interactive form input with validation
- Hex color validation with normalization (6 chars, optional # prefix)
- Image URL accessibility testing with aiohttp (5 second timeout)
- Preview + confirmation workflow with ConfirmationView
- Support for both major league and minor league affiliate updates
- Dice color customization for game rolls
- Discord role color sync (non-blocking with graceful fallback)
- Comprehensive error handling and user feedback

Technical Implementation:
- BrandingModal class with 5 optional fields
- Concurrent URL validation using asyncio.gather
- Fixed team_service.update_team() to use PATCH with query parameters
- Enhanced TeamService documentation with correct method signatures
- 33 comprehensive tests (100% passing)

Bug Fixes:
- Fixed modal send timing (immediate response vs deferred)
- Fixed interaction handling for cancel button
- Fixed database API communication (PATCH query params vs PUT JSON)

Files:
- commands/teams/branding.py (NEW - ~500 lines)
- commands/teams/__init__.py (added BrandingCommands registration)
- commands/teams/CLAUDE.md (added comprehensive documentation)
- tests/test_commands_teams_branding.py (NEW - 33 tests)
- services/team_service.py (fixed update_team to use query params)
- VERSION (2.19.2 → 2.20.0)

Docker: manticorum67/major-domo-discord-app-v2:2.20.0

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-25 10:39:52 -06:00
Cal Corum
570f2e5e5a Fix /cc-create endpoint path mismatch (v2.19.2)
Corrected API endpoint paths from 'custom_command_creators' to 'custom_commands/creators' to match the database API routing structure.

**Issue**: Users unable to create custom commands due to 404 errors
**Root Cause**: Bot calling /api/v3/custom_command_creators instead of /api/v3/custom_commands/creators
**Solution**: Updated 5 endpoint references in custom_commands_service.py

Fixes:
- Line 547: create_item_in_table() call
- Lines 732, 748: client.put() calls for creator updates
- Lines 762, 768: get_items_from_table_with_params() calls for creator queries

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-24 21:20:28 -06:00
Cal Corum
0c001b6dab Fix @requires_team decorator API error handling
The @requires_team() decorator was incorrectly treating API errors as "no team"
because get_user_team() was catching all exceptions and returning None.

Changes:
1. get_user_team() now propagates exceptions instead of catching them
   - Allows callers to distinguish between "no team found" vs "API error"
   - Updated docstring to document the exception behavior

2. @requires_team() decorator now has try-except block
   - Returns specific error for "no team" (None result)
   - Returns helpful error for API/network issues (exception caught)
   - Logs exceptions for debugging

3. league_admin_only() decorator enhanced
   - Now supports both slash commands (Interaction) and prefix commands (Context)
   - Unified error handling for both command types

4. team_service.py and related updates
   - Team model field name corrected: team_abbrev -> abbrev

This fixes the regression where /cc-create was failing with "no team" error
when it should have been showing an API error message or working correctly.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-14 09:31:14 -06:00
Cal Corum
69ab4f60c3 CLAUDE: Use DELETE endpoint for clearing draft list
The API now has a DELETE /draftlist/team/{team_id} endpoint
that properly clears a team's draft list.

Updated clear_list() to use the new endpoint instead of trying
to POST an empty list, which was failing with "list index out of range"
error because the API expected at least one entry to determine team_id.

This resolves the "Clear Failed" error when using /draft-list-clear.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-25 19:50:30 -05:00
Cal Corum
5f69d495ab CLAUDE: Fix draft list operations and improve add success display
Multiple fixes for draft list functionality:

1. **Model Fix (draft_list.py):**
   - API returns nested Team and Player objects, not just IDs
   - Changed team_id/player_id from fields to @property methods
   - Extract IDs from nested objects via properties
   - Fixes Pydantic validation errors on GET operations

2. **Service Fix (draft_list_service.py):**
   - Override _extract_items_and_count_from_response() for API quirk
   - GET returns items under 'picks' key (not 'draftlist')
   - Changed add_to_list() return type from single entry to full list
   - Return verification list instead of trying to create new DraftList
   - Fixes "Failed to add" error from validation issues

3. **Command Enhancement (list.py):**
   - Display full draft list on successful add (not just confirmation)
   - Show position where player was added
   - Reuse existing create_draft_list_embed() for consistency
   - Better UX - user sees complete context after adding player

API Response Format:
GET: {"count": N, "picks": [{team: {...}, player: {...}}]}
POST: {"count": N, "draft_list": [{team_id: X, player_id: Y}]}

This resolves:
- Empty list after adding player (Pydantic validation)
- "Add Failed" error despite successful operation
- Poor UX with minimal success feedback

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-25 19:35:50 -05:00
Cal Corum
0d64407217 CLAUDE: Rewrite all draft list operations for bulk replacement API
Root cause: Draft list API has NO individual CRUD endpoints.
Only endpoints available:
- GET (retrieve list)
- POST (bulk replacement - deletes all, inserts new list)

All modification operations (add, remove, clear, reorder, move) were
incorrectly using BaseService CRUD methods (create, delete, patch) which
don't exist for this endpoint.

Fixes:
- add_to_list(): Use bulk replacement with rank insertion logic
- remove_player_from_list(): Rebuild list without player
- clear_list(): POST empty list
- reorder_list(): POST list with new rank order
- move_entry_up(): Swap ranks and POST
- move_entry_down(): Swap ranks and POST
- remove_from_list(): Deprecated (no DELETE endpoint)

All operations now:
1. GET current list
2. Build updated list with modifications
3. POST entire updated list (bulk replacement)

This resolves all draft list modification failures including:
- "Add Failed" when adding players
- Remove operations failing silently
- Reorder/move operations failing

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-24 23:07:54 -05:00
Cal Corum
b0a5b19346 CLAUDE: Fix draft list add operation for bulk replacement API
Root cause: API mismatch between bot service and database endpoint.

The draft list POST endpoint uses bulk replacement pattern:
- Expects: {"count": N, "draft_list": [...]}
- Deletes entire team's list
- Inserts all entries in bulk

The bot service was incorrectly using BaseService.create() which sends
a single entry object, causing the API to reject the request.

Fix:
- Rewrite add_to_list() to use bulk replacement pattern
- Get current list
- Add new entry with proper rank insertion
- Shift existing entries if inserting in middle
- POST entire updated list to API
- Return created entry as DraftList object

This resolves "Add Failed" error when adding players to draft queue.

Note: Direct client.post() call is appropriate here since the API
endpoint doesn't follow standard CRUD patterns (uses bulk replacement).

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-24 23:03:26 -05:00
Cal Corum
7370fa7006 CLAUDE: Fix draft channel configuration not persisting
Root cause: Field naming mismatch between bot model and database schema.

The database stores channel IDs in columns named 'result_channel' and
'ping_channel', but the bot's DraftData model incorrectly used
'result_channel_id' and 'ping_channel_id'.

Additionally, the draft data PATCH endpoint requires query parameters
instead of JSON body (like player, game, transaction, and injury endpoints).

Changes:
- models/draft_data.py: Renamed fields to match database schema
  - result_channel_id → result_channel
  - ping_channel_id → ping_channel
- services/draft_service.py: Added use_query_params=True to PATCH calls
- views/draft_views.py: Updated embed to use correct field names
- tasks/draft_monitor.py: Updated channel lookups to use correct field names
- tests/test_models.py: Updated test assertions to match new field names

This fixes:
- Channel configuration now saves correctly via /draft-admin channels
- Ping channel settings persist across bot restarts
- Result channel settings persist across bot restarts
- All draft data updates work properly

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-24 22:52:57 -05:00
Cal Corum
ea7b356db9 CLAUDE: Refactor draft system to eliminate hard-coded magic numbers
Replace all hard-coded values with centralized config constants for better
maintainability and flexibility:

Added config constants:
- draft_team_count (16)
- draft_linear_rounds (10)
- swar_cap_limit (32.00)
- cap_player_count (26)
- draft_total_picks property (derived: rounds × teams)

Critical fixes:
- FA team ID (498) now uses config.free_agent_team_id in:
  * tasks/draft_monitor.py - Auto-draft validation
  * commands/draft/picks.py - Pick validation and autocomplete
- sWAR cap limit display now uses config.swar_cap_limit

Refactored modules:
- utils/draft_helpers.py - All calculation functions
- services/draft_service.py - Pick advancement logic
- views/draft_views.py - Display formatting

Benefits:
- Eliminates risk of silent failures from hard-coded IDs
- Centralizes all draft constants in one location
- Enables easy draft format changes via config
- Improves testability with mockable config
- Zero breaking changes - fully backwards compatible

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-24 22:14:17 -05:00
Cal Corum
0e54a81bbe CLAUDE: Add comprehensive draft system documentation
Update documentation across services, tasks, and commands:

Services Documentation (services/CLAUDE.md):
- Added Draft System Services section with all three services
- Documented why NO CACHING is used for draft services
- Explained architecture integration (global lock, background monitor)
- Documented hybrid linear+snake draft format

Tasks Documentation (tasks/CLAUDE.md):
- Added Draft Monitor task documentation
- Detailed self-terminating behavior and resource efficiency
- Explained global lock integration with commands
- Documented auto-draft process and channel requirements

Commands Documentation (commands/draft/CLAUDE.md):
- Complete reference for /draft command
- Global pick lock implementation details
- Pick validation flow (7-step process)
- FA player autocomplete pattern
- Cap space validation algorithm
- Race condition prevention strategy
- Troubleshooting guide and common issues
- Integration with background task
- Future commands roadmap

All documentation follows established patterns from existing
CLAUDE.md files with comprehensive examples and code snippets.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-24 15:16:39 -05:00