- Created utils/scorebug_helpers.py with shared scorebug functions
- create_scorebug_embed(): Unified embed creation for command and background task
- create_team_progress_bar(): Win probability visualization
- Fixed win probability bar to show dark blocks weighted toward winning team
- Arrow extends from the side with advantage
- Home winning: "POR ░▓▓▓▓▓▓▓▓▓► WV 95.0%"
- Away winning: "POR ◄▓▓▓▓▓▓▓░░░ WV 30.0%"
- Changed embed color from score-based to win probability-based
- Embed shows color of team favored to win, not necessarily winning
- Creates fun psychological element showing momentum/advantage
- Added dynamic channel visibility for #live-sba-scores
- Channel visible to @everyone when active games exist
- Channel hidden when no games are active
- Bot retains access via role permissions
- Added set_channel_visibility() to utils/discord_helpers.py
- Eliminated ~220 lines of duplicate code across files
- Removed duplicate embed creation from commands/gameplay/scorebug.py
- Removed duplicate embed creation from tasks/live_scorebug_tracker.py
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Enhancement: Allow releasing players to Free Agency via /ilmove
Changes:
- Added "Free Agency" as destination choice in command options
- Updated destination_map to include "fa" -> RosterType.FREE_AGENCY
- Added logic to fetch FA team from config (free_agent_team_id: 498)
- Set to_team correctly: FA team when releasing, user team otherwise
This allows users to immediately release players to Free Agency for current week,
complementing the existing ML/MiL/IL destination options.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Bug: /dropadd was incorrectly rejecting players from Minor League affiliates
Root Cause: Ownership check used team.id comparison instead of organizational check
Fix: Use team.is_same_organization() to properly handle ML/MiL/IL affiliates
Before: player.team.id != builder.team.id (fails for WVMiL when user owns WV)
After: not builder.team.is_same_organization(player.team) (correctly identifies same org)
This brings /dropadd in line with /ilmove implementation which already used
the correct organizational check pattern.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
App Version: 2.0.4
Created reusable text_utils module with split_text_for_fields() function
to handle rare play results that exceed Discord's 1024 character field limit.
Changes:
- New utils/text_utils.py with intelligent text splitting on delimiters
- Updated commands/dice/rolls.py to split long rare play results into multiple fields
- Automatic part indicators for multi-chunk results (e.g., "Part 1/2")
- Handles outfield rare plays (~1135 chars) by splitting into 2 fields
- Maintains single field for shorter infield/pitcher rare plays
Benefits:
- Fixes Discord field limit issue for outfield rare plays
- Reusable utility for any future long-text scenarios
- Clean breaks on semantic boundaries (between result types)
- No multiple embeds needed - everything in single embed
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Added data consistency check to automatically clear stale injury records
where is_active=True but il_return=None. This prevents old injury records
from blocking new injury creation when players should not be injured.
- Detects mismatch between injury table and player il_return field
- Auto-clears stale injury records with warning log
- Allows legitimate injuries with matching il_return to block command
- Logs both warning (stale data found) and info (cleared) for debugging
Fixes issue where Ronald Acuna Jr had active injury record but no il_return.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Fixed bug where responder_team variable was only assigned conditionally
but always referenced, causing UnboundLocalError when clearing injuries
for major league players.
- Initialize responder_team = None before conditional check
- Ensures variable is defined for both ML and non-ML teams
- Conditional expression on line 674 now works correctly
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
This enhancement automatically unpublishes scorecards when their associated
voice channels are deleted by the cleanup service, ensuring data synchronization
and reducing unnecessary API calls to Google Sheets for inactive games.
Implementation:
- Added gameplay commands package with scorebug/scorecard functionality
- Created ScorebugService for reading live game data from Google Sheets
- VoiceChannelTracker now stores text_channel_id for voice-to-text association
- VoiceChannelCleanupService integrates ScorecardTracker for automatic cleanup
- LiveScorebugTracker monitors published scorecards and updates displays
- Bot initialization includes gameplay commands and live scorebug tracker
Key Features:
- Voice channels track associated text channel IDs
- cleanup_channel() unpublishes scorecards during normal cleanup
- verify_tracked_channels() unpublishes scorecards for stale entries on startup
- get_voice_channel_for_text_channel() enables reverse lookup
- LiveScorebugTracker logging improved (debug level for missing channels)
Testing:
- Added comprehensive test coverage (2 new tests, 19 total pass)
- Tests verify scorecard unpublishing in cleanup and verification scenarios
Documentation:
- Updated commands/voice/CLAUDE.md with scorecard cleanup integration
- Updated commands/gameplay/CLAUDE.md with background task integration
- Updated tasks/CLAUDE.md with automatic cleanup details
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Image Version: 2.0.3
Added ability to add charts with multiple images and manage them incrementally.
Service Layer Changes (chart_service.py):
- Added add_image_to_chart() method to append URLs to existing charts
- Added remove_image_from_chart() method to remove specific URLs
- Validation to prevent duplicate URLs in charts
- Protection against removing the last image from a chart
Command Layer Changes (charts.py):
- Modified /chart-manage add to accept comma-separated URLs
- Parse and strip URLs from comma-delimited string
- Shows image count in success message
- Displays first image in response embed
- Added /chart-manage add-image command for incremental additions
- Added /chart-manage remove-image command to remove specific URLs
- All commands use chart autocomplete for easy selection
- Admin/Help Editor permission checks on all management commands
Usage Examples:
# Add chart with multiple images in one command
/chart-manage add defense "Defense Chart" gameplay "https://example.com/def1.png, https://example.com/def2.png"
# Add additional images later
/chart-manage add-image defense https://example.com/def3.png
# Remove specific image
/chart-manage remove-image defense https://example.com/def2.png🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Added new command to resolve caching issue where manual edits to
charts.json were not reflected in the bot without a restart.
Changes:
- Added /chart-manage reload command to ChartManageGroup
- Calls chart_service.reload_charts() to refresh in-memory cache
- Shows success message with chart and category counts
- Requires admin or Help Editor role permissions
- Uses @logged_command decorator for automatic logging
Fixes: Chart updates not appearing until bot restart
Resolves: Permission denied issue with charts.json (ownership fixed separately)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Adding 17 CLAUDE.md files across the project to provide detailed context
and implementation guidelines for AI development agents:
Root Documentation:
- CLAUDE.md - Main project guide with Git workflow requirements
Component Documentation:
- commands/CLAUDE.md - Command architecture and patterns
- models/CLAUDE.md - Pydantic models and validation
- services/CLAUDE.md - Service layer and API interactions
- tasks/CLAUDE.md - Background tasks and automation
- tests/CLAUDE.md - Testing strategies and patterns
- utils/CLAUDE.md - Utility functions and decorators
- views/CLAUDE.md - Discord UI components and embeds
Command Package Documentation:
- commands/help/CLAUDE.md - Help system implementation
- commands/injuries/CLAUDE.md - Injury management commands
- commands/league/CLAUDE.md - League-wide commands
- commands/players/CLAUDE.md - Player information commands
- commands/profile/CLAUDE.md - User profile commands
- commands/teams/CLAUDE.md - Team information commands
- commands/transactions/CLAUDE.md - Transaction management
- commands/utilities/CLAUDE.md - Utility commands
- commands/voice/CLAUDE.md - Voice channel management
Key Updates:
- Updated .gitignore to track CLAUDE.md files in version control
- Added Git Workflow section requiring branch-based development
- Documented all architectural patterns and best practices
- Included comprehensive command/service implementation guides
These files provide essential context for AI agents working on the codebase,
ensuring consistent patterns, proper error handling, and maintainable code.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
The command was incorrectly using get_team_schedule(weeks=1) which fetches
the first week of the season rather than the current week's games. Changed
to use get_week_schedule(current_week) with proper team filtering.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Implemented comprehensive /ilmove command system for immediate roster changes (IL moves,
activations, etc.) that execute instantly for the current week, complementing the existing
/dropadd system which schedules moves for next week.
New Features:
- /ilmove command: Interactive transaction builder for THIS week (immediate execution)
- /clearilmove command: Clear current IL move transaction builder
- Dual-mode transaction system: Scheduled (/dropadd) vs Immediate (/ilmove)
Key Fixes:
- Organizational team matching: Minor League players (WVMiL) now correctly recognized as
valid targets for their Major League organization (WV)
- Transaction POST format: Fixed to use correct batch API format with count/moves structure
- RosterType to team affiliate mapping: Moves to IL now correctly assign players to WVIL
instead of WV, and moves from MiL correctly reference WVMiL as source team
- Player team updates: Added update_player_team() method for immediate team assignments
Technical Changes:
- commands/transactions/ilmove.py: New command with organizational validation
- commands/transactions/__init__.py: Register ILMoveCommands cog
- services/transaction_service.py: create_transaction_batch() with correct batch format
- services/player_service.py: update_player_team() for immediate updates
- services/transaction_builder.py: RosterType affiliate resolution with async team lookups
- views/transaction_embed.py: Dual-mode support with context-aware instructions
Code Reuse:
- 95% code sharing between /dropadd and /ilmove via shared TransactionBuilder
- Same validation, UI, and move tracking - only submission differs
- Context-aware command_name parameter for dynamic UI instructions
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Added /jump command for baserunner stealing mechanics with pickoff/balk detection.
Enhanced dice rolling commands with team color support in embeds.
Improved /admin-sync with local/global options and prefix command fallback.
Fixed type safety issues in admin commands and injury management.
Updated config for expanded draft rounds and testing mode.
Key changes:
- commands/dice/rolls.py: New /jump and !j commands with special cases for pickoff (d20=1) and balk (d20=2)
- commands/dice/rolls.py: Added team/channel color support to /ab and dice embeds
- commands/dice/rolls.py: Added pitcher position to /fielding command with proper range/error charts
- commands/admin/management.py: Enhanced /admin-sync with local/clear options and !admin-sync prefix fallback
- commands/admin/management.py: Fixed Member type checking and channel type validation
- commands/injuries/management.py: Fixed responder team detection for injury clearing
- models/custom_command.py: Made creator_id optional for execute endpoint compatibility
- config.py: Updated draft_rounds to 32 and enabled testing mode
- services/transaction_builder.py: Adjusted ML roster limit to 26
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Implements comprehensive automated system for weekly transaction freeze periods
with priority-based contested player resolution.
New Features:
- Weekly freeze/thaw task (Monday 00:00 freeze, Saturday 00:00 thaw)
- Priority resolution for contested transactions (worst teams get first priority)
- Admin league management commands (/freeze-begin, /freeze-end, /advance-week)
- Enhanced API client to handle string-based transaction IDs (moveids)
- Service layer methods for transaction cancellation, unfreezing, and bulk operations
- Offseason mode configuration flag to disable freeze operations
Technical Changes:
- api/client.py: URL-encode object_id parameter to handle colons in moveids
- bot.py: Initialize and shutdown transaction freeze task
- config.py: Add offseason_flag to BotConfig
- services/league_service.py: Add update_current_state() for week/freeze updates
- services/transaction_service.py: Add cancel/unfreeze methods with bulk support
- tasks/transaction_freeze.py: Main freeze/thaw automation with error recovery
- commands/admin/league_management.py: Manual admin controls for freeze system
Infrastructure:
- .gitlab-ci.yml and .gitlab/: GitLab CI/CD pipeline configuration
- .mcp.json: MCP server configuration
- Dockerfile.versioned: Versioned Docker build support
- .dockerignore: Added .gitlab/ to ignore list
Testing:
- tests/test_tasks_transaction_freeze.py: Comprehensive freeze task tests
The system uses team standings to fairly resolve contested players (multiple teams
trying to acquire the same player), with worst-record teams getting priority.
Includes comprehensive error handling, GM notifications, and admin reporting.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add interactive PlayerStatsView with toggle buttons to show/hide batting and
pitching statistics independently in the /player command. Stats are hidden by
default with clean, user-friendly buttons (💥 batting, ⚾ pitching) that update
the embed in-place. Only the command caller can toggle stats, and buttons
timeout after 5 minutes.
Player Stats Toggle Feature:
- Add views/players.py with PlayerStatsView class
- Update /player command to use interactive view
- Stats hidden by default, shown on button click
- Independent batting/pitching toggles
- User-restricted interactions with timeout handling
Injury System Enhancements:
- Add BatterInjuryModal and PitcherRestModal for injury logging
- Add player_id extraction validator to Injury model
- Fix injury creation to merge API request/response data
- Add responders parameter to BaseView for multi-user interactions
API Client Improvements:
- Handle None values correctly in PATCH query parameters
- Convert None to empty string for nullable fields in database
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Added confirmation embed before clearing injury
- Shows player info, team, expected return, games missed
- User prompted: "Is {Player} cleared to return?"
- Buttons: "Clear Injury" / "Cancel"
- 3-minute timeout for response
- Team GMs can also confirm/cancel
- Added player autocomplete to /injury clear command
- Uses same autocomplete as /injury roll
- Prioritizes user's team players
- Updated commands/injuries/CLAUDE.md documentation
- Documented new confirmation flow
- Added autocomplete parameter details
- Clarified user flow and responders
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
This commit addresses critical bugs in the injury command system and
establishes best practices for Discord command groups.
## Critical Fixes
### 1. GroupCog → app_commands.Group Migration
- **Problem**: `commands.GroupCog` has a duplicate interaction processing bug
causing "404 Unknown interaction" errors when deferring responses
- **Root Cause**: GroupCog triggers command handler twice, consuming the
interaction token before the second execution can respond
- **Solution**: Migrated InjuryCog to InjuryGroup using `app_commands.Group`
pattern (same as ChartManageGroup and ChartCategoryGroup)
- **Result**: Reliable command execution, no more 404 errors
### 2. GiphyService GIF URL Fix
- **Problem**: Giphy service returned web page URLs (https://giphy.com/gifs/...)
instead of direct image URLs, preventing Discord embed display
- **Root Cause**: Code accessed `data.url` instead of `data.images.original.url`
- **Solution**: Updated both `get_disappointment_gif()` and `get_gif()` methods
to use correct API response path for embeddable GIF URLs
- **Result**: GIFs now display correctly in Discord embeds
## Documentation
### Command Groups Best Practices (commands/README.md)
Added comprehensive section documenting:
- **Critical Warning**: Never use `commands.GroupCog` - use `app_commands.Group`
- **Technical Explanation**: Why GroupCog fails (duplicate execution bug)
- **Migration Guide**: Step-by-step conversion from GroupCog to Group
- **Comparison Table**: Key differences between the two approaches
- **Working Examples**: References to ChartManageGroup, InjuryGroup patterns
## Architecture Changes
### Injury Commands (`commands/injuries/`)
- Converted from `commands.GroupCog` to `app_commands.Group`
- Registration via `bot.tree.add_command()` instead of `bot.add_cog()`
- Removed workarounds for GroupCog duplicate interaction issues
- Clean defer/response pattern with `@logged_command` decorator
### GiphyService (`services/giphy_service.py`)
- Centralized from `commands/soak/giphy_service.py`
- Now returns direct GIF image URLs for Discord embeds
- Maintains Trump GIF filtering (legacy behavior)
- Added gif_url to log output for debugging
### Configuration (`config.py`)
- Added `giphy_api_key` and `giphy_translate_url` settings
- Environment variable support via `GIPHY_API_KEY`
- Default values provided for out-of-box functionality
## Files Changed
- commands/injuries/: New InjuryGroup with app_commands.Group pattern
- services/giphy_service.py: Centralized service with GIF URL fix
- commands/soak/giphy_service.py: Backwards compatibility wrapper
- commands/README.md: Command groups best practices documentation
- config.py: Giphy configuration settings
- services/__init__.py: GiphyService exports
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Makes all application constants (except baseball positions) configurable
via environment variables for greater deployment flexibility.
Changes:
- config.py: Added 18 new configurable fields to BotConfig
* Discord limits (embed/field/description limits)
* League settings (weeks, games, modern stats era)
* Current season constants (SBA/PD)
* API configuration (version, timeout, retries)
* Draft settings (pick minutes, rounds)
* Special team IDs (free agent team)
* Role/channel names (help editor, players, news channel)
* Base URLs (SBA website)
- constants.py: Refactored to load from config
* All constants now read from get_config()
* Position sets remain static (PITCHER_POSITIONS, etc.)
* Added documentation about configurability
- .env.example: Added all new environment variables
* Organized into logical sections with headers
* Includes default values from config.py
* Clear documentation for each setting
Benefits:
- Environment-specific configuration without code changes
- Easy deployment across dev/staging/production
- Season rollover requires only env variable updates
- Team-specific customization (channels, roles, URLs)
- Docker-friendly configuration management
Backward Compatible: All defaults match previous hardcoded values
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Implements full Google Sheets scorecard submission with:
- Complete game data extraction (68 play fields, pitching decisions, box score)
- Transaction rollback support at 3 states (plays/game/complete)
- Duplicate game detection with confirmation dialog
- Permission-based submission (GMs only)
- Automated results posting to news channel
- Automatic standings recalculation
- Key plays display with WPA sorting
New Components:
- Play, Decision, Game models with full validation
- SheetsService for Google Sheets integration
- GameService, PlayService, DecisionService for data management
- ConfirmationView for user confirmations
- Discord helper utilities for channel operations
Services Enhanced:
- StandingsService: Added recalculate_standings() method
- CustomCommandsService: Fixed creator endpoint path
- Team/Player models: Added helper methods for display
Configuration:
- Added SHEETS_CREDENTIALS_PATH environment variable
- Added SBA_NETWORK_NEWS_CHANNEL and role constants
- Enabled pygsheets dependency
Documentation:
- Comprehensive README updates across all modules
- Added command, service, model, and view documentation
- Detailed workflow and error handling documentation
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Fixed issue where key plays were showing the score twice:
- Before: "Top 3: Player (NYY) homers, NYY up 2-0, NYY up 2-0"
- After: "Top 3: Player (NYY) homers, NYY up 2-0"
Changes:
- Simplified Play.descriptive_text() to use rbi for score calculation
- Removed duplicate score logic in format_key_plays() helper
- Now only shows score after the play is completed
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Standardize data file locations to data/ directory and improve command organization with better UI for team rosters, pagination for team lists, and refactored chart commands into logical command groups.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Fix transaction count bug by filtering transactions >= current week
- Add TransactionPaginationView with "Show Move IDs" button
- Implement intelligent message chunking for long transaction lists
- Remove emojis from individual transaction lines (kept in headers)
- Display 10 transactions per page with navigation buttons
- Show move IDs on demand via ephemeral button (stays under 2000 char limit)
- Update all tests to validate pagination and chunking behavior
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Replaced dictionary return values with a DiceRoll dataclass for better
type safety and cleaner code.
Changes:
- Added DiceRoll dataclass with fields: dice_notation, num_dice, die_sides, rolls, total
- Updated _parse_and_roll_single_dice() to return Optional[DiceRoll]
- Updated _parse_and_roll_multiple_dice() to return list[DiceRoll]
- Updated _roll_weighted_scout_dice() to return list[DiceRoll]
- Updated _create_multi_roll_embed() to accept list[DiceRoll]
- Updated _create_fielding_embed() to accept list[DiceRoll]
- Changed all dict key access (result['total']) to dataclass attributes (result.total)
- Updated logging statements to use dataclass attributes
- Updated all 34 test cases to use DiceRoll dataclass
Benefits:
- Improved type safety with explicit dataclass types
- Better IDE autocomplete and type checking
- More maintainable code with clear data structures
- No runtime changes - all functionality preserved
All 34 dice command tests pass.
Fixed 14 instances across 6 command files where manual emojis were added
to titles when EmbedTemplate methods already add them automatically.
Changes:
- commands/soak/info.py: Removed 📊 from info() title
- commands/help/main.py: Removed 📚, ✅, ⚠️ from various titles (4 fixes)
- commands/profile/images.py: Removed ✅ from success() title
- commands/voice/channels.py: Removed 📢 from deprecated command titles (2 fixes)
- commands/custom_commands/main.py: Removed ✅, 📝 from titles (3 fixes)
- commands/utilities/charts.py: Removed ✅ from admin command titles (3 fixes)
This prevents double emoji rendering (e.g., "ℹ️📊 Last Soak" now shows as "ℹ️ Last Soak")
since EmbedTemplate.success/error/warning/info/loading methods automatically prepend
the appropriate emoji to the title.
Update CacheManager.get() and CacheManager.set() type annotations to
accept Any JSON-serializable type (dict, list, str, int, bool, None)
instead of just dict.
This fixes type checker warnings in base_service.py where lists are
cached for API responses. The runtime behavior was already correct,
this just aligns the type hints with actual usage.
Changes:
- CacheManager.get() return type: Optional[dict] -> Optional[Any]
- CacheManager.set() data param: dict -> Any
- Updated docstrings to clarify JSON-serializable types
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add comprehensive "soaking" easter egg feature that detects mentions
and responds with GIFs showing escalating disappointment based on
recency (reversed from legacy - more recent = more disappointed).
Features:
- Detects "soak", "soaking", "soaked", "soaker" (case-insensitive)
- 7 disappointment tiers with 5 varied search phrases each
- Giphy API integration with Trump filter and fallback handling
- JSON-based persistence tracking all mentions with history
- /lastsoak command showing detailed information
- 25 comprehensive unit tests (all passing)
Architecture:
- commands/soak/giphy_service.py - Tiered GIF fetching
- commands/soak/tracker.py - JSON persistence with history
- commands/soak/listener.py - Message detection and response
- commands/soak/info.py - /lastsoak info command
- tests/test_commands_soak.py - Full test coverage
Uses existing Giphy API key from legacy implementation.
Zero new dependencies, follows established patterns.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Added defensive error handling to prevent crashes when custom command
creators are missing from the database.
Changes Made:
1. services/custom_commands_service.py:
- Added try/except blocks in get_popular_commands()
- Added try/except blocks in get_commands_needing_warning()
- Added try/except blocks in get_commands_eligible_for_deletion()
- Catches BotException when get_creator_by_id() fails
- Logs warning with command details and continues processing
- Skips problematic commands instead of failing entire operation
2. commands/help/main.py:
- Removed redundant emoji from success message title
- EmbedTemplate.success() already includes check mark emoji
3. tests/test_models_help_command.py:
- Updated test assertions to match new message format
4. tests/test_services_help_commands.py:
- Updated test expectations for error handling behavior
Impact:
- Prevents service crashes when creator data is orphaned or deleted
- Maintains functionality for commands with valid creator data
- Provides visibility into data integrity issues via warning logs
- Ensures automated cleanup tasks can complete successfully
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
The /set-image command was failing to persist player image updates to the
database. Investigation revealed a mismatch between how the bot sent PATCH
data versus how the database API expected it.
Root Cause:
- Database API endpoint (/api/v3/players/{id}) expects PATCH data as URL
query parameters, not JSON body
- Bot was sending: PATCH /api/v3/players/12288 {"vanity_card": "url"}
- API expected: PATCH /api/v3/players/12288?vanity_card=url
Changes Made:
1. api/client.py:
- Added use_query_params parameter to patch() method
- When enabled, sends data as URL query parameters instead of JSON body
- Maintains backward compatibility (defaults to JSON body)
2. services/base_service.py:
- Added use_query_params parameter to patch() method
- Passes parameter through to API client
3. services/player_service.py:
- Updated update_player() to use use_query_params=True
- Added documentation note about query parameter requirement
4. commands/profile/images.py:
- Fixed autocomplete to use correct utility function
- Changed from non-existent player_autocomplete_with_team_priority
- Now uses player_autocomplete from utils/autocomplete.py
Documentation Updates:
5. commands/profile/README.md:
- Updated API Integration section
- Documented PATCH endpoint uses query parameters
- Added note about automatic handling in player_service
6. services/README.md:
- Added PATCH vs PUT operations documentation
- Documented use_query_params parameter
- Included usage examples for both modes
Testing:
- Verified /set-image command now successfully persists image URLs
- Confirmed API returns updated player with vanity_card populated
- Validated both fancy-card and headshot updates work correctly
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add /set-image command for updating player fancy cards and headshots.
Features:
- Single command with fancy-card/headshot choice parameter
- Comprehensive URL validation (format + accessibility testing)
- Permission system (users can edit org players, admins can edit all)
- Preview embed with confirmation dialog before database update
- Player name autocomplete prioritizing user's team
- HTTP HEAD request to verify URL accessibility and content-type
Implementation:
- New commands/profile/ package with ImageCommands cog
- Two-stage URL validation (format check + accessibility test)
- Permission checking via Team.is_same_organization()
- Interactive confirmation view with 180s timeout
- Updates player.vanity_card or player.headshot field
Testing:
- 23 comprehensive tests covering validation and permissions
- Uses aioresponses for HTTP mocking (project standard)
- Test coverage for admin/user permissions and organization checks
Documentation:
- Comprehensive README.md with usage guide and troubleshooting
- Updated PRE_LAUNCH_ROADMAP.md to mark feature complete
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Update PRE_LAUNCH_ROADMAP.md to reflect completion of help system:
- Changed status from "🚧 In progress" to "✅ Complete"
- Updated resource tracking to show help system complete (saved 2-3 hours)
- Updated next steps to focus on remaining features (images, memes, scout)
Remaining pre-launch work: ~6-9 hours (images, memes, scouting)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>