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>
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>
The Saturday thaw report was silently failing because it searched for
channels named 'bot-admin', 'admin', or 'bot-logs' which don't exist.
Now uses a configurable channel ID (overridable via THAW_REPORT_CHANNEL_ID).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add clickable link field to weather embed as fallback for Discord
caching issues. Users can click the link to view the stadium image
in their browser if the embedded image fails to render.
Changes:
- Added "Stadium Image" field with direct link to team.stadium
- Bump version to 2.29.7
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
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.
**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>
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>
The all_seasons=True parameter causes the API search query to take 15+ seconds,
exceeding Discord's 3-second autocomplete timeout. Changed to all_seasons=False
to search only the current season, which is fast enough.
Users can still access historical players by manually typing the name and using
the season parameter in the /player command.
Fixes: discord.errors.NotFound 404 (error code: 10062): Unknown interaction
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Fix /injury roll and /injury clear commands crashing when player.team is None
- Add team fetching logic after search_players() for all injury commands
- The search_players() API endpoint returns team as ID only (not nested object)
- Added null checks and explicit team fetching using team_service.get_team()
- Add Gitea Actions workflow for automated Docker builds
- Implements semantic version validation on PRs
- Builds and pushes to Docker Hub on main branch merges
- Sends Discord notifications on success/failure
- Generates 3 image tags: latest, v{VERSION}, v{VERSION}-{COMMIT}
Fixes AttributeError: 'NoneType' object has no attribute 'roster_type'
Fixes AttributeError: 'NoneType' object has no attribute 'thumbnail'
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
The search_players() API endpoint returns team as an ID only (not nested object),
causing player.team to be None. Added null check before accessing team.thumbnail.
Fixes AttributeError: 'NoneType' object has no attribute 'thumbnail'
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
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>
Prevents double emoji display by clearing the "✅ Confirmed!" content
when showing the delete result embed.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
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>
The delete confirmation was showing success but never calling the delete
service. Added the actual delete_command() call when user confirms.
Co-Authored-By: Claude <noreply@anthropic.com>
- Use channel.send() instead of followup.send() for custom command output
(webhook-based followup messages don't trigger mention notifications)
- Add ephemeral "Sending..." confirmation to satisfy interaction response
- Add utils/mentions.py for converting text @mentions to Discord format
- Add tests for mention conversion utility
Co-Authored-By: Claude <noreply@anthropic.com>
Comprehensive guide covering:
- Build/lint/test commands including single test execution
- Code style: imports, formatting, types, naming, error handling
- Discord patterns: @logged_command, autocomplete, embed emojis
- Service layer abstraction rules
- Model patterns (from_api_data, required IDs)
- Testing with aioresponses and complete model data
- Critical rules for git, services, and commits
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>