From 0b56b89a0b43c7b01883f3b873bb463ff44b77f1 Mon Sep 17 00:00:00 2001 From: Cal Corum Date: Sat, 1 Nov 2025 01:17:45 -0500 Subject: [PATCH] Update NEXT_SESSION.md Context includes completing week 7 work and planning week 8 work. --- .claude/implementation/NEXT_SESSION.md | 1017 ++++++++++++++++++------ 1 file changed, 754 insertions(+), 263 deletions(-) diff --git a/.claude/implementation/NEXT_SESSION.md b/.claude/implementation/NEXT_SESSION.md index 9b7e99e..8d6d618 100644 --- a/.claude/implementation/NEXT_SESSION.md +++ b/.claude/implementation/NEXT_SESSION.md @@ -1,324 +1,815 @@ -# Next Session Plan - Week 8: Substitutions & Advanced Gameplay +# Next Session Plan - Week 7 Complete, Ready for Week 8 -**Current Status**: Phase 3 - Week 7 Complete (100%) โœ… โ†’ Starting Week 8 -**Last Commit**: `4cf349a` - "CLAUDE: Update NEXT_SESSION.md - Week 7 complete at 100%" +**Current Status**: Phase 3 - Week 7 COMPLETE (100%) โœ… +**Last Commit**: `a696473` - "CLAUDE: Integrate flyball advancement with RunnerAdvancement system" **Date**: 2025-10-31 -**Next Priority**: Week 8 - Player substitutions, pitching changes, and game management features - ---- - -## ๐ŸŽ‰ Week 7 Summary - COMPLETE! - -**All 8 tasks completed successfully:** - -### Task 1: Strategic Decision Integration โœ… -- Async decision workflow with `asyncio.Future` -- Defensive decision queue: alignment, infield/outfield depth, hold runners -- Offensive decision queue: approach, steal attempts, bunting -- Full integration with GameEngine - -### Task 2: Decision Validators โœ… (54 tests) -- DefensiveDecision validation: positioning rules, depth requirements -- OffensiveDecision validation: steal/bunt prerequisites -- Lineup validation: complete defensive positioning -- Game flow validation: inning/out state checks - -### Task 3: Result Charts + PD Auto Mode โœ… (21 tests) -- `ResultChart` abstract base class -- `PdAutoResultChart` for auto-generated outcomes -- `ManualResultChart` for player submissions -- `calculate_hit_location()` helper (pull rates, handedness) -- `ManualOutcomeSubmission` validation model - -### Task 4: Runner Advancement Logic โœ… (30 tests) -- `RunnerAdvancement` class with 13 result types -- Infield Back chart (default positioning) -- Infield In chart (runner on 3rd) -- Corners In positioning (hybrid approach) -- Full groundball outcome resolution - -### Task 5: Double Play Mechanics โœ… -- Integrated into Task 4 `RunnerAdvancement` -- Base probability: 45% with modifiers -- Positioning: Infield In (-15%), Normal (0%) -- Hit location: Middle infield (+10%), Corners (-10%) -- Probabilistic execution (not deterministic) - -### Task 6: PlayResolver Integration โœ… (9 tests) -- **Outcome-first architecture** - Manual mode is primary -- `resolve_outcome()` core method - all game logic -- `resolve_manual_play()` wrapper for player submissions -- `resolve_auto_play()` wrapper for PD auto mode -- RunnerAdvancement integrated for all groundballs -- `hit_location` tracked in `PlayResult` -- Removed obsolete `SimplifiedResultChart` and singleton - -### Task 7: WebSocket Manual Outcome Handlers โœ… (12 tests) -- `roll_dice` event: Server rolls, broadcasts to players -- `submit_manual_outcome` event: Players submit after reading cards -- `GameEngine.resolve_manual_play()` orchestration -- Terminal client commands: `roll_dice`, `manual_outcome` - -### Task 8: Terminal Client Enhancement โœ… -- Manual outcome submission commands -- Full REPL integration -- Testing without frontend - -### Testing Summary -- **180/181 core tests passing** (1 pre-existing failure in dice history) -- **126 new tests for Week 7** - all passing -- **Manual testing**: 8/8 scenarios verified โœ… - ---- - -## ๐Ÿš€ Week 8: Substitutions & Advanced Gameplay - -**Focus**: Player substitutions, pitching management, and advanced game features - -### Planned Tasks - -#### Task 1: Substitution System -- **Pinch hitters** - Replace batter mid-at-bat or in lineup -- **Pinch runners** - Replace runner on base -- **Defensive replacements** - Swap fielders -- **Database tracking**: `replacing_id`, `after_play`, `entered_inning` -- **Validation**: DH rules, position eligibility, one-way substitutions - -#### Task 2: Pitching Changes -- **Relief pitcher** - Bring in from bullpen -- **Pitching fatigue** - Track pitch count and `is_fatigued` flag -- **Bullpen management** - Available relievers, warmup status -- **Closer/setup roles** - Strategic substitution timing - -#### Task 3: Advanced Game Rules -- **Steal attempts** - Use OffensiveDecision.steal_attempts -- **Caught stealing resolution** - JumpRoll mechanics -- **Pick-off attempts** - Pitcher vs runner -- **Balk detection** - Using chaos_d20 rolls - -#### Task 4: Game State Persistence -- **Save/load functionality** - Store/restore game mid-play -- **Replay system** - Rebuild state from play history -- **Recovery on crash** - Automatic state reconstruction - -#### Task 5: Enhanced Terminal Client -- **Substitution commands** - `pinch_hit`, `pinch_run`, `defensive_sub` -- **Pitching commands** - `change_pitcher`, `bullpen_status` -- **Better status display** - Show fatigue, available subs +**Remaining Work**: Week 8 - Substitutions & Advanced Gameplay (0% complete) --- ## Quick Start for Next AI Agent -### ๐ŸŽฏ Where to Begin (Week 8) +### ๐ŸŽฏ Where to Begin +1. Read this entire document first +2. Review the "What We Just Completed" section to understand recent flyball work +3. Review files in "Files to Review Before Starting" section +4. Start with Task 1 in "Tasks for Next Session" (Week 8) +5. Run test commands after each task -1. **Read Week 8 plan** (to be created): `@.claude/implementation/WEEK_8_PLAN.md` -2. **Review database models**: `@app/models/db_models.py` - - Check `Lineup` model: `replacing_id`, `after_play`, `is_fatigued` fields - - These are already in place from Phase 1! -3. **Start with Task 1**: Substitution system - - Create `SubstitutionManager` class - - Implement pinch hitter logic first (simplest case) - - Add validation rules +### ๐Ÿ“ Current Context -### ๐Ÿ“ Current Architecture (Week 7 Complete) +Week 7 is **100% complete** including the major flyball advancement integration completed in this session. The runner advancement system now handles BOTH groundballs (13 result types) AND flyballs (4 types) through a unified interface. PlayResolver has been refactored to delegate all runner movement to RunnerAdvancement, eliminating duplicate code. State recovery has been fixed to properly reconstruct LineupPlayerState objects from database. -**Game Engine Flow**: +**Next priority**: Week 8 - Substitution system (pinch hitters, pinch runners, pitching changes) + +--- + +## What We Just Completed โœ… + +### 1. Flyball Advancement System (Major Refactor) + - **Files Modified**: + - `backend/app/config/result_charts.py` - Added FLYOUT_BQ variant + - `backend/app/core/runner_advancement.py` - Extended to handle flyballs + - `backend/app/core/play_resolver.py` - Refactored to delegate flyballs to RunnerAdvancement + - `backend/app/core/state_manager.py` - Fixed state recovery + - `backend/app/core/CLAUDE.md` - Comprehensive flyball documentation + + **Implementation Details**: + - Added `FLYOUT_BQ` (medium-shallow) to existing flyball types (A, B, C) + - Now 4 flyball depths with clear semantics: + - **FLYOUT_A** (Deep): All runners tag up and advance one base + - **FLYOUT_B** (Medium): R3 scores, R2 may attempt tag (DECIDE), R1 holds + - **FLYOUT_BQ** (Medium-shallow): R3 may attempt to score (DECIDE), R2 holds, R1 holds + - **FLYOUT_C** (Shallow): No advancement, all runners hold + - `RunnerAdvancement.advance_runners()` now routes to either `_advance_runners_groundball()` or `_advance_runners_flyball()` + - Comprehensive flyball logic with proper DECIDE mechanics per type + - No-op movements recorded for state recovery consistency + + **Testing**: 21 new tests in `test_flyball_advancement.py` - all passing โœ… + +### 2. PlayResolver DRY Refactoring + - Consolidated all 4 flyball outcomes to delegate to RunnerAdvancement + - Eliminated duplicate flyball resolution code (~40 lines removed) + - Renamed helpers for clarity: + - `_advance_on_single()` โ†’ `_advance_on_single_1()` and `_advance_on_single_2()` + - `_advance_on_double()` โ†’ `_advance_on_double_2()` and `_advance_on_double_3()` + - Fixed single/double advancement logic for different hit types + +### 3. State Recovery Fix + - Fixed `state_manager.py` game recovery to build `LineupPlayerState` objects properly + - Added `get_lineup_player()` helper to construct from lineup data + - Correctly tracks runners in `on_first`/`on_second`/`on_third` fields + - Matches Phase 2 model architecture (direct base references vs list) + +### 4. Database Support + - Added runner tracking fields to play data for accurate recovery + - Includes `batter_id`, `on_first_id`, `on_second_id`, `on_third_id`, and `*_final` fields + - Enables state reconstruction from database after server restart + +### 5. Type Safety Improvements + - Fixed `lineup_id` access throughout `runner_advancement.py` + - Was accessing `on_first` directly, now properly accesses `on_first.lineup_id` + - Made `current_batter_lineup_id` non-optional (always set by `_prepare_next_play`) + - Added `# type: ignore` comments for known SQLAlchemy false positives + +### 6. Documentation + - Updated `backend/app/core/CLAUDE.md` with comprehensive flyball documentation + - Added flyball types table, usage examples, and test coverage notes + - Documented differences between groundball and flyball mechanics + - 51 new lines of documentation + +--- + +## Key Architecture Decisions Made + +### 1. **Unified Runner Advancement System** + - **Decision**: Extend RunnerAdvancement to handle both groundballs AND flyballs instead of keeping separate logic + - **Rationale**: + - DRY principle - eliminates code duplication in PlayResolver + - Single source of truth for runner movement + - Consistent interface for all outcome types + - Easier to test and maintain + - **Implementation**: Route method `_advance_runners_groundball()` vs `_advance_runners_flyball()` based on outcome type + +### 2. **Four Flyball Depths** + - **Decision**: Add FLYOUT_BQ as fourth flyball variant (was 3, now 4) + - **Rationale**: + - Physical cards show "fly(b)?" outcomes distinct from "fly(b)" + - Different advancement rules: BQ has R3 DECIDE vs B has R2 DECIDE + - More accurate simulation of card-based gameplay + - **Impact**: More granular runner advancement logic, better matches physical gameplay + +### 3. **Direct Base References for State Recovery** + - **Decision**: Use `on_first`, `on_second`, `on_third` fields instead of `runners: List[RunnerState]` + - **Rationale**: + - Matches database structure exactly (Play table has `on_first_id`, etc.) + - Simpler state management (direct assignment vs list operations) + - Better type safety (LineupPlayerState vs generic runner) + - No list management overhead + - **Status**: Implemented in Phase 2, recovery logic fixed in this session + +### 4. **No-op Movement Recording** + - **Decision**: Record runner "hold" movements even when they don't advance + - **Rationale**: + - State recovery needs complete movement list + - Distinguishes "held at base" from "wasn't on base" + - Consistent with groundball advancement logic + - **Example**: FLYOUT_C with R1, R2, R3 records 3 movements (all from_base X to_base X) + +--- + +## Blockers Encountered ๐Ÿšง + +None - development proceeded smoothly. The flyball integration was a major refactor but went cleanly. + +--- + +## Outstanding Questions โ“ + +### 1. **DECIDE Mechanics Implementation** + - **Question**: Should DECIDE tag-up attempts be: + - (A) Fully automated based on arm strength + runner speed probabilities? + - (B) Interactive decision presented to offensive player? + - (C) Mix: Auto in auto-mode, interactive in manual mode? + - **Context**: Currently defaults to "hold" for DECIDE scenarios + - **Impact**: Affects gameplay realism and player agency + - **Recommendation**: Defer to Week 9 (Advanced Rules) - current default behavior is safe + +### 2. **Hit Location for Flyballs** + - **Question**: Do we need more granular location tracking (shallow LF vs deep LF)? + - **Context**: Currently just track LF/CF/RF, depth is implicit in outcome type + - **Impact**: Future feature for arm strength calculations in DECIDE scenarios + - **Recommendation**: Current implementation sufficient for Week 8 + +--- + +## Tasks for Next Session + +### Week 8 Focus: Substitution System & Pitching Management + +--- + +### Task 1: Create SubstitutionManager Class (2 hours) + +**File(s)**: `backend/app/core/substitution_manager.py` (NEW) + +**Goal**: Implement core substitution logic for pinch hitters, pinch runners, and defensive replacements. + +**Changes**: +1. Create `SubstitutionManager` class with methods: + - `pinch_hit(game_id, batting_order_pos, new_lineup_id)` โ†’ Updates lineup + - `pinch_run(game_id, base, new_lineup_id)` โ†’ Replaces runner on base + - `defensive_replacement(game_id, position, new_lineup_id)` โ†’ Swaps fielder + - `validate_substitution(game_id, sub_type, ...)` โ†’ Checks eligibility + +2. Track substitution metadata: + - `replacing_id`: Lineup ID being replaced + - `after_play`: Play number when sub occurred + - `entered_inning`: Inning when sub entered + - `is_active`: Set old player to False, new to True + +3. Handle special cases: + - DH rules (American League style) + - Position eligibility validation + - One-way substitution (can't re-enter) + +**Files to Create**: +- `backend/app/core/substitution_manager.py`: ```python -# Manual mode (SBA + PD manual) -GameEngine.resolve_manual_play( - game_id, ab_roll, outcome, hit_location -) โ†’ PlayResult +""" +Player substitution management. -# Auto mode (PD only) -GameEngine.resolve_play(game_id) โ†’ PlayResult +Handles pinch hitters, pinch runners, defensive replacements, and pitching changes. +Validates substitution rules and tracks metadata. +""" + +from typing import Optional +from uuid import UUID +import logging + +from app.database.operations import DatabaseOperations +from app.core.state_manager import StateManager +from app.models.game_models import GameState, LineupPlayerState + +logger = logging.getLogger(f'{__name__}.SubstitutionManager') + + +class SubstitutionManager: + """Manages player substitutions during game.""" + + def __init__(self, state_manager: StateManager, db_ops: DatabaseOperations): + self.state_manager = state_manager + self.db_ops = db_ops + + async def pinch_hit( + self, + game_id: UUID, + batting_order_pos: int, + new_lineup_id: int + ) -> dict: + """Replace batter in lineup with pinch hitter.""" + # Implementation here + pass + + # ... other methods ``` -**Play Resolution**: -```python -PlayResolver(league_id, auto_mode) - โ”œโ”€โ”€ resolve_manual_play(submission, state, ...) โ†’ PlayResult - โ”œโ”€โ”€ resolve_auto_play(state, batter, pitcher, ...) โ†’ PlayResult - โ””โ”€โ”€ resolve_outcome(outcome, hit_location, state, ...) โ†’ PlayResult (core) -``` - -**Runner Advancement**: -```python -RunnerAdvancement.advance_runners( - outcome, hit_location, state, defensive_decision -) โ†’ AdvancementResult -``` - -### ๐Ÿ”‘ Key Files for Week 8 - -**Substitution System**: -- `app/models/db_models.py` - Lineup model (already has substitution fields!) -- `app/core/substitution_manager.py` (NEW) - Handle substitution logic -- `app/core/validators.py` - Add substitution validation -- `tests/unit/core/test_substitution_manager.py` (NEW) - -**Pitching Changes**: -- `app/core/game_engine.py` - Add `change_pitcher()` method -- `app/models/game_models.py` - Add pitching state tracking -- `app/core/validators.py` - Validate pitcher eligibility - -**Terminal Client**: -- `terminal_client/commands.py` - Add sub commands -- `terminal_client/repl.py` - Add REPL integration - -### ๐Ÿงช Testing Strategy - +**Test Command**: ```bash -# Run substitution tests export PYTHONPATH=. && pytest tests/unit/core/test_substitution_manager.py -v +``` -# Run all core tests (should still pass) -export PYTHONPATH=. && pytest tests/unit/core/ -v +**Acceptance Criteria**: +- [ ] SubstitutionManager class created with all 4 methods +- [ ] Database operations update `replacing_id`, `after_play`, `is_active` +- [ ] Validation prevents invalid substitutions (position, already used, etc.) +- [ ] State manager updated with new lineup after substitution +- [ ] At least 15 unit tests covering happy path and edge cases -# Manual testing in terminal client +--- + +### Task 2: Add Substitution Validation Rules (1.5 hours) + +**File(s)**: `backend/app/core/validators.py` + +**Goal**: Add validation rules specific to substitutions (position eligibility, DH rules, one-way). + +**Changes**: +1. Add `validate_pinch_hitter()` - Check player eligible to bat +2. Add `validate_pinch_runner()` - Check player eligible to run +3. Add `validate_defensive_replacement()` - Check position eligibility +4. Add `validate_substitution_legality()` - General rules (not already used, exists in roster) + +**Files to Update**: +- `backend/app/core/validators.py` - Add 4 new validation functions: +```python +def validate_pinch_hitter( + state: GameState, + lineup: List[LineupPlayerState], + new_lineup_id: int, + batting_order_pos: int +) -> None: + """ + Validate pinch hitter substitution. + + Raises: + ValueError: If substitution is invalid + """ + # Check player exists in lineup and isn't already active + player = next((p for p in lineup if p.lineup_id == new_lineup_id), None) + if not player: + raise ValueError(f"Player {new_lineup_id} not in lineup") + if player.is_active: + raise ValueError(f"Player {new_lineup_id} already active") + + # Check batting order position is valid + if not 1 <= batting_order_pos <= 9: + raise ValueError(f"Invalid batting order position: {batting_order_pos}") + + # Additional rules... +``` + +**Test Command**: +```bash +export PYTHONPATH=. && pytest tests/unit/core/test_validators.py::TestSubstitutionValidation -v +``` + +**Acceptance Criteria**: +- [ ] 4 validation functions added to validators.py +- [ ] Functions raise ValueError with clear messages on invalid input +- [ ] At least 20 tests covering all edge cases +- [ ] Existing validator tests still pass (54 tests) + +--- + +### Task 3: Integrate Substitutions into GameEngine (1 hour) + +**File(s)**: `backend/app/core/game_engine.py` + +**Goal**: Add substitution methods to GameEngine and integrate with play flow. + +**Changes**: +1. Add `SubstitutionManager` to GameEngine initialization +2. Add public methods: + - `make_substitution(game_id, sub_type, ...)` + - `get_available_substitutes(game_id, team_id)` +3. Update `_prepare_next_play()` to use current active lineup + +**Files to Update**: +- `backend/app/core/game_engine.py`: +```python +class GameEngine: + def __init__(self, ...): + # ... existing + self.substitution_manager = SubstitutionManager(self.state_manager, self.db_ops) + + async def make_substitution( + self, + game_id: UUID, + sub_type: str, + **kwargs + ) -> dict: + """ + Make a player substitution. + + Args: + game_id: Game identifier + sub_type: 'pinch_hit', 'pinch_run', 'defensive', 'pitcher' + **kwargs: Type-specific arguments + + Returns: + Substitution result with old and new player info + """ + if sub_type == 'pinch_hit': + return await self.substitution_manager.pinch_hit(game_id, **kwargs) + elif sub_type == 'pinch_run': + return await self.substitution_manager.pinch_run(game_id, **kwargs) + # ... etc +``` + +**Test Command**: +```bash +export PYTHONPATH=. && pytest tests/integration/test_game_engine.py::TestSubstitutions -v +``` + +**Acceptance Criteria**: +- [ ] SubstitutionManager integrated into GameEngine +- [ ] Public methods exposed for each substitution type +- [ ] Substitutions properly update in-memory state +- [ ] Substitutions properly persist to database +- [ ] Integration tests verify full flow + +--- + +### Task 4: Add Pitching Change Logic (1.5 hours) + +**File(s)**: `backend/app/core/substitution_manager.py`, `backend/app/models/game_models.py` + +**Goal**: Implement pitcher substitution with fatigue tracking. + +**Changes**: +1. Add `change_pitcher(game_id, new_lineup_id)` to SubstitutionManager +2. Track pitching fatigue: + - Add `pitches_thrown` to GameState + - Set `is_fatigued` flag in database when threshold reached +3. Add `get_bullpen_status(game_id, team_id)` to list available relievers + +**Files to Update**: +- `backend/app/core/substitution_manager.py`: +```python +async def change_pitcher( + self, + game_id: UUID, + new_lineup_id: int, + reason: str = "relief" +) -> dict: + """ + Change the pitcher. + + Args: + game_id: Game identifier + new_lineup_id: New pitcher's lineup ID + reason: 'relief', 'injury', 'ejection' + + Returns: + Dict with old pitcher, new pitcher, stats + """ + # Implementation +``` + +- `backend/app/models/game_models.py`: +```python +class GameState(BaseModel): + # ... existing fields + pitches_thrown: int = 0 # Current pitcher's pitch count +``` + +**Test Command**: +```bash +export PYTHONPATH=. && pytest tests/unit/core/test_substitution_manager.py::TestPitchingChanges -v +``` + +**Acceptance Criteria**: +- [ ] `change_pitcher()` method implemented +- [ ] `pitches_thrown` tracked in GameState +- [ ] `is_fatigued` flag set in database when > 100 pitches +- [ ] `get_bullpen_status()` returns available relievers +- [ ] At least 10 tests for pitching change scenarios + +--- + +### Task 5: WebSocket Substitution Handlers (1 hour) + +**File(s)**: `backend/app/websocket/handlers.py` + +**Goal**: Add WebSocket event handlers for substitution requests. + +**Changes**: +1. Add `make_substitution` event handler +2. Add `get_available_subs` event handler +3. Validate substitution requests before processing +4. Broadcast substitution to all clients + +**Files to Update**: +- `backend/app/websocket/handlers.py`: +```python +@sio.event +async def make_substitution(sid: str, data: dict): + """ + Handle substitution request from client. + + Expected data: + { + 'game_id': str (UUID), + 'sub_type': 'pinch_hit' | 'pinch_run' | 'defensive' | 'pitcher', + 'batting_order_pos': int (for pinch_hit), + 'base': int (for pinch_run), + 'position': str (for defensive), + 'new_lineup_id': int + } + """ + try: + game_id = UUID(data['game_id']) + sub_type = data['sub_type'] + + # Validate user owns team making substitution + # ... auth logic + + # Make substitution + result = await game_engine.make_substitution(game_id, sub_type, **data) + + # Broadcast to all clients in game + await connection_manager.broadcast_to_game( + game_id, + 'substitution_made', + result + ) + + except Exception as e: + logger.error(f"Substitution error: {e}") + await sio.emit('error', {'message': str(e)}, room=sid) +``` + +**Test Command**: +```bash +export PYTHONPATH=. && pytest tests/unit/websocket/test_substitution_handlers.py -v +``` + +**Acceptance Criteria**: +- [ ] `make_substitution` event handler implemented +- [ ] `get_available_subs` event handler implemented +- [ ] Validation before processing substitution +- [ ] Broadcasts update to all game clients +- [ ] At least 8 tests for handler scenarios + +--- + +### Task 6: Terminal Client Substitution Commands (1 hour) + +**File(s)**: `backend/terminal_client/commands.py`, `backend/terminal_client/repl.py` + +**Goal**: Add terminal client commands for testing substitutions. + +**Changes**: +1. Add `pinch_hit` command +2. Add `pinch_run` command +3. Add `change_pitcher` command +4. Add `show_bench` command (list available subs) +5. Update REPL with new commands + +**Files to Update**: +- `backend/terminal_client/commands.py`: +```python +async def make_substitution( + game_id: UUID, + sub_type: str, + **kwargs +) -> dict: + """Make a player substitution.""" + result = await game_engine.make_substitution(game_id, sub_type, **kwargs) + return result + +async def show_bench(game_id: UUID, team_id: int) -> list: + """Show available substitute players.""" + lineup = await game_engine.state_manager.get_lineup(game_id, team_id) + bench = [p for p in lineup if not p.is_active] + return bench +``` + +- `backend/terminal_client/repl.py`: +```python +def do_pinch_hit(self, arg): + """ + Substitute a pinch hitter. + Usage: pinch_hit + Example: pinch_hit 7 25 + """ + # Implementation + +def do_show_bench(self, arg): + """ + Show available substitute players. + Usage: show_bench + Example: show_bench 1 + """ + # Implementation +``` + +**Test Command**: +```bash +# Manual testing python -m terminal_client > new_game > start_game -> pinch_hit 5 101 # Pinch hit for batting order 5 with lineup_id 101 +> show_bench 1 +> pinch_hit 5 15 > status ``` +**Acceptance Criteria**: +- [ ] 4 new REPL commands added +- [ ] Commands integrate with SubstitutionManager +- [ ] Help text updated with new commands +- [ ] Manual testing scenarios verified + --- -## Week 7 Architectural Decisions (Reference) +### Task 7: Enhanced Status Display with Subs (30 mins) -### 1. **Outcome-First PlayResolver Architecture** -- **Manual mode is primary** - Most games use this (all SBA + half of PD) -- **Core `resolve_outcome()` method** - All game logic in one place -- **Thin wrappers** - `resolve_manual_play()` and `resolve_auto_play()` -- **No hard-coded exceptions** - Multi-step plays handled generically by GameEngine +**File(s)**: `backend/terminal_client/display.py` -### 2. **Auto Mode Configuration** -- **Stored per-game** - `GameState.auto_mode` field -- **League validation** - `supports_auto_mode()` in config - - SBA: `False` (raises error if attempted) - - PD: `True` (has digitized ratings) +**Goal**: Update status display to show substitutions and fatigue. -### 3. **Hit Location Tracking** -- **Critical for advancement** - Determines chart row and conditionals -- **Groundballs** - Must specify location (1B, 2B, 3B, SS, P, C) -- **Flyouts** - Track for future tag-up logic (LF, CF, RF) -- **Other outcomes** - `None` (walks, strikeouts, etc.) +**Changes**: +1. Show pitcher fatigue indicator (`is_fatigued` flag) +2. Show substitution history (who replaced whom) +3. Show bench players separately from active lineup +4. Add visual indicators for pinch hitters/runners -### 4. **Manual vs Auto Mode** -**Manual Mode** (primary): +**Files to Update**: +- `backend/terminal_client/display.py`: ```python -1. Server rolls dice โ†’ AbRoll -2. Broadcasts dice to players via WebSocket -3. Players read physical cards -4. Players submit outcome + location -5. Server validates ManualOutcomeSubmission -6. Server resolves with RunnerAdvancement -7. Broadcasts result +def format_lineup_with_subs(lineup: List[LineupPlayerState]) -> str: + """Format lineup showing substitutions.""" + active = [p for p in lineup if p.is_active] + bench = [p for p in lineup if not p.is_active] + + output = "Active Lineup:\n" + for player in active: + indicator = "" + if not player.is_starter: + indicator = " (SUB)" # Show substitution indicator + output += f" {player.batting_order}. {player.position} - ID {player.lineup_id}{indicator}\n" + + output += "\nBench:\n" + for player in bench: + output += f" {player.position} - ID {player.lineup_id}\n" + + return output ``` -**Auto Mode** (PD only, rare): -```python -1. Server rolls dice โ†’ AbRoll -2. PdAutoResultChart.get_outcome(roll, batter, pitcher) โ†’ outcome + location -3. Server resolves with RunnerAdvancement -4. Broadcasts result +**Test Command**: +```bash +# Manual verification +python -m terminal_client +> new_game +> start_game +> status # Should show updated format ``` ---- - -## Important Patterns & Conventions - -### Testing -- **Always use venv**: `source venv/bin/activate` -- **Set PYTHONPATH**: `export PYTHONPATH=.` -- **Run tests after each change**: `pytest tests/unit/core/ -v` - -### Git Commits -- **Prefix with "CLAUDE: "**: All commits must start with this -- **Descriptive messages**: Include what changed and why -- **Reference tasks**: "Implement Week 8 Task 1 - Substitution System" - -### Code Style -- **Pydantic dataclasses** - For models and validation -- **Async/await** - All database operations -- **Frozen configs** - Immutable league configurations -- **"Raise or Return"** - No Optional unless required -- **Pendulum for dates** - Never use Python's datetime - -### Documentation -- **Update NEXT_SESSION.md** - After completing tasks -- **Add TODO comments** - For future work -- **Docstrings** - Google style for classes and public methods +**Acceptance Criteria**: +- [ ] Status display shows active vs bench players +- [ ] Substitution indicators visible +- [ ] Pitcher fatigue shown +- [ ] Clean, readable format --- -## Current Test Status +## Files to Review Before Starting -**Total Tests**: ~519 tests -- Config: 79/79 โœ… (58 base + 21 result charts) -- Validators: 54/54 โœ… -- Runner Advancement: 30/30 โœ… -- PlayResolver: 9/9 โœ… (rewritten for new architecture) -- WebSocket Handlers: 12/12 โœ… -- Dice: 34/35 (1 pre-existing failure in get_rolls_since) -- Roll Types: 27/27 โœ… -- Player Models: 32/32 โœ… -- Game Models: ~150+ โœ… -- State Manager: ~80+ โœ… +Critical files for Week 8 substitution work: -**Week 8 Target**: Add ~50 new tests for substitutions and pitching +1. **`backend/app/models/db_models.py:104-135`** - Lineup model with substitution fields + - Already has `replacing_id`, `after_play`, `entered_inning`, `is_fatigued` + - Fields are in place from Phase 1, just need logic! + +2. **`backend/app/core/runner_advancement.py`** - Recently refactored, understand pattern + - Good example of delegation and routing logic + - Similar pattern needed for SubstitutionManager + +3. **`backend/app/core/game_engine.py:1-100`** - Initialization and structure + - Understand how to add SubstitutionManager + - See existing manager integrations + +4. **`backend/app/core/validators.py`** - Existing validation patterns + - Add substitution validators following same style + - See defensive/offensive decision validation for examples + +5. **`backend/app/websocket/handlers.py:250-350`** - Manual outcome handlers + - Good pattern for new substitution handlers + - Copy auth and broadcast patterns + +6. **`.claude/implementation/WEEK_7_PLAN.md`** - Week 7 plan (completed) + - Reference for task structure and detail level + +7. **`backend/terminal_client/commands.py`** - Command implementation pattern + - Follow same async pattern for new commands + +8. **`backend/CLAUDE.md:86-175`** - Database model documentation + - Understand Lineup substitution tracking design --- -## Database & Environment +## Verification Steps -**Database**: PostgreSQL @ 10.10.0.42:5432 (paperdynasty_dev) +After completing all Week 8 tasks: + +1. **Run all tests**: + ```bash + # Unit tests (should add ~50 new tests) + export PYTHONPATH=. && pytest tests/unit/ -v + + # Integration tests (one at a time) + export PYTHONPATH=. && pytest tests/integration/test_game_engine.py::TestSubstitutions -v + ``` + +2. **Manual testing**: + ```bash + python -m terminal_client + > new_game + > start_game + > show_bench 1 + > pinch_hit 7 15 # Substitute for 7th batter + > status # Verify substitution shows + > change_pitcher 20 # Bring in reliever + > status # Verify new pitcher + > pinch_run 1 18 # Replace runner on first + > status # Verify runner replaced + ``` + +3. **Database verification**: + ```sql + -- Check substitution metadata + SELECT lineup_id, position, is_active, is_starter, replacing_id, after_play + FROM lineups + WHERE game_id = '[test_game_id]' + ORDER BY team_id, batting_order; + ``` + +4. **Commit changes**: + ```bash + git add backend/app/core/substitution_manager.py \ + backend/app/core/validators.py \ + backend/app/core/game_engine.py \ + backend/app/models/game_models.py \ + backend/app/websocket/handlers.py \ + backend/terminal_client/*.py \ + tests/unit/core/test_substitution_manager.py \ + tests/unit/core/test_validators.py \ + tests/unit/websocket/test_substitution_handlers.py + + git commit -m "CLAUDE: Implement Week 8 - Player substitution system + + Complete substitution system with all types: + - SubstitutionManager class with pinch hit/run/defensive/pitcher methods + - Validation rules for substitution eligibility + - Database tracking of replacing_id, after_play, is_active + - Pitching fatigue tracking with is_fatigued flag + - WebSocket handlers for substitution events + - Terminal client commands for testing + - Enhanced status display with substitution indicators + + Testing: + - 50+ new unit tests (all passing) + - Integration tests for full substitution flow + - Manual testing scenarios verified + + ๐Ÿš€ Generated with [Claude Code](https://claude.com/claude-code) + + Co-Authored-By: Claude " + ``` + +--- + +## Success Criteria + +Week 8 will be **100% complete** when: + +- [ ] SubstitutionManager class created with 4 substitution methods (50+ tests) +- [ ] Substitution validation rules added to validators.py (20+ tests) +- [ ] GameEngine integration with substitution methods +- [ ] Pitching change logic with fatigue tracking +- [ ] WebSocket handlers for substitution events (8+ tests) +- [ ] Terminal client commands for all substitution types +- [ ] Enhanced status display showing subs and fatigue +- [ ] All existing tests still passing (201 core tests) +- [ ] Documentation updated in CLAUDE.md +- [ ] Git commit created with Week 8 completion + +**Expected Test Count After Week 8**: ~260 core tests (201 current + ~50 new + ~9 integration) + +--- + +## Quick Reference + +**Current Test Count**: 201 core tests passing, 1 pre-existing failure (dice history) +**Last Test Run**: All passing (2025-10-31) +**Branch**: `implement-phase-3` **Python**: 3.13.3 **Virtual Env**: `backend/venv/` -**Branch**: `implement-phase-2` -**Key Commands**: -```bash -# Activate venv -cd backend && source venv/bin/activate +**Key Imports for Next Session**: +```python +# Substitution system +from app.core.substitution_manager import SubstitutionManager +from app.models.game_models import GameState, LineupPlayerState +from app.database.operations import DatabaseOperations +from app.core.validators import ( + validate_pinch_hitter, + validate_pinch_runner, + validate_defensive_replacement +) -# Run tests -export PYTHONPATH=. && pytest tests/unit/core/ -v +# Testing +from uuid import uuid4 +import pytest +from unittest.mock import Mock, AsyncMock, patch +``` -# Terminal client -python -m terminal_client - -# Check git status -git status +**Recent Commit History** (Last 10): +``` +a696473 - CLAUDE: Integrate flyball advancement with RunnerAdvancement system (7 hours ago) +23a0a1d - CLAUDE: Update tests to match Phase 2 model changes (8 hours ago) +76e24ab - CLAUDE: Refactor ManualOutcomeSubmission to use PlayOutcome enum + comprehensive documentation (8 hours ago) +119f169 - CLAUDE: Prepare NEXT_SESSION.md for Week 8 (16 hours ago) +4cf349a - CLAUDE: Update NEXT_SESSION.md - Week 7 complete at 100% (16 hours ago) +e2f1d60 - CLAUDE: Implement Week 7 Task 6 - PlayResolver Integration with RunnerAdvancement (16 hours ago) +5b88b11 - CLAUDE: Update NEXT_SESSION.md - Tasks 4 & 5 complete, Week 7 at 87% (25 hours ago) +102cbb6 - CLAUDE: Implement Week 7 Tasks 4 & 5 - Runner advancement logic and double play mechanics (25 hours ago) +69782f5 - CLAUDE: Update NEXT_SESSION.md with latest commit hash (26 hours ago) +9cae63a - CLAUDE: Implement Week 7 Task 7 - WebSocket manual outcome handlers (26 hours ago) ``` --- -## What NOT to Do +## Context for AI Agent Resume -- โŒ Don't modify database schema without migrations +**If the next agent needs to understand the bigger picture**: +- Overall project: See `@prd-web-scorecard-1.1.md` and `@backend/CLAUDE.md` +- Architecture: See `@.claude/implementation/00-index.md` +- Week 7 completed work: See `@.claude/implementation/WEEK_7_PLAN.md` +- Database models: See `@backend/app/models/db_models.py` +- State management: See `@backend/app/core/state_manager.py` + +**Critical files in current focus area**: +1. `backend/app/models/db_models.py` - Lineup model with substitution support +2. `backend/app/core/game_engine.py` - Main orchestration +3. `backend/app/core/state_manager.py` - In-memory state +4. `backend/app/core/runner_advancement.py` - Recently refactored, good pattern +5. `backend/app/core/validators.py` - Validation patterns +6. `backend/app/websocket/handlers.py` - WebSocket event patterns +7. `backend/terminal_client/commands.py` - Command implementation +8. `backend/terminal_client/repl.py` - REPL integration +9. `backend/terminal_client/display.py` - Status display formatting +10. `tests/unit/core/test_validators.py` - Test patterns + +**What NOT to do**: +- โŒ Don't modify database schema without migrations (substitution fields already exist!) - โŒ Don't use Python's `datetime` (use Pendulum) -- โŒ Don't return `Optional` unless required -- โŒ Don't disable type checking globally -- โŒ Don't skip validation +- โŒ Don't return `Optional` unless required ("Raise or Return" pattern) +- โŒ Don't disable type checking globally (use targeted `# type: ignore`) +- โŒ Don't skip validation (validate early, validate often) - โŒ Don't commit without "CLAUDE: " prefix - โŒ Don't forget `export PYTHONPATH=.` when running tests -- โŒ Don't hard-code multi-step play logic (keep it generic) +- โŒ Don't run all integration tests at once (known connection conflicts) +- โŒ Don't create new database fields (Lineup already has everything needed!) --- -## References - -- **Implementation Guide**: `@.claude/implementation/01-infrastructure.md` -- **Backend Architecture**: `@.claude/implementation/backend-architecture.md` -- **Week 7 Plan**: `@.claude/implementation/WEEK_7_PLAN.md` -- **Database Design**: `@.claude/implementation/database-design.md` -- **Full PRD**: `@prd-web-scorecard-1.1.md` - ---- - -**Status**: โœ… Week 7 Complete - Ready for Week 8! +**Estimated Time for Next Session**: 8-10 hours (7 tasks) **Priority**: High - Substitutions are core gameplay feature -**Estimated Time**: Week 8 should take 3-5 sessions -**Next Milestone**: Complete substitution system and pitching management +**Blocking Other Work**: No - can proceed with Week 8 independently +**Next Milestone After This**: Week 9 - Advanced rules (steals, balks, pick-offs) + +--- + +## Week 7 Completion Summary (For Reference) + +**What Was Completed**: +1. Strategic Decision Integration (async workflow) +2. Decision Validators (54 tests) +3. Result Charts + PD Auto Mode (21 tests) +4. Runner Advancement Logic (30 groundball tests) +5. Double Play Mechanics (integrated) +6. PlayResolver Integration (9 tests) +7. WebSocket Manual Outcome Handlers (12 tests) +8. Terminal Client Enhancement +9. **Flyball Advancement Integration (21 tests)** โ† Just completed! + +**Total Week 7 Tests**: 147 tests (126 originally planned + 21 flyball) + +**Key Achievement**: Unified runner advancement system handling both groundballs (13 result types) and flyballs (4 types) through consistent interface. + +--- + +**Status**: โœ… Week 7 Complete (100%) - Ready for Week 8!