strat-gameplay-webapp/.claude/implementation/NEXT_SESSION.md
Cal Corum 5b88b11ea0 CLAUDE: Update NEXT_SESSION.md - Tasks 4 & 5 complete, Week 7 at 87%
Updated documentation to reflect completion of runner advancement logic
and double play mechanics:

Status Changes:
- Week 7 progress: 62% → 87% complete
- Tasks complete: 7 of 8 (only Task 6 remaining)
- Test count: 489 → 519 tests passing (94% of target)

Completed Tasks:
- Task 4: Runner advancement logic (30 tests)
  - GroundballResultType IntEnum with 13 result constants
  - Infield Back and Infield In chart implementations
  - Corners In hybrid positioning support
  - DECIDE mechanic foundation
- Task 5: Double play mechanics (integrated into Task 4)
  - Probability-based DP calculation (45% base)
  - Positioning and hit location modifiers
  - Integrated into results 2, 10, and 13

Documentation Updates:
- Added comprehensive Task 4 & 5 completion summary
- Updated "What We Just Completed" with full implementation details
- Resolved outstanding questions (TOOTBLAN/FARTSLAM deprecated)
- Updated Quick Reference with new test counts
- Streamlined "Tasks for Next Session" to focus on Task 6
- Updated commit history and progress metrics

Next Steps:
- Task 6: PlayResolver Integration (final task, 3-4 hours)
- Integrate RunnerAdvancement into play_resolver.py
- Update all existing tests
- Week 7 completion at 100%

Related: #week7 #task4 #task5 #runner-advancement #documentation
2025-10-30 23:38:34 -05:00

28 KiB

Next Session Plan - Phase 3 Week 7 in Progress

Current Status: Phase 3 - Week 7 (~87% Complete) Last Commit: 102cbb6 - "CLAUDE: Implement Week 7 Tasks 4 & 5 - Runner advancement logic and double play mechanics" Date: 2025-10-30 Remaining Work: 13% (1 of 8 tasks remaining - Task 6: PlayResolver Integration)


Quick Start for Next AI Agent

🎯 Where to Begin

  1. Read this entire document first
  2. Review @.claude/implementation/WEEK_7_PLAN.md for comprehensive task details
  3. Start with Task 6: PlayResolver Integration (final task!)
  4. Run tests after each change: export PYTHONPATH=. && pytest tests/unit/core/ -v

📍 Current Context

Week 7 Tasks 1-5, 7-8 are complete!

  • Task 1: Async decision workflow with asyncio Futures
  • Task 2: Defensive/offensive decision validators with 54 tests passing
  • Task 3: Result chart abstraction + PD auto mode with 21 tests passing
  • Task 4: Runner advancement logic with 30 tests passing
  • Task 5: Double play mechanics (integrated into Task 4)
  • Task 7: WebSocket manual outcome handlers with 12 tests passing
  • Task 8: Terminal client enhancement (manual commands)

Next up: Task 6 - PlayResolver Integration! This is the final task. Integrate the RunnerAdvancement class into play_resolver.py so all groundball outcomes use the new advancement logic. Update existing tests and ensure no regressions.

Note: Tasks 7-8 completed out of order while waiting for advancement chart clarification from user.

IMPORTANT CONTEXT: In this session, we clarified major architectural points:

  • Manual Mode (SBA + PD manual):
    • Server rolls dice for fairness and auditing (NOT players!)
    • Players read PHYSICAL cards based on server dice
    • Players submit outcomes via WebSocket
    • System validates and processes with server-rolled dice
  • PD Auto Mode: System uses digitized ratings to auto-generate outcomes for faster/AI play. This is NEW functionality enabling AI vs AI games.
  • Decision Modifiers: Do NOT change the base outcome (GROUNDBALL_C stays GROUNDBALL_C). They affect RUNNER ADVANCEMENT based on hit location and defensive positioning.

What We Just Completed

1. Validator Bug Fixes (Commit c0051d2)

  • File: app/core/validators.py
  • Issue: Validator checking wrong on_base_codes for "runner on third"
  • Fix: Updated to use state.is_runner_on_third() helper method
  • Changes:
    • Fixed infield depth validation (corners_in/infield_in require runner on third)
    • Updated DefensiveDecision Pydantic model: infield depths ['infield_in', 'normal', 'corners_in']
    • Updated DefensiveDecision Pydantic model: outfield depths ['in', 'normal'] (removed 'back')
    • Removed 4 invalid double_play depth tests (depth doesn't exist)
    • Added 4 proper corners_in/infield_in tests
  • Testing: All 54 validator tests passing
  • Impact: Validators now correctly check game state using helper methods

2. Result Chart Abstraction & PD Auto Mode (Commit 9245b4e) - Week 7 Task 3

  • Files:

    • app/config/result_charts.py (+400 lines)
    • app/models/game_models.py (+55 lines)
    • tests/unit/config/test_result_charts.py (+492 lines, NEW)
  • Core Implementation:

    • ResultChart abstract base class: Defines get_outcome(roll, state, batter, pitcher) -> tuple[outcome, location]
    • calculate_hit_location() helper:
      • 45% pull, 35% center, 20% opposite field distribution
      • RHB pulls left (3B, SS, LF), LHB pulls right (1B, 2B, RF)
      • Groundballs → infield positions (1B, 2B, SS, 3B, P, C)
      • Flyouts → outfield positions (LF, CF, RF)
    • PlayOutcome.requires_hit_location(): Returns True for groundballs and flyouts only
  • Manual Mode Support:

    • ManualResultChart: Passthrough class (raises NotImplementedError)
    • Manual mode doesn't use result charts - players submit via WebSocket
    • ManualOutcomeSubmission model: Validates PlayOutcome enum + hit location
      • Validates outcome is valid PlayOutcome value
      • Validates hit location in ['1B', '2B', 'SS', '3B', 'LF', 'CF', 'RF', 'P', 'C']
      • Location is optional (only needed for certain outcomes)
  • PD Auto Mode Implementation:

    • PdAutoResultChart: Full auto-generation for PD games
      • _select_card(): Coin flip (50/50) to choose batting or pitching card
      • _build_distribution(): Creates cumulative distribution from rating percentages
      • _select_outcome(): Rolls 1d100 to select outcome from distribution
      • Maps rating fields to PlayOutcome enum:
        • Common: homerun, triple, doubles, singles, walks, strikeouts
        • Batting-specific: lineouts, popouts, flyout variants, groundout variants
        • Pitching-specific: uncapped singles/doubles (SINGLE_UNCAPPED, DOUBLE_UNCAPPED)
      • Calculates hit location using handedness and pull rates
      • Proper error handling when card data missing
  • Testing: 21 comprehensive unit tests (all passing )

    • Helper function tests (calculate_hit_location)
    • PlayOutcome helper tests (requires_hit_location)
    • ManualResultChart tests (NotImplementedError)
    • PdAutoResultChart tests:
      • Coin flip distribution (~50/50 over 1000 trials)
      • Handedness matchup selection
      • Cumulative distribution building
      • Outcome selection from probabilities
      • Hit location calculation for groundballs
      • Error handling for missing cards
      • Statistical distribution verification
    • ManualOutcomeSubmission validation tests
  • Impact:

    • Foundation for both manual and auto play modes
    • Hit locations ready for Task 4 runner advancement
    • PD auto mode enables AI vs AI games
    • Integration with PlayResolver deferred (Phase 6)
    • Terminal client manual outcome command deferred (Phase 8)

3. WebSocket Manual Outcome Handlers (Current Session) - Week 7 Task 7

  • Files:

    • app/websocket/handlers.py (+240 lines - 2 new event handlers)
    • app/core/game_engine.py (+147 lines - resolve_manual_play method)
    • app/models/game_models.py (+1 line - pending_manual_roll field)
    • terminal_client/commands.py (+128 lines - roll_manual_dice, submit_manual_outcome)
    • terminal_client/repl.py (updated do_roll_dice, do_manual_outcome)
    • tests/unit/websocket/test_manual_outcome_handlers.py (+432 lines, NEW)
  • Core Implementation:

    • roll_dice WebSocket Handler:

      • Server rolls dice using dice_system.roll_ab()
      • Stores ab_roll in state.pending_manual_roll
      • Broadcasts dice results to all players in game room
      • Events: dice_rolled (broadcast), error (validation failures)
    • submit_manual_outcome WebSocket Handler:

      • Validates ManualOutcomeSubmission model (outcome + optional location)
      • Checks for pending_manual_roll (prevents submission without roll)
      • Validates hit_location required for groundballs/flyouts
      • Calls game_engine.resolve_manual_play() to process
      • Events: outcome_accepted, outcome_rejected, play_resolved, error
    • GameEngine.resolve_manual_play():

      • Accepts server-rolled ab_roll for audit trail
      • Uses player-submitted outcome for resolution
      • Validates hit_location when required
      • Same orchestration as resolve_play() (save, update, advance inning)
      • Tracks rolls for batch saving at inning boundaries
    • Terminal Client Commands:

      • roll_dice - Roll dice and display results
      • manual_outcome <outcome> [location] - Submit manual outcome
      • Both integrated into REPL for testing
  • Testing: 12 comprehensive unit tests (all passing )

    • roll_dice tests (4):
      • Successful roll and broadcast
      • Missing game_id validation
      • Invalid game_id format validation
      • Game not found error handling
    • submit_manual_outcome tests (8):
      • Successful submission and play resolution
      • Missing game_id validation
      • Missing outcome validation
      • Invalid outcome value validation
      • Invalid hit_location validation
      • Missing required hit_location validation
      • No pending roll error handling
      • Walk without location (valid case)
  • Key Architectural Decisions:

    • Server rolls dice for fairness: Clarified with user - server generates dice, stores for audit, players read cards
    • One-time roll usage: pending_manual_roll cleared after submission to prevent reuse
    • Early validation: Check for pending roll BEFORE emitting outcome_accepted
    • Comprehensive error handling: Field-level error messages for clear user feedback
  • Impact:

    • Complete manual outcome workflow implemented
    • WebSocket handlers ready for frontend integration
    • Terminal client testing commands available
    • Audit trail maintained with server-rolled dice
    • Foundation for SBA and PD manual mode gameplay

4. Runner Advancement Logic (Current Session) - Week 7 Tasks 4 & 5

  • Files:

    • app/core/runner_advancement.py (+1230 lines, NEW)
    • tests/unit/core/test_runner_advancement.py (+705 lines, NEW)
  • Core Implementation:

    • GroundballResultType IntEnum: 13 result constants matching rulebook exactly

      • BATTER_OUT_RUNNERS_HOLD (1)
      • DOUBLE_PLAY_AT_SECOND (2)
      • BATTER_OUT_RUNNERS_ADVANCE (3)
      • BATTER_SAFE_FORCE_OUT_AT_SECOND (4)
      • CONDITIONAL_ON_MIDDLE_INFIELD (5)
      • CONDITIONAL_ON_RIGHT_SIDE (6)
      • BATTER_OUT_FORCED_ONLY (7/8)
      • LEAD_HOLDS_TRAIL_ADVANCES (9)
      • DOUBLE_PLAY_HOME_TO_FIRST (10)
      • BATTER_SAFE_LEAD_OUT (11)
      • DECIDE_OPPORTUNITY (12)
      • CONDITIONAL_DOUBLE_PLAY (13)
    • RunnerAdvancement class:

      • advance_runners() - Main entry point for advancement calculation
      • _determine_groundball_result() - Chart lookup logic (Infield Back vs Infield In)
      • _execute_result() - Dispatches to result-specific handlers
      • _calculate_double_play_probability() - DP success calculation with modifiers
    • Infield Back Chart (default defensive positioning):

      • Empty bases: Result 1 (batter out, runners hold)
      • Runner on 1st: Result 2/4 (DP attempt or force out)
      • Runner on 2nd: Result 6 (conditional on right side hit)
      • Runner on 3rd: Result 5 (conditional on middle infield hit)
      • Multiple runners: Various forced advancement scenarios
    • Infield In Chart (runner on 3rd, defense playing in):

      • 3rd only: Result 7/1/8 based on groundball type
      • 1st & 3rd: Result 7/9/12 with DECIDE opportunities
      • 2nd & 3rd: Result 7/1/8
      • Bases loaded: Result 10/11 (DP attempts at home)
    • Corners In Positioning (hybrid approach):

      • Uses Infield In rules when ball hit to corners (1B/3B/P/C)
      • Uses Infield Back rules when ball hit to middle infield (2B/SS)
      • Automatic detection based on hit_location parameter
    • Double Play Mechanics (Task 5):

      • Base probability: 45%
      • Positioning modifiers:
        • Infield In: -15% (prioritizing out at plate)
        • Normal: 0% (base rate)
      • Hit location modifiers:
        • Middle infield (2B/SS): +10%
        • Corners (1B/3B/P/C): -10%
      • TODO: Runner speed modifiers when player ratings available
      • Probability clamped between 0% and 100%
    • DECIDE Mechanic (Result 12):

      • Placeholder for interactive runner advancement decisions
      • Offense chooses whether lead runner attempts to advance
      • Defense chooses to take sure out OR throw for lead runner
      • Safe range calculation: runner_speed - 4 + fielder_rating
      • Conservative default (runners hold) until interactive flow implemented
    • All 13 Result Handlers:

      • _gb_result_1() through _gb_result_13()
      • Each returns AdvancementResult with movements, outs, runs
      • Handles force plays, runner advancement, scoring logic
      • Conditional results based on hit location
  • Testing: 30 comprehensive unit tests (all passing )

    • Chart lookup tests (7):

      • Empty bases → Result 1
      • 2 outs → Result 1 (always)
      • Runner on 1st + GBA + Infield Back → Result 2 (DP)
      • Runner on 3rd + Infield In → Result 7 (forced only)
      • Bases loaded + Infield In → Result 10 (DP home to first)
      • Corners In hit to corner → Infield In rules
      • Corners In hit to middle → Infield Back rules
    • Result handler tests (11):

      • Result 1: Batter out, runners hold
      • Result 2: Double play (successful and failed)
      • Result 3: Batter out, runners advance
      • Result 5: Conditional on middle infield
      • Result 7: Forced advancement only
      • Result 10: DP home to first
      • Result 12: DECIDE opportunities
    • Double play probability tests (5):

      • Base probability (45% + location bonus)
      • Corner penalty (-10%)
      • Infield in penalty (-15%)
      • Probability bounds (0-1 clamping)
    • Edge case tests (7):

      • Invalid outcome raises ValueError
      • All groundball types supported (A, B, C)
      • All hit locations supported (1B, 2B, SS, 3B, P, C)
      • All on-base codes supported (0-7)
  • Key Architectural Decisions:

    • IntEnum approach: Balances rulebook traceability with code clarity
    • Probability-based DPs: More realistic than deterministic outcomes
    • TOOTBLAN/FARTSLAM deprecated: User clarified these are no longer in ruleset
    • DECIDE placeholder: Foundation laid, interactive flow deferred to game engine layer
    • Hit location critical: Determines which chart row and conditional logic applies
  • Impact:

    • Complete groundball advancement system implemented
    • Both Infield Back and Infield In charts working
    • Double play mechanics with realistic probability
    • Foundation for interactive DECIDE mechanic
    • 30 tests ensuring correctness across all scenarios
    • Integration with PlayResolver pending (Task 6)

Key Architecture Decisions Made

1. Manual vs Auto Mode Clarification

Decision: Manual mode doesn't use result charts at all - humans submit outcomes directly

Rationale:

  • SBA and PD manual games use physical cards that aren't digitized (SBA) or optional digitization (PD)
  • Players roll dice, read their card, and tell system the outcome + location via WebSocket
  • Result charts only used for PD auto mode where we need to generate outcomes

Impact:

  • Simpler architecture - no "manual result chart" logic needed
  • ManualResultChart exists only for interface completeness (raises NotImplementedError)
  • WebSocket handlers will receive ManualOutcomeSubmission objects
  • PdAutoResultChart is truly optional - only for auto mode

2. Decision Modifiers Affect Advancement, Not Outcomes

Decision: Defensive decisions don't change the PlayOutcome - they change runner advancement

Rationale:

  • User provided advancement charts showing different runner movements for same outcome
  • GROUNDBALL_C stays GROUNDBALL_C whether infield is "in", "back", or "normal"
  • The HIT LOCATION + DEFENSIVE POSITIONING determine advancement (Infield In/Back charts)
  • Example: GROUNDBALL_C to SS with "corners_in" = different advancement than "normal" depth

Impact:

  • Task 3 (this session) focused on outcome selection + hit location calculation
  • Task 4 (next) implements advancement logic using hit locations from Task 3
  • SimplifiedResultChart in play_resolver.py remains untouched (no breaking changes)
  • Original Week 7 plan overestimated decision modifier complexity

3. Hit Location is Critical, Not Just Informational

Decision: Track precise hit location (1B, 2B, SS, 3B, LF, CF, RF, P, C) for every groundball/flyout

Rationale:

  • User's advancement charts show different rules for different fielders
  • "Corners in" only affects plays hit to 1B, 3B, P, or C (not 2B/SS)
  • Hit location determines which advancement chart row to use
  • Tag-up logic for flyouts depends on location (deep fly vs shallow)

Impact:

  • calculate_hit_location() must be accurate with proper pull rates
  • ManualOutcomeSubmission requires location for groundballs/flyouts
  • Task 4 will use location extensively in advancement logic
  • Future: Could add fielder ratings affecting outcomes

4. On-Base Code is Enumeration, Not Bit Field

Decision: current_on_base_code is 0-7 enumeration, not bit-field addition

Clarification (from user):

  • 0: empty
  • 1: on first
  • 2: on second
  • 3: on third
  • 4: first and second
  • 5: first and third
  • 6: second and third
  • 7: bases loaded

Impact:

  • Fixed validator bug checking wrong codes for "runner on third"
  • Code should use helper methods (is_runner_on_first()) instead of hardcoding
  • Documentation updated with correct enumeration values

Blockers Encountered 🚧

1. PYTHONPATH Required for Tests

Issue: Tests fail with ModuleNotFoundError: No module named 'app' without PYTHONPATH set

Workaround: Run tests with export PYTHONPATH=. && pytest ...

Status: ⚠️ Need to investigate why PYTHONPATH isn't set automatically by pytest.ini

TODO: Add PYTHONPATH configuration to pytest.ini or add init.py files to fix imports


Outstanding Questions

1. DECIDE Mechanic Interactive Flow RESOLVED

Question: How should DECIDE mechanic interactive flow work?

Context: Result 12 creates DECIDE opportunities where offense chooses if lead runner attempts to advance, then defense responds.

Resolution: Foundation implemented in RunnerAdvancement with conservative default (runners hold). Full interactive flow will be handled by game engine layer with WebSocket events for offense/defense decisions. Safe range calculation: runner_speed - 4 + fielder_rating (max 1-19).

2. TOOTBLAN/FARTSLAM Mechanics RESOLVED

Question: Should we implement TOOTBLAN and FARTSLAM mechanics from images?

Context: Images show these as special d20 roll mechanics for runner advancement.

Resolution: User clarified these are deprecated from the ruleset. We do NOT implement them.

3. WebSocket Event Names for Manual Submissions RESOLVED

Question: What events should manual mode use?

Context: Need events for rolling dice, submitting outcomes, validation, and broadcasting results.

Resolution: Implemented in Task 7 with these events:

  • roll_dice - Server rolls dice and broadcasts to players
  • submit_manual_outcome - Player sends ManualOutcomeSubmission
  • outcome_accepted - Server confirms valid outcome
  • outcome_rejected - Server rejects invalid outcome (validation error)
  • dice_rolled - Broadcast event with dice results
  • play_resolved - Broadcast event with play result

4. Terminal Client Testing Without Frontend RESOLVED

Question: How to test manual outcome submission flow without WebSocket?

Resolution: Implemented in Task 8 with roll_dice and manual_outcome commands that call WebSocket handlers directly, allowing full manual mode testing in terminal client without needing a frontend.


Tasks for Next Session

Task 6: PlayResolver Integration (3-4 hours) - FINAL TASK

Files:

  • app/core/play_resolver.py (major refactor)
  • app/core/game_engine.py (update calls)

Goal: Integrate result charts and runner advancement into play resolution

Changes:

  1. Add league_id and auto_mode params to PlayResolver.init()
  2. Create PdAutoResultChart for PD auto mode
  3. Update resolve_play() to use result chart when in auto mode
  4. Integrate RunnerAdvancement for all plays
  5. Store hit_location in play results
  6. Update all callers (game_engine, terminal_client)

Files to Update:

  • app/core/play_resolver.py - Major refactor
  • app/core/game_engine.py - Update resolve_play calls
  • tests/unit/core/test_play_resolver.py - Update existing tests
  • terminal_client/commands.py - Update for auto mode support

Test Command:

export PYTHONPATH=. && pytest tests/unit/core/test_play_resolver.py -v

Acceptance Criteria:

  • PlayResolver accepts league_id and auto_mode params
  • PD auto mode uses PdAutoResultChart
  • Manual mode bypasses result charts (expects ManualOutcomeSubmission)
  • RunnerAdvancement called for all groundball outcomes
  • Hit location stored in play results
  • All existing tests pass (no regressions)
  • Terminal client works with both modes
  • Integration tests verify end-to-end groundball advancement

Files to Review Before Starting

For Task 6 (PlayResolver Integration):

  1. app/core/runner_advancement.py - NEW RunnerAdvancement class to integrate
  2. app/core/play_resolver.py - Entire file needs refactor
  3. app/core/game_engine.py - resolve_play calls that need updating
  4. app/config/result_charts.py - ResultChart interface and hit location helpers
  5. tests/unit/core/test_play_resolver.py - Update all existing tests
  6. tests/unit/core/test_runner_advancement.py - Reference for advancement behavior

Verification Steps

After Task 6:

  1. Run unit tests:

    # Runner advancement tests
    export PYTHONPATH=. && pytest tests/unit/core/test_runner_advancement.py -v
    
    # Play resolver tests
    export PYTHONPATH=. && pytest tests/unit/core/test_play_resolver.py -v
    
    # All core tests
    export PYTHONPATH=. && pytest tests/unit/core/ -v
    
  2. Run all tests (check for regressions):

    export PYTHONPATH=. && pytest tests/unit/ -v
    
  3. Terminal client testing:

    python -m terminal_client
    > new_game --league pd --auto
    > defensive normal normal normal
    > offensive normal
    > resolve  # Auto mode
    
    > new_game --league sba
    > roll_dice
    > manual_outcome groundball_c SS  # Manual mode
    > status
    
  4. Commit after each task:

    git add [modified files]
    git commit -m "CLAUDE: Implement Week 7 Task [N] - [Task Name]"
    

Success Criteria

Week 7 will be 100% complete when:

  • Task 1: Strategic Decision Integration (DONE)
  • Task 2: Decision Validators (DONE - 54 tests passing)
  • Task 3: Result Charts + PD Auto Mode (DONE - 21 tests passing)
  • Task 4: Runner Advancement Logic (DONE - 30 tests passing)
  • Task 5: Double Play Mechanics (DONE - integrated into Task 4)
  • Task 6: PlayResolver Integration (all existing tests still pass)
  • Task 7: WebSocket Manual Outcome Handlers (DONE - 12 tests passing)
  • Task 8: Terminal Client Enhancement (DONE - manual commands working)
  • All 130+ new tests passing (currently 117/130 done - 90%)
  • Terminal client demonstrates both auto and manual modes
  • Documentation updated
  • Git commits for each task

Week 8 will begin with:

  • Substitution system (pinch hitters, defensive replacements)
  • Pitching changes (bullpen management)
  • Frontend game interface (mobile-first)

Quick Reference

Current Test Count: ~519 tests passing

  • Config tests: 79/79 (58 + 21 new from Task 3)
  • Validators: 54/54
  • Runner advancement: 30/30 (NEW from Tasks 4 & 5)
  • WebSocket handlers: 12/12 (NEW from Task 7)
  • Play resolver tests: 19/19
  • Dice tests: 34/35 (1 pre-existing failure)
  • Roll types tests: 27/27
  • Player models: 32/32
  • Game models: ~150+
  • State manager: ~80+

Target Test Count After Week 7: ~550+ tests Current Progress: 519/550 (94%)

Last Test Run: All passing except 1 pre-existing (2025-10-30) Branch: implement-phase-2 Python: 3.13.3 Virtual Env: backend/venv/ Database: PostgreSQL @ 10.10.0.42:5432 (paperdynasty_dev)

Key Imports for Week 7 Remaining Tasks:

from app.config import get_league_config, PlayOutcome
from app.config.result_charts import calculate_hit_location, PdAutoResultChart, ManualOutcomeSubmission
from app.core.dice import AbRoll
from app.core.validators import game_validator, ValidationError
from app.core.state_manager import state_manager
from app.core.ai_opponent import ai_opponent
from app.models.game_models import DefensiveDecision, OffensiveDecision, GameState, ManualOutcomeSubmission

Recent Commit History (Last 10):

102cbb6 - CLAUDE: Implement Week 7 Tasks 4 & 5 - Runner advancement logic and double play mechanics
9cae63a - CLAUDE: Implement Week 7 Task 7 - WebSocket manual outcome handlers
9b03fb5 - CLAUDE: Implement play rollback functionality for error recovery
8ecce0f - CLAUDE: Implement forced outcome feature for terminal client testing
16ba30b - CLAUDE: Update NEXT_SESSION.md with Week 7 Task 3 completion status
9245b4e - CLAUDE: Implement Week 7 Task 3 - Result chart abstraction and PD auto mode
c0051d2 - CLAUDE: Fix defensive decision validation for corners_in/infield_in depths
f07d8ca - CLAUDE: Update NEXT_SESSION.md - Task 2 complete
121a908 - CLAUDE: Implement Week 7 Task 2 - Decision Validators
0a21eda - CLAUDE: Update project plan for Week 7 continuation

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 @CLAUDE.md
  • Architecture: See @.claude/implementation/00-index.md
  • Backend guide: See @backend/CLAUDE.md
  • Current phase details: See @.claude/implementation/03-gameplay-features.md
  • Week 7 detailed plan: See @.claude/implementation/WEEK_7_PLAN.md

Critical files for current work (Week 7 Task 6):

  1. app/core/runner_advancement.py - COMPLETE - Runner advancement logic with 13 result types
  2. app/core/play_resolver.py - UPDATE for Task 6 (integrate RunnerAdvancement)
  3. app/core/game_engine.py - UPDATE for Task 6 (update resolve_play calls)
  4. app/config/result_charts.py - REFERENCE for hit location logic
  5. tests/unit/core/test_runner_advancement.py - REFERENCE for advancement behavior
  6. tests/unit/core/test_play_resolver.py - UPDATE with integration tests

What NOT to do:

  • Don't modify database schema without migration
  • Don't use Python's datetime module (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 - all decisions must be validated
  • Don't implement full AI logic yet (Week 9 task)
  • Don't commit without "CLAUDE: " prefix
  • Don't forget export PYTHONPATH=. when running tests
  • Don't try to change PlayOutcome with decision modifiers (affects advancement, not outcome)

Patterns we're using:

  • Pydantic dataclasses for models
  • Async/await for all database operations
  • Frozen configs for immutability
  • asyncio.Future for decision queue
  • Validator pattern with clear error messages
  • Result chart abstraction for league-specific resolution
  • Manual vs auto mode separation (manual = WebSocket, auto = result charts)
  • Hit location tracking for advancement logic
  • TODO comments for future work (Week 9 AI, Week 8 substitutions)

Manual Mode Flow:

# 1. Player requests action
> resolve

# 2. Server rolls dice
dice = dice_system.roll_ab(game_id)

# 3. Server broadcasts dice to players via WebSocket
emit('dice_rolled', {column_d6, row_2d6, chaos_d20})

# 4. Players read physical cards
[Human player looks at card]

# 5. Player submits outcome via WebSocket
emit('submit_manual_outcome', {
    outcome: 'groundball_c',
    hit_location: 'SS'
})

# 6. Server validates ManualOutcomeSubmission
submission = ManualOutcomeSubmission(**data)

# 7. Server resolves play with manual outcome
result = play_resolver.resolve_with_manual_outcome(submission, state)

# 8. Server broadcasts result
emit('play_resolved', result)

Auto Mode Flow:

# 1. Player requests action
> resolve

# 2. Server generates outcome automatically
outcome, location = result_chart.get_outcome(roll, state, batter, pitcher)

# 3. Server resolves play with auto outcome
result = play_resolver.resolve_play(outcome, location, state)

# 4. Server broadcasts result
emit('play_resolved', result)

Estimated Time for Next Session: 3-4 hours (Task 6 only - final task!) Priority: High (completes Week 7) Blocking Other Work: No (WebSocket handlers and terminal client already complete) Next Milestone After This: Week 8 - Substitutions + Frontend UI

Status: Week 7 is 87% complete, only PlayResolver integration remaining!