strat-gameplay-webapp/.claude/implementation/NEXT_SESSION.md
Cal Corum 0b56b89a0b Update NEXT_SESSION.md
Context includes completing week 7 work and planning week 8 work.
2025-11-01 01:17:45 -05:00

28 KiB

Next Session Plan - Week 7 Complete, Ready for Week 8

Current Status: Phase 3 - Week 7 COMPLETE (100%) Last Commit: a696473 - "CLAUDE: Integrate flyball advancement with RunnerAdvancement system" Date: 2025-10-31 Remaining Work: Week 8 - Substitutions & Advanced Gameplay (0% complete)


Quick Start for Next AI Agent

🎯 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

📍 Current Context

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.

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:
"""
Player substitution management.

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

Test Command:

export PYTHONPATH=. && pytest tests/unit/core/test_substitution_manager.py -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

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:
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:

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:
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:

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:
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:
class GameState(BaseModel):
    # ... existing fields
    pitches_thrown: int = 0  # Current pitcher's pitch count

Test Command:

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:
@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:

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:
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:
def do_pinch_hit(self, arg):
    """
    Substitute a pinch hitter.
    Usage: pinch_hit <batting_order_pos> <new_lineup_id>
    Example: pinch_hit 7 25
    """
    # Implementation

def do_show_bench(self, arg):
    """
    Show available substitute players.
    Usage: show_bench <team_id>
    Example: show_bench 1
    """
    # Implementation

Test Command:

# Manual testing
python -m terminal_client
> new_game
> start_game
> 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

Task 7: Enhanced Status Display with Subs (30 mins)

File(s): backend/terminal_client/display.py

Goal: Update status display to show substitutions and fatigue.

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

Files to Update:

  • backend/terminal_client/display.py:
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

Test Command:

# Manual verification
python -m terminal_client
> new_game
> start_game
> status  # Should show updated format

Acceptance Criteria:

  • Status display shows active vs bench players
  • Substitution indicators visible
  • Pitcher fatigue shown
  • Clean, readable format

Files to Review Before Starting

Critical files for Week 8 substitution work:

  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

Verification Steps

After completing all Week 8 tasks:

  1. Run all tests:

    # 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:

    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:

    -- 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:

    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 <noreply@anthropic.com>"
    

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/

Key Imports for Next Session:

# 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
)

# Testing
from uuid import uuid4
import pytest
from unittest.mock import Mock, AsyncMock, patch

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)

Context for AI Agent Resume

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 ("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 run all integration tests at once (known connection conflicts)
  • Don't create new database fields (Lineup already has everything needed!)

Estimated Time for Next Session: 8-10 hours (7 tasks) Priority: High - Substitutions are core gameplay feature 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!