major-domo-v2/commands/gameplay/CLAUDE.md
Cal Corum 5616cfec3a CLAUDE: Add automatic scorecard unpublishing when voice channels are cleaned up
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>
2025-10-21 07:18:21 -05:00

318 lines
10 KiB
Markdown

# Gameplay Commands
This directory contains Discord slash commands for live game tracking and scorecard management during gameplay.
## Files
### `scorebug.py`
- **Commands**:
- `/publish-scorecard <url>` - Link a Google Sheets scorecard to a channel for live tracking
- `/scorebug [full_length]` - Display the current scorebug from the published scorecard
- **Description**: Main command implementation for scorebug display and management
- **Service Dependencies**:
- `ScorebugService` - Reading live game data from Google Sheets
- `team_service.get_team()` - Team information lookup
- **Tracker Dependencies**:
- `ScorecardTracker` - JSON-based persistent storage of scorecard-channel mappings
### `scorecard_tracker.py`
- **Class**: `ScorecardTracker`
- **Description**: JSON-based persistent tracking of published scorecards
- **Features**:
- Maps Discord text channels to Google Sheets URLs
- Persistent storage across bot restarts
- Automatic stale entry cleanup
- Timestamp tracking for monitoring
### `__init__.py`
- **Function**: `setup_gameplay(bot)`
- **Description**: Package initialization with resilient cog loading
- **Integration**: Follows established bot architecture patterns
## Background Integration
### Live Scorebug Tracker Task
**File**: `tasks/live_scorebug_tracker.py`
**Schedule**: Every 3 minutes
**Operations**:
1. **Update `#live-sba-scores` Channel**
- Reads all published scorecards from tracker
- Generates compact scorebug embeds for active games
- Clears old messages and posts fresh scorebugs
- Filters out final games (only shows active/in-progress)
2. **Update Voice Channel Descriptions**
- For each active scorecard, checks for associated voice channel
- Updates voice channel topic with live score: `"BOS 4 @ 3 NYY"`
- Adds "FINAL" suffix when game completes: `"BOS 5 @ 3 NYY - FINAL"`
- Gracefully handles missing or deleted voice channels
## Key Features
### `/publish-scorecard <url>`
**URL/Key Support**:
- Full URL: `https://docs.google.com/spreadsheets/d/[KEY]/edit...`
- Just the key: `[SHEET_KEY]`
**Validation**:
- Checks scorecard accessibility (public read permissions)
- Verifies scorecard has required 'Scorebug' tab
- Tests data reading to ensure valid scorecard structure
**Storage**:
- Saves mapping in `data/scorecards.json`
- Persists across bot restarts
- Associates scorecard with text channel ID
**User Feedback**:
- Confirmation message with sheet title
- Usage instructions for `/scorebug` command
- Clear error messages for access issues
### `/scorebug [full_length]`
**Display Modes**:
- `full_length=True` (default): Complete scorebug with runners, matchups, and summary
- `full_length=False`: Compact view with just score and status
**Data Display**:
- Game header and inning information
- Score formatted in table
- Current game status (inning/half)
- Runners on base with positions
- Current matchups (optional)
- Game summary (optional)
- Team colors and thumbnails
**Error Handling**:
- Clear message if no scorecard published in channel
- Helpful errors for access or read failures
- Graceful handling of missing team data
### Live Score Updates (Background Task)
**Channel Updates**:
- Clears `#live-sba-scores` channel before each update
- Posts up to 10 scorebugs per message (Discord limit)
- Splits into multiple messages if needed
- Shows only active games (filters out finals)
**Voice Channel Integration**:
- Looks up voice channel associated with scorecard's text channel
- Updates voice channel `topic` with formatted score
- Format: `"{AWAY_ABBREV} {AWAY_SCORE} @ {HOME_SCORE} {HOME_ABBREV}"`
- Adds "- FINAL" when game completes
- Rate limits to avoid Discord API issues
## Architecture
### Service Layer Integration
**ScorebugService** (`services/scorebug_service.py`):
- Extends `SheetsService` for Google Sheets access
- Returns `ScorebugData` objects with parsed game information
- Supports both URL and key-based scorecard access
- Reads from 'Scorebug' tab (B2:S20) for game state
- Reads team IDs from 'Setup' tab (B5:B6)
**ScorebugData Fields**:
```python
{
'away_team_id': int,
'home_team_id': int,
'header': str, # Game header with inning info
'away_score': int,
'home_score': int,
'which_half': str, # Top/Bottom inning indicator
'is_final': bool,
'runners': list, # Runner info [position, name] pairs
'matchups': list, # Current batter/pitcher matchups
'summary': list # Game summary data
}
```
### Tracker Integration
**ScorecardTracker** stores:
```json
{
"scorecards": {
"123456789": {
"text_channel_id": "123456789",
"sheet_url": "https://docs.google.com/...",
"published_at": "2025-01-15T10:30:00",
"last_updated": "2025-01-15T10:35:00",
"publisher_id": "111222333"
}
}
}
```
**Voice Channel Association**:
- Voice tracker updated to store `text_channel_id` when voice channels created
- New method: `get_voice_channel_for_text_channel(text_channel_id)`
- Enables background task to update voice channel descriptions
### Command Flow
**Publishing Flow**:
1. User runs `/publish-scorecard <url>`
2. Bot validates access to Google Sheet
3. Bot verifies Scorebug tab exists
4. Bot reads sample data to ensure valid structure
5. Tracker stores text_channel_id → sheet_url mapping
6. User receives confirmation message
**Display Flow**:
1. User runs `/scorebug` in channel
2. Bot looks up scorecard URL from tracker
3. Bot reads current scorebug data from sheet
4. Bot fetches team information from API
5. Bot creates rich embed with game state
6. Bot updates tracker timestamp
**Background Update Flow**:
1. Task runs every 3 minutes
2. Reads all published scorecards from tracker
3. For each scorecard:
- Reads current scorebug data
- Checks if game is active (not final)
- Creates compact embed for live channel
- Checks for associated voice channel
- Updates voice channel description if found
4. Posts all active scorebugs to `#live-sba-scores`
5. Clears channel if no active games
## Configuration
### Channel Requirements
- **`#live-sba-scores`** - Live scorebug display channel (auto-updated every 3 minutes)
### Data Storage
- **`data/scorecards.json`** - Published scorecard mappings
- **`data/voice_channels.json`** - Voice channel tracking (includes text_channel_id)
### Google Sheets Requirements
Scorecards must have:
- **Scorebug tab**: Live game data (B2:S20)
- **Setup tab**: Team IDs (B5:B6)
- **Public read access**: "Anyone with the link can view"
## Error Handling
### Common Scenarios
- **Sheet not accessible**: Clear message about public permissions
- **Missing Scorebug tab**: Error indicating invalid scorecard structure
- **No scorecard published**: Helpful message to use `/publish-scorecard`
- **Sheet read failures**: Graceful degradation with retry suggestions
- **Voice channel deleted**: Silent skip (no errors to users)
- **Missing permissions**: Clear permission error messages
### Service Dependencies
- **Graceful degradation**: Commands work without background task
- **Rate limiting**: 1-second delay between scorecard reads
- **API failures**: Comprehensive error handling for external service calls
- **Discord errors**: Specific handling for Forbidden, NotFound, etc.
## Voice Channel Enhancement
### Text Channel Association
When voice channels are created via `/voice-channel`:
- Text channel ID stored in voice channel tracking data
- Enables scorebug → voice channel lookup
- Persistent across bot restarts
### Description Update Format
**Active Game**:
```
BOS 4 @ 3 NYY
```
**Final Game**:
```
BOS 5 @ 3 NYY - FINAL
```
**Implementation**:
- Uses voice channel `topic` field (description)
- Updates every 3 minutes with live scores
- Automatic cleanup when game ends
- No manual user interaction required
## Integration Points
### Bot Integration
- **Package Loading**: Integrated into `bot.py` command package loading sequence
- **Background Tasks**: Live scorebug tracker started in `_setup_background_tasks()`
- **Shutdown Handling**: Tracker stopped in `bot.close()`
### Service Layer
- **ScorebugService**: Google Sheets data extraction
- **TeamService**: Team information and logo lookups
- **ScorecardTracker**: Persistent scorecard-channel mapping
### Discord Integration
- **Application Commands**: Modern slash command interface
- **Embed Templates**: Consistent styling using `EmbedTemplate`
- **Error Handling**: Integration with global application command error handler
- **Voice Channels**: Bi-directional integration with voice channel system
## Usage Examples
### Publishing a Scorecard
```
/publish-scorecard https://docs.google.com/spreadsheets/d/ABC123/edit
```
**Result**: Scorecard linked to current channel for live tracking
### Using Just Sheet Key
```
/publish-scorecard ABC123DEF456
```
**Result**: Same functionality with cleaner input
### Displaying Scorebug
```
/scorebug
```
**Result**: Full scorebug display with all details
### Compact Scorebug
```
/scorebug full_length:False
```
**Result**: Just score and status, no runners/matchups/summary
## Monitoring and Logs
### Structured Logging
```python
self.logger.info(f"Published scorecard to channel {text_channel_id}: {sheet_url}")
self.logger.debug(f"Updated voice channel {voice_channel.name} description to: {description}")
self.logger.warning(f"Could not read scorecard {sheet_url}: {e}")
```
### Performance Tracking
- Background task execution timing
- Google Sheets read latency
- Voice channel update success rates
- Scorecard access failure rates
## Future Enhancements
### Potential Features
- **Scorecard rotation**: Multiple scorecard support per channel
- **Custom refresh intervals**: User-configurable update frequency
- **Notification system**: Alerts for game events (runs, innings, etc.)
- **Statistics tracking**: Historical scorebug access patterns
- **Mobile optimization**: Compact embeds for mobile viewing
### Configuration Options
- **Per-channel settings**: Different update intervals per channel
- **Role permissions**: Restrict scorecard publishing to specific roles
- **Format customization**: User-selectable scorebug styles
- **Alert thresholds**: Configurable notification triggers
---
**Last Updated**: January 2025
**Architecture**: Modern async Discord.py with Google Sheets integration
**Dependencies**: discord.py, pygsheets, ScorebugService, ScorecardTracker, VoiceChannelTracker