strat-gameplay-webapp/.claude/status-2025-10-22-0113.md
Cal Corum a287784328 CLAUDE: Complete Week 4 - State Management & Persistence
Implemented hybrid state management system with in-memory game states and async
PostgreSQL persistence. This provides the foundation for fast gameplay (<500ms
response) with complete state recovery capabilities.

## Components Implemented

### Production Code (3 files, 1,150 lines)
- app/models/game_models.py (492 lines)
  - Pydantic GameState with 20+ helper methods
  - RunnerState, LineupPlayerState, TeamLineupState
  - DefensiveDecision and OffensiveDecision models
  - Full Pydantic v2 validation with field validators

- app/core/state_manager.py (296 lines)
  - In-memory state management with O(1) lookups
  - State recovery from database
  - Idle game eviction mechanism
  - Statistics tracking

- app/database/operations.py (362 lines)
  - Async PostgreSQL operations
  - Game, lineup, and play persistence
  - Complete state loading for recovery
  - GameSession WebSocket state tracking

### Tests (4 files, 1,963 lines, 115 tests)
- tests/unit/models/test_game_models.py (60 tests, ALL PASSING)
- tests/unit/core/test_state_manager.py (26 tests, ALL PASSING)
- tests/integration/database/test_operations.py (21 tests)
- tests/integration/test_state_persistence.py (8 tests)
- pytest.ini (async test configuration)

### Documentation (6 files)
- backend/CLAUDE.md (updated with Week 4 patterns)
- .claude/implementation/02-week4-state-management.md (marked complete)
- .claude/status-2025-10-22-0113.md (planning session summary)
- .claude/status-2025-10-22-1147.md (implementation session summary)
- .claude/implementation/player-data-catalog.md (player data reference)
- Week 5 & 6 plans created

## Key Features

- Hybrid state: in-memory (fast) + PostgreSQL (persistent)
- O(1) state access via dictionary lookups
- Async database writes (non-blocking)
- Complete state recovery from database
- Pydantic validation on all models
- Helper methods for common game operations
- Idle game eviction with configurable timeout
- 86 unit tests passing (100%)

## Performance

- State access: O(1) via UUID lookup
- Memory per game: ~1KB (just state)
- Target response time: <500ms 
- Database writes: <100ms (async) 

## Testing

- Unit tests: 86/86 passing (100%)
- Integration tests: 29 written
- Test configuration: pytest.ini created
- Fixed Pydantic v2 config deprecation
- Fixed pytest-asyncio configuration

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-22 12:01:03 -05:00

618 lines
20 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Session Summary: Phase 2 Game Engine Planning
**Date**: 2025-10-22
**Time**: ~23:00 - 01:13
**Duration**: ~2 hours
**Branch**: `implement-phase-2`
**Status**: Planning Complete ✅ - Ready to Begin Implementation
---
## Session Overview
### Primary Objectives
1. Plan Phase 2: Game Engine Core implementation (Weeks 4-6)
2. Design in-memory state management architecture
3. Document all player data fields for caching
4. Create detailed weekly implementation plans
### Technologies Involved
- **Backend**: FastAPI, Python 3.13, Pydantic, SQLAlchemy (async)
- **Database**: PostgreSQL (10.10.0.42:5432)
- **State Management**: In-memory Python dictionaries + async DB persistence
- **Testing**: pytest, automated Python tests
### Overall Outcome
**Successfully completed comprehensive planning for Phase 2**
- Created 4 detailed planning documents
- Resolved key architectural questions about state caching
- Documented complete player data model from Discord bot
- Established "measure twice, cut once" approach
- Ready to begin Week 4 implementation
---
## Current State
### Active Todos (from TodoWrite)
**Completed:**
1. ✅ Create detailed Phase 2 implementation plan documents
2. ✅ Document all player data fields to cache in memory
**In Progress:**
3. 🔄 Review player data catalog and supplement with any missing fields
**Pending (Week 4):**
4. ⏳ Week 4: Create Pydantic game state models with rich player cache
5. ⏳ Week 4: Implement State Manager (in-memory game state)
6. ⏳ Week 4: Implement database operations layer
7. ⏳ Week 4: Build state recovery mechanism
**Pending (Week 5):**
8. ⏳ Week 5: Implement cryptographic dice system
9. ⏳ Week 5: Build play resolver (simplified charts)
10. ⏳ Week 5: Create game engine core logic
11. ⏳ Week 5: Implement rule validators
**Pending (Week 6):**
12. ⏳ Week 6: Create polymorphic player model architecture
13. ⏳ Week 6: Implement league configuration system
14. ⏳ Week 6: Build result charts (d20 tables)
15. ⏳ Week 6: Create league API client
16. ⏳ Week 6: End-to-end testing of complete at-bat flow
### Running Services
- Backend FastAPI: Multiple instances running on port 8000 (multiple background processes)
- Frontend SBA: Running on port 3000
- Frontend PD: Running on port 3001
### Git Status
```
Branch: implement-phase-2
Modified: .claude/implementation/02-game-engine.md
Recent commits:
d8a43fa - CLAUDE: Complete Phase 1 - Frontend Infrastructure Setup
fc7f53a - CLAUDE: Complete Phase 1 backend infrastructure setup
5c75b93 - CLAUDE: Initial project setup - documentation and infrastructure
```
### Key Files Being Worked On
- `.claude/implementation/02-game-engine.md` (updated with approach)
- `.claude/implementation/02-week4-state-management.md` (created)
- `.claude/implementation/02-week5-game-logic.md` (created)
- `.claude/implementation/02-week6-league-features.md` (created)
- `.claude/implementation/player-data-catalog.md` (created)
---
## Changes Made
### Files Created
1. **`.claude/implementation/02-week4-state-management.md`**
- Comprehensive Week 4 implementation plan
- Pydantic game state models specification
- StateManager class design
- DatabaseOperations async layer
- State recovery mechanism
- Complete test specifications
2. **`.claude/implementation/02-week5-game-logic.md`**
- Week 5 implementation plan
- DiceSystem with cryptographic RNG
- PlayResolver with simplified charts
- GameEngine orchestration
- Rule validators
- Integration test framework
3. **`.claude/implementation/02-week6-league-features.md`**
- Week 6 implementation plan
- Polymorphic player models (BasePlayer → SbaPlayer/PdPlayer)
- League configuration system
- Result charts for SBA and PD
- LeagueApiClient implementation
- End-to-end testing strategy
4. **`.claude/implementation/player-data-catalog.md`**
- **CRITICAL REFERENCE**: Complete player data field specifications
- Batting card data (8 basic fields + 54 rating values per player)
- Pitching card data (7 basic fields + 60 rating values per player)
- Defensive ratings (5 fields per position, multi-position support)
- Memory usage analysis (~500-700 bytes per player)
- Usage examples for gameplay scenarios
- Data loading and caching strategies
### Files Modified
1. **`.claude/implementation/02-game-engine.md`** (lines 171-209)
- Added "Implementation Approach" section
- Documented key decisions from user
- Added links to detailed weekly plans
- Updated status to "In Progress - Planning Complete"
### No Code Files Created/Modified
This session was **planning only** - no implementation code written yet.
---
## Key Decisions & Discoveries
### Architectural Decision: Rich In-Memory Caching
**Decision**: Cache complete player objects with ALL ratings in memory, not minimal state.
**Rationale** (from Discord bot experience):
- Gameplay requires frequent access to:
- Player images for display
- Defensive ratings for x-checks (unpredictable position)
- Catcher passed ball / pitcher wild pitch for chaos rolls
- Stealing ratings, bunting ratings, etc.
- Memory cost is negligible: ~10-15KB per game (20 players × ~500-700 bytes)
- 100 concurrent games = < 2MB total
- Discord bot suffered from slow DB queries - this solves that
**Pattern Established**:
```python
class CachedPlayer(BaseModel):
# Complete player data cached
- Identity & display (12 fields)
- Batting attributes (8 fields)
- Batting ratings vL and vR (54 values total)
- Pitching attributes (7 fields)
- Pitching ratings vL and vR (60 values total)
- Defense ratings per position (Dict[str, DefenseRatings])
# Cache in GameState
home_lineup: Dict[int, CachedPlayer] # {lineup_id: player}
away_lineup: Dict[int, CachedPlayer]
```
### Decision: SBA First, PD Second
**Approach**: Build each component for SBA league first, learn lessons, apply to PD.
**Rationale**:
- SBA is simpler (fewer fields, manual result selection)
- PD adds complexity (auto-selection via scouting model)
- Ensures base case works before adding complexity
- Matches user's request
### Decision: Automated Python Testing (No WebSocket UI Tests in Phase 2)
**Approach**: Test via Python scripts and unit/integration tests, not through UI.
**Benefits**:
- Faster iteration during development
- Easier to debug game logic
- Can test edge cases more thoroughly
- UI testing comes in Phase 3
**Test Script Pattern**:
```python
# scripts/test_game_flow.py
async def test_at_bat():
state = await state_manager.create_game(...)
await game_engine.start_game(game_id)
await game_engine.submit_defensive_decision(...)
await game_engine.submit_offensive_decision(...)
result = await game_engine.resolve_play(game_id)
```
### Decision: Hybrid State Management
**Pattern**:
```
User Action → WebSocket → Game Engine
Update In-Memory State (fast, <200ms)
Async Write to PostgreSQL (non-blocking, <100ms)
Broadcast via WebSocket
```
**Data Consistency Strategy**:
- In-memory state is source of truth for active games
- Database is async backup + historical record
- On crash: Recover from DB plays, rebuild in-memory cache
- Write-through cache pattern
### Discovery: Discord Bot Data Model Complexity
**Finding**: Paper Dynasty Discord bot has extensive player data:
- **Batting**: 27 rating fields × 2 platoon splits (vs LHP/RHP) = 54 values
- **Pitching**: 30 rating fields × 2 platoon splits (vs LHB/RHB) = 60 values
- **Defense**: Multi-position support (player can have ratings for 2-8 positions)
- **Chaos Events**: Wild pitch, passed ball, balk, pickoff ratings
- **X-Checks**: 9 position-specific x-check probabilities on pitcher cards
**Implication**: Must cache ALL this data for fast gameplay. Initial "minimal state" approach would have failed.
### Pattern: Result Selection Models
**SBA League**:
- Players see dice roll FIRST
- Select from available results on chart
- Manual decision required
**PD League**:
- Flexible approach
- Manual selection OR auto-resolution via scouting model
- Scouting model uses detailed BattingCardRatings/PitchingCardRatings
---
## Problems & Solutions
### Problem: Initial Architecture Too Simple
**Issue**: Original plan had minimal in-memory state (just current batter ID, outs, score).
**Discovery**: User explained real gameplay needs:
- "On each play there is a chance for a chaos roll if there are baserunners - need catcher passed_ball and pitcher wild_pitch"
- "X-check plays require calling <RandomDefender>.range and .error values"
- "Need to display player images for batter, runners, pitcher, catcher"
**Solution**: Switched to rich player caching with complete data model.
**Lesson**: Real-world production experience (Discord bot) revealed requirements that weren't obvious from specs.
### Problem: Unclear Data Requirements
**Issue**: Didn't know all the fields that needed to be cached.
**Solution**: Deep dive into Discord bot codebase:
- Read `paper-dynasty/database/app/routers_v2/battingcards.py`
- Read `paper-dynasty/database/app/routers_v2/pitchingcards.py`
- Read `paper-dynasty/database/app/routers_v2/battingcardratings.py`
- Read `paper-dynasty/database/app/routers_v2/pitchingcardratings.py`
- Read `paper-dynasty/database/app/routers_v2/cardpositions.py`
- Read `paper-dynasty/database/app/routers_v2/players.py`
**Result**: Created comprehensive `player-data-catalog.md` documenting all 100+ fields.
### Problem: Performance vs Consistency Trade-off
**Issue**: How to balance fast gameplay with data consistency?
**Solution**: Async write-through cache
- In-memory cache updated synchronously (fast)
- Database write happens asynchronously (non-blocking)
- On crash, rebuild from database plays
**Guarantees**:
- Response time < 500ms (in-memory reads)
- Data persisted within seconds (async writes)
- Full recovery possible from database
---
## Technology Context
### Database Server
- **Location**: `10.10.0.42:5432`
- **Database**: `paperdynasty_dev`
- **User**: `paperdynasty`
- **Connection**: `postgresql+asyncpg://paperdynasty:PASSWORD@10.10.0.42:5432/paperdynasty_dev`
### Python Environment
- **Version**: Python 3.13.3
- **Virtual Env**: `backend/venv/`
- **Activation**: `source venv/bin/activate` (from backend directory)
### Critical Dependencies
- **Pydantic**: v2.10.6 (data validation)
- **SQLAlchemy**: v2.0.36 (async ORM)
- **asyncpg**: v0.30.0 (PostgreSQL async driver)
- **Pendulum**: v3.0.0 (datetime - ALWAYS use instead of Python datetime)
- **greenlet**: Required for SQLAlchemy async
### League API References
- **SBA API**: Integration pending (Week 6)
- **PD API**: Discord bot at `/mnt/NV2/Development/paper-dynasty/database/`
### Database Models (Phase 1 Complete)
- `Game`: UUID primary key, AI support, team tracking
- `Play`: 25+ statistics fields, player FKs, on_base_code bit field
- `Lineup`: Substitution tracking, fatigue flags
- `GameCardsetLink`: PD cardset validation
- `RosterLink`: PD roster management
- `GameSession`: WebSocket state tracking
---
## Next Steps
### Immediate Actions (User Review Required)
1. **Review Player Data Catalog** (`.claude/implementation/player-data-catalog.md`)
- Check for missing fields
- Verify field types
- Confirm usage scenarios
- Answer questions at end of document
2. **Answer Architecture Questions**:
- **Variant Cards**: Are these different versions of same player in same game?
- **Offensive Column**: What is `offense_col` used for?
- **SBA Simplifications**: Cache ratings or truly use simplified charts?
- **Scouting Data**: Is BattingCardRatings the scouting data or separate?
### Once Review Complete → Begin Week 4
**First Implementation Task**: Create Pydantic game state models
- Location: `backend/app/models/game_models.py`
- Models needed:
- `CachedPlayer` (complete player with all ratings)
- `BattingAttributes`, `BattingRatings`
- `PitchingAttributes`, `PitchingRatings`
- `DefensivePosition`
- `GameState` (with rich lineup caches)
- `RunnerState`, decision models
**Test First**: Write unit tests before implementation
- `tests/unit/models/test_game_models.py`
- Test model validation
- Test helper methods
- Test platoon split lookups
### Week 4 Complete Deliverables
- Pydantic models with full player data
- StateManager with in-memory game states
- DatabaseOperations for async persistence
- State recovery from database
- All tests passing
### Week 5-6 (After Week 4)
Follow plans in:
- `.claude/implementation/02-week5-game-logic.md`
- `.claude/implementation/02-week6-league-features.md`
---
## Reference Information
### Critical Planning Documents
1. **`.claude/implementation/02-game-engine.md`**
- Phase 2 overview
- Implementation approach and decisions
- Links to weekly plans
2. **`.claude/implementation/02-week4-state-management.md`**
- Complete Week 4 plan with code examples
- Pydantic models specification
- StateManager design
- Database operations layer
- Testing strategy
3. **`.claude/implementation/02-week5-game-logic.md`**
- Dice system (cryptographic d20 rolls)
- Play resolver with result charts
- Game engine orchestration
- Rule validators
- Integration tests
4. **`.claude/implementation/02-week6-league-features.md`**
- Polymorphic player models
- League configurations (SBA vs PD)
- Result charts
- API client
- E2E testing
5. **`.claude/implementation/player-data-catalog.md`** **MOST CRITICAL**
- Complete field specifications for caching
- Memory usage analysis
- Usage examples
- Loading strategies
- **MUST READ before implementing models**
### Discord Bot Reference Locations
**Player Data Models**:
- `/mnt/NV2/Development/paper-dynasty/database/app/routers_v2/players.py:35-62` - PlayerPydantic
- `/mnt/NV2/Development/paper-dynasty/database/app/routers_v2/battingcards.py:22-33` - BattingCardModel
- `/mnt/NV2/Development/paper-dynasty/database/app/routers_v2/pitchingcards.py:22-33` - PitchingCardModel
- `/mnt/NV2/Development/paper-dynasty/database/app/routers_v2/cardpositions.py:22-39` - CardPositionModel
- `/mnt/NV2/Development/paper-dynasty/database/app/routers_v2/battingcardratings.py:29-60` - BattingCardRatingsModel
- `/mnt/NV2/Development/paper-dynasty/database/app/routers_v2/pitchingcardratings.py:28-61` - PitchingCardRatingsModel
### Existing Backend Structure
**Database Models** (Phase 1 Complete):
- `backend/app/models/db_models.py:34-70` - Game model
- `backend/app/models/db_models.py:72-205` - Play model (extensive stats)
- `backend/app/models/db_models.py:207-233` - Lineup model
- `backend/app/models/db_models.py:10-20` - GameCardsetLink
- `backend/app/models/db_models.py:22-31` - RosterLink
- `backend/app/models/db_models.py:235-246` - GameSession
**Backend Infrastructure** (Phase 1 Complete):
- `backend/app/main.py` - FastAPI app with Socket.io
- `backend/app/config.py` - Settings with Pydantic
- `backend/app/database/session.py` - Async database session
- `backend/app/websocket/connection_manager.py` - WebSocket lifecycle
- `backend/app/websocket/handlers.py` - Socket.io event handlers
- `backend/app/utils/logging.py` - Rotating logger setup
**Empty Directories Ready for Phase 2**:
- `backend/app/core/` - Game engine, state manager, play resolver
- `backend/app/config/` - League configs (currently just app config)
- `backend/app/data/` - API client
### Important Patterns from CLAUDE.md
**DateTime Handling** - ALWAYS use Pendulum:
```python
import pendulum
now = pendulum.now('UTC') # ✅ Correct
formatted = now.format('YYYY-MM-DD HH:mm:ss')
# ❌ NEVER use:
from datetime import datetime
```
**Logging Pattern**:
```python
import logging
logger = logging.getLogger(f'{__name__}.ClassName')
logger.info(f"Message with context: {variable}")
```
**Error Handling** - "Raise or Return" pattern:
```python
# ✅ Raise exceptions for errors
def get_player(player_id: int) -> Player:
player = find_player(player_id)
if not player:
raise ValueError(f"Player {player_id} not found")
return player
# ❌ Don't return Optional unless specifically required
def get_player(player_id: int) -> Optional[Player]: # Avoid this
```
**Git Commits** - Prefix with "CLAUDE: ":
```bash
git commit -m "CLAUDE: Implement Week 4 state manager"
```
### Common Operations
**Start Backend**:
```bash
cd /mnt/NV2/Development/strat-gameplay-webapp/backend
source venv/bin/activate
python -m app.main
# Available at http://localhost:8000
# API docs at http://localhost:8000/docs
```
**Run Tests**:
```bash
cd /mnt/NV2/Development/strat-gameplay-webapp/backend
source venv/bin/activate
pytest tests/ -v
pytest tests/unit/models/test_game_models.py -v # Specific test
```
**Database Connection Test**:
```bash
psql postgresql://paperdynasty:PASSWORD@10.10.0.42:5432/paperdynasty_dev
```
---
## Performance Targets (Phase 2)
**Critical Metrics**:
- Action response: < 500ms (user action state update)
- WebSocket delivery: < 200ms
- Database write: < 100ms (async, non-blocking)
- State recovery: < 2 seconds (rebuild from DB)
- Concurrent games: 10+ simultaneous active games
- Memory per game: ~10-15KB (20 cached players)
**How We'll Achieve Them**:
- In-memory state (no DB queries during plays)
- Async database writes (non-blocking)
- Lightweight Pydantic models (fast serialization)
- Efficient state recovery (single query with joins)
---
## Architecture Summary
### The "Two-Model" Pattern
**In-Memory (Pydantic)**:
```python
class GameState(BaseModel):
# Fast, lightweight, optimized for game logic
game_id: UUID
inning: int
outs: int
home_score: int
away_score: int
home_lineup: Dict[int, CachedPlayer] # Complete player data
away_lineup: Dict[int, CachedPlayer]
runners: List[RunnerState]
current_batter_id: int
# ...
```
**Database (SQLAlchemy)**:
```python
class Game(Base):
# Persistent, complete, auditable
id = Column(UUID, primary_key=True)
league_id = Column(String)
current_inning = Column(Integer)
home_score = Column(Integer)
# Relationships
plays = relationship("Play", cascade="all, delete-orphan")
lineups = relationship("Lineup", cascade="all, delete-orphan")
# ...
```
**Why Both?**:
- Pydantic: Fast reads, easy WebSocket serialization, optimized structure
- SQLAlchemy: Persistence, relationships, audit trail, crash recovery
**Translation Layer**: StateManager handles conversion between models
---
## Questions for User (Awaiting Answers)
1. **Variant Cards**: I saw `variant: int = 0` in batting/pitching card models. Are variants different versions of the same player that could be in the same game simultaneously? Or are they alternate ratings for different seasons?
2. **Offensive Column**: What is `offense_col` (BattingCard, PitchingCard) used for? Is this for result chart lookups or something else?
3. **SBA Simplifications**: For SBA league, should we:
- Option A: Still cache BattingCardRatings/PitchingCardRatings but use simplified result selection
- Option B: Truly simplify and not cache detailed ratings at all
4. **Scouting Data**: The PRD mentions "scouting data" for PD. Is the detailed `BattingCardRatings` / `PitchingCardRatings` (with all the probability fields) THE scouting data, or is there additional scouting information beyond those rating tables?
5. **Missing Fields**: Are there any player attributes or ratings used in gameplay that aren't captured in the player-data-catalog.md document?
---
## Success Criteria - Phase 2 Complete
By end of Phase 2, we will have:
- [x] Comprehensive planning documents (THIS SESSION)
- [ ] In-memory game state management working
- [ ] Play resolution engine with dice rolls
- [ ] League configuration system (SBA and PD configs)
- [ ] Polymorphic player models (BasePlayer, SbaPlayer, PdPlayer)
- [ ] Database persistence layer with async operations
- [ ] State recovery mechanism from database
- [ ] Basic game flow (start plays end)
- [ ] Complete ONE at-bat for SBA league
- [ ] Complete ONE at-bat for PD league
- [ ] All unit tests passing (90%+ coverage)
- [ ] All integration tests passing
- [ ] Dice distribution verified as uniform
- [ ] Performance targets met (<500ms response)
---
## Final Status
**Planning Phase: COMPLETE**
**Ready to Begin**: Week 4 - State Management & Persistence
**Blockers**: None - awaiting user review of player-data-catalog.md
**Confidence Level**: High - comprehensive planning with proven Discord bot reference
**Next Session**: Implement Pydantic game state models after user review
---
**Session saved**: 2025-10-22 01:13
**Document**: `.claude/status-2025-10-22-0113.md`