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>
14 KiB
Injury Commands
Command Group: /injury
Permission Required: SBA Players role (for set-new and clear)
Subcommands: roll, set-new, clear
Overview
The injury command family provides comprehensive player injury management for the SBA league. Team managers can roll for injuries using official Strat-o-Matic injury tables, record confirmed injuries, and clear injuries when players return.
Commands
/injury roll
Roll for injury based on a player's injury rating using 3d6 dice and official injury tables.
Usage:
/injury roll <player_name>
Parameters:
player_name(required, autocomplete): Name of the player - uses smart autocomplete prioritizing your team's players
Injury Rating Format:
The player's injury_rating field contains both the games played and rating in format #p##:
- Format:
1p70,4p50,2p65, etc. - First character: Games played in current series (1-6)
- Remaining characters: Injury rating (p70, p65, p60, p50, p40, p30, p20)
Examples:
1p70= 1 game played, p70 rating4p50= 4 games played, p50 rating2p65= 2 games played, p65 rating
Dice Roll:
- Rolls 3d6 (3-18 range)
- Automatically extracts games played and rating from player's injury_rating field
- Looks up result in official Strat-o-Matic injury tables
- Returns injury duration based on rating and games played
Possible Results:
- OK: No injury
- REM: Remainder of game (batters) or Fatigued (pitchers)
- Number: Games player will miss (1-24 games)
Example:
/injury roll Mike Trout
Response Fields:
- Roll: Total rolled and individual dice (e.g., "15 (3d6: 5 + 5 + 5)")
- Player: Player name and position
- Injury Rating: Full rating with parsed details (e.g., "4p50 (p50, 4 games)")
- Result: Injury outcome (OK, REM, or number of games)
- Team: Player's current team
Response Colors:
- Green: OK (no injury)
- Gold: REM (remainder of game/fatigued)
- Orange: Number of games (injury occurred)
Error Handling:
If a player's injury_rating is not in the correct format, an error message will be displayed:
Invalid Injury Rating Format
{Player} has an invalid injury rating: `{rating}`
Expected format: #p## (e.g., 1p70, 4p50)
/injury set-new
Record a new injury for a player on your team.
Usage:
/injury set-new <player_name> <this_week> <this_game> <injury_games>
Parameters:
player_name(required): Name of the player to injurethis_week(required): Current week numberthis_game(required): Current game number (1-4)injury_games(required): Total number of games player will be out
Validation:
- Player must exist in current season
- Player cannot already have an active injury
- Game number must be between 1 and 4
- Injury duration must be at least 1 game
Automatic Calculations: The command automatically calculates:
- Injury start date (adjusts for game 4 edge case)
- Return date based on injury duration
- Week rollover when games exceed 4 per week
Example:
/injury set-new Mike Trout 5 2 4
This records an injury occurring in week 5, game 2, with player out for 4 games (returns week 6, game 2).
Response:
- Confirmation embed with injury details
- Player's name, position, and team
- Total games missed
- Calculated return date
/injury clear
Clear a player's active injury and mark them as eligible to play.
Usage:
/injury clear <player_name>
Parameters:
player_name(required, autocomplete): Name of the player whose injury to clear - uses smart autocomplete prioritizing your team's players
Validation:
- Player must exist in current season
- Player must have an active injury
User Flow:
- Command issued with player name
- Confirmation embed displayed showing:
- Player name and position
- Team name and abbreviation
- Expected return date
- Total games missed
- Team thumbnail (if available)
- User prompted: "Is {Player Name} cleared to return?"
- Two buttons presented:
- "Clear Injury" → Proceeds with clearing the injury
- "Cancel" → Cancels the operation
- After confirmation, injury is cleared and success message displayed
Example:
/injury clear Mike Trout
Confirmation Embed:
- Title: Player name
- Description: "Is {Player Name} cleared to return?"
- Fields: Player info, team, expected return date, games missed
- Buttons: "Clear Injury" / "Cancel"
- Timeout: 3 minutes
Success Response (after confirmation):
- Confirmation that injury was cleared
- Shows previous return date
- Shows total games that were missed
- Player's team information
Responders:
- Command issuer
- Team GM(s) - can also confirm/cancel on behalf of team
Date Format
All injury dates use the format w##g#:
w##= Week number (zero-padded to 2 digits)g#= Game number (1-4)
Examples:
w05g2= Week 5, Game 2w12g4= Week 12, Game 4w01g1= Week 1, Game 1
Injury Calculation Logic
Basic Calculation
For an injury of N games starting at week W, game G:
-
Calculate weeks and remaining games:
out_weeks = floor(N / 4) out_games = N % 4 -
Calculate return date:
return_week = W + out_weeks return_game = G + 1 + out_games -
Handle week rollover:
if return_game > 4: return_week += 1 return_game -= 4
Special Cases
Game 4 Edge Case
If injury occurs during game 4, the start date is adjusted:
start_week = W + 1
start_game = 1
Examples
Example 1: Simple injury (same week)
- Current: Week 5, Game 1
- Injury: 2 games
- Return: Week 5, Game 4
Example 2: Week rollover
- Current: Week 5, Game 3
- Injury: 3 games
- Return: Week 6, Game 3
Example 3: Multi-week injury
- Current: Week 5, Game 2
- Injury: 8 games
- Return: Week 7, Game 3
Example 4: Game 4 start
- Current: Week 5, Game 4
- Injury: 2 games
- Start: Week 6, Game 1
- Return: Week 6, Game 3
Database Schema
Injury Model
class Injury(SBABaseModel):
id: int # Injury ID
season: int # Season number
player_id: int # Player ID
total_games: int # Total games player will be out
start_week: int # Week injury started
start_game: int # Game number injury started (1-4)
end_week: int # Week player returns
end_game: int # Game number player returns (1-4)
is_active: bool # Whether injury is currently active
API Integration
The commands interact with the following API endpoints:
GET /api/v3/injuries- Query injuries with filtersPOST /api/v3/injuries- Create new injury recordPATCH /api/v3/injuries/{id}- Update injury (clear active status)PATCH /api/v3/players/{id}- Update player's il_return field
Service Layer
InjuryService
Location: services/injury_service.py
Key Methods:
get_active_injury(player_id, season)- Get active injury for playerget_injuries_by_player(player_id, season, active_only)- Get all injuries for playerget_injuries_by_team(team_id, season, active_only)- Get team injuriescreate_injury(...)- Create new injury recordclear_injury(injury_id)- Deactivate injury
Permissions
Required Roles
For /injury check:
- No role required (available to all users)
For /injury set-new and /injury clear:
- SBA Players role required
- Configured via
SBA_PLAYERS_ROLE_NAMEenvironment variable
Permission Checks
The commands use has_player_role() method to verify user has appropriate role:
def has_player_role(self, interaction: discord.Interaction) -> bool:
"""Check if user has the SBA Players role."""
player_role = discord.utils.get(
interaction.guild.roles,
name=get_config().sba_players_role_name
)
return player_role in interaction.user.roles if player_role else False
Error Handling
Common Errors
Player Not Found:
❌ Player Not Found
I did not find anybody named **{player_name}**.
Already Injured:
❌ Already Injured
Hm. It looks like {player_name} is already hurt.
Not Injured:
❌ No Active Injury
{player_name} isn't injured.
Invalid Input:
❌ Invalid Input
Game number must be between 1 and 4.
Permission Denied:
❌ Permission Denied
This command requires the **SBA Players** role.
Logging
All injury commands use the @logged_command decorator for automatic logging:
@app_commands.command(name="check")
@logged_command("/injury check")
async def injury_check(self, interaction, player_name: str):
# Command implementation
Log Context:
- Command name
- User ID and username
- Player name
- Season
- Injury details (duration, dates)
- Success/failure status
Example Log:
{
"level": "INFO",
"command": "/injury set-new",
"user_id": "123456789",
"player_name": "Mike Trout",
"season": 12,
"injury_games": 4,
"return_date": "w06g2",
"message": "Injury set for Mike Trout"
}
Testing
Test Coverage
Location: tests/test_services_injury.py
Test Categories:
- Model Tests (5 tests) - Injury model creation and properties
- Service Tests (8 tests) - InjuryService CRUD operations with API mocking
- Roll Logic Tests (8 tests) - Injury rating parsing, table lookup, and dice roll logic
- Calculation Tests (5 tests) - Date calculation logic for injury duration
Total: 26 comprehensive tests
Running Tests:
# Run all injury tests
python -m pytest tests/test_services_injury.py -v
# Run specific test class
python -m pytest tests/test_services_injury.py::TestInjuryService -v
python -m pytest tests/test_services_injury.py::TestInjuryRollLogic -v
# Run with coverage
python -m pytest tests/test_services_injury.py --cov=services.injury_service --cov=commands.injuries
Injury Roll Tables
Table Structure
The injury tables are based on official Strat-o-Matic rules with the following structure:
Ratings: p70, p65, p60, p50, p40, p30, p20 (higher is better) Games Played: 1-6 games in current series Roll: 3d6 (results from 3-18)
Rating Availability by Games Played
Not all ratings are available for all games played combinations:
- 1 game: All ratings (p70-p20)
- 2 games: All ratings (p70-p20)
- 3 games: p65-p20 (p70 exempt)
- 4 games: p60-p20 (p70, p65 exempt)
- 5 games: p60-p20 (p70, p65 exempt)
- 6 games: p40-p20 (p70, p65, p60, p50 exempt)
When a rating/games combination has no table, the result is automatically "OK" (no injury).
Example Table (p65, 1 game):
| Roll | Result |
|---|---|
| 3 | 2 |
| 4 | 2 |
| 5 | OK |
| 6 | REM |
| 7 | 1 |
| ... | ... |
| 18 | 12 |
UI/UX Design
Embed Colors
- Roll (OK): Green - No injury
- Roll (REM): Gold - Remainder of game/Fatigued
- Roll (Injury): Orange - Number of games
- Set New: Success (green) -
EmbedTemplate.success() - Clear: Success (green) -
EmbedTemplate.success() - Errors: Error (red) -
EmbedTemplate.error()
Response Format
All successful responses use Discord embeds with:
- Clear title indicating action/status
- Well-organized field layout
- Team information when applicable
- Consistent formatting for dates
Integration with Player Model
The Player model includes injury-related fields:
class Player(SBABaseModel):
# ... other fields ...
pitcher_injury: Optional[int] # Pitcher injury rating
injury_rating: Optional[str] # General injury rating
il_return: Optional[str] # Injured list return date (w##g#)
When an injury is set or cleared, the player's il_return field is automatically updated via PlayerService.
Future Enhancements
Possible improvements for future versions:
- Injury History - View player's injury history for a season
- Team Injury Report - List all injuries for a team
- Injury Notifications - Automatic notifications when players return from injury
- Injury Statistics - Track injury trends and statistics
- Injury Chart Image - Display the official injury chart as an embed image
Migration from Legacy
Legacy Commands
The legacy injury commands were located in:
discord-app/cogs/players.py-set_injury_slash()andclear_injury_slash()discord-app/cogs/players.py-injury_roll_slash()with manual rating/games input
Key Improvements
- Cleaner Command Structure: Using GroupCog for organized subcommands (
/injury roll,/injury set-new,/injury clear) - Simplified Interface: Single parameter for injury roll - games played automatically extracted from player data
- Smart Injury Ratings: Automatically reads and parses player's injury rating from database
- Player Autocomplete: Modern autocomplete with team prioritization for better UX
- Better Error Handling: User-friendly error messages via EmbedTemplate with format validation
- Improved Logging: Automatic logging via @logged_command decorator
- Service Layer: Separated business logic from command handlers
- Type Safety: Full type hints and Pydantic models
- Testability: Comprehensive unit tests (26 tests) with mocked API calls
- Modern UI: Consistent embed-based responses with color coding
- Official Tables: Complete Strat-o-Matic injury tables built into the command
Migration Details
Old: /injuryroll <rating> <games> - Manual rating and games selection
New: /injury roll <player> - Single parameter, automatic rating and games extraction from player's injury_rating field
Old: /setinjury <player> <week> <game> <duration>
New: /injury set-new <player> <week> <game> <duration> - Same functionality, better naming
Old: /clearinjury <player>
New: /injury clear <player> - Same functionality, better naming
Database Field Update
The injury_rating field format has changed to include games played:
- Old Format:
p65,p70, etc. (rating only) - New Format:
1p70,4p50,2p65, etc. (games + rating)
Players must have their injury_rating field updated to the new format for the /injury roll command to work.
Last Updated: January 2025 Version: 2.0 Status: Active