# Gameplay Loop Implementation - Session Handoff

**Date**: 2025-01-21
**Session Focus**: Connecting frontend gameplay UI to backend WebSocket handlers
**Status**: 🟡 In Progress - Defensive decisions working, testing offensive workflow next

---

## 🎯 Session Goals

Implement the core gameplay loop: dice rolling → outcome submission → play resolution

**Target Workflow**:
1. User submits defensive setup (infield/outfield positioning)
2. User submits offensive decision (batting action)
3. User rolls dice
4. User submits manual outcome (from physical card)
5. Backend resolves play and broadcasts result
6. Game state updates, play appears in feed

---

## ✅ What We Accomplished

### 1. **Connected Gameplay Loop Components**
- Fixed `submitManualOutcome()` signature in `useGameActions.ts`
- Added `play_resolved` WebSocket event handler
- Fixed game page to call outcome submission correctly
- Added missing TypeScript imports

### 2. **Fixed Decision Panel Visibility Issues**

**Root Cause**: Frontend was checking for `decision_phase: "defense"` but backend uses `"awaiting_defensive"`

**Files Modified**:
- `frontend-sba/store/game.ts` - Added checks for both naming conventions:
  ```typescript
  needsDefensiveDecision: checks 'defense' OR 'awaiting_defensive'
  needsOffensiveDecision: checks 'offensive_approach' OR 'awaiting_offensive'
  ```

### 3. **Fixed Game Start Issues**

**Problem**: Games were stuck in `decision_phase: "idle"` after lineups submitted

**Root Causes Fixed**:
1. Missing `game_engine` import in `backend/app/api/routes/games.py`
2. `start_game()` wasn't setting `decision_phase` after preparing first play

**Files Modified**:
- `backend/app/api/routes/games.py`:
  ```python
  from app.core.game_engine import game_engine  # Added import
  ```

- `backend/app/core/game_engine.py`:
  ```python
  # In start_game() after _prepare_next_play():
  state.decision_phase = "awaiting_defensive"  # Added this line
  ```

### 4. **Fixed State Updates After Decision Submission**

**Problem**: After submitting defensive decision, UI stayed on defensive panel instead of advancing to offensive

**Solution**: Frontend now requests updated game state after decision submissions

**File Modified**:
- `frontend-sba/composables/useWebSocket.ts`:
  ```typescript
  socketInstance.on('defensive_decision_submitted', (data) => {
    // Request updated game state to get new decision_phase
    socketInstance.emit('request_game_state', { game_id: gameStore.gameId })
  })
  ```

### 5. **Added Debug Logging**
- Added console logging in game page to debug panel visibility
- Logs show `decision_phase`, `needsDefensiveDecision`, `needsOffensiveDecision`, etc.

---

## 📁 Files Modified (Need Committing)

### Backend Changes
```
backend/app/api/routes/games.py
backend/app/core/game_engine.py
```

### Frontend Changes
```
frontend-sba/store/game.ts
frontend-sba/composables/useGameActions.ts
frontend-sba/composables/useWebSocket.ts
frontend-sba/pages/games/[id].vue
```

---

## ✅ What's Working Now

### ✓ Game Creation Flow
- Create game → submit lineups → game auto-starts
- Game enters `"awaiting_defensive"` phase immediately
- Frontend shows **Defensive Setup** panel

### ✓ Defensive Decision Submission
- User can select infield/outfield positioning
- Clicking "Submit" sends decision to backend
- Backend receives and processes decision
- Emits `defensive_decision_submitted` event
- Frontend requests updated game state

### ✓ WebSocket Communication
- Connection established successfully
- Events flowing backend → frontend
- `dice_rolled`, `outcome_accepted`, `play_resolved` handlers implemented

### ✓ Backend Game Engine
- All 15 WebSocket handlers implemented (Phase 3E-Final)
- Manual outcome workflow complete
- Play resolution working
- Database persistence functional

---

## 🔄 Current State

### What User Just Did
1. ✅ Created new game (ID: `0411d0ce-f41f-46eb-b0ac-23bae818d6ad`)
2. ✅ Saw defensive setup panel appear
3. ✅ Submitted defensive decision
4. ⚠️ Still seeing "Your Defensive Turn" indicator

### What Should Happen Next
After latest fix (requesting game state after submission), user should:
1. Refresh game page
2. Submit defensive decision again
3. Should see **Offensive Approach** panel appear
4. Select batting action → Submit
5. Should see **Gameplay Panel** with **Roll Dice** button

---

## 🧪 Testing Checklist

### ✅ Tested & Working
- [x] Game creation
- [x] Lineup submission
- [x] Game auto-start
- [x] Defensive panel appears
- [x] Defensive decision sends to backend

### ⏳ Next to Test
- [ ] Defensive submission → Offensive panel transition
- [ ] Offensive decision submission
- [ ] Offensive → Resolution phase (dice rolling)
- [ ] Dice roll button click
- [ ] Dice results display
- [ ] Manual outcome entry
- [ ] Outcome submission
- [ ] Play resolution display
- [ ] Play-by-play feed update
- [ ] Game state updates (score, outs, runners)
- [ ] Second at-bat (loop continues)

---

## 🔧 Technical Details

### Backend Decision Phase Values
```python
"idle"                  # Initial state (before start)
"awaiting_defensive"    # Waiting for defensive setup
"awaiting_offensive"    # Waiting for offensive approach
"resolution"            # Ready for dice rolling
```

### WebSocket Event Flow

**Decision Submission**:
```
Frontend: submit_defensive_decision →
Backend:  process → emit defensive_decision_submitted →
Frontend: request_game_state →
Backend:  game_state (with decision_phase: "awaiting_offensive") →
Frontend: Show offensive panel
```

**Dice Rolling & Outcome**:
```
Frontend: roll_dice →
Backend:  roll dice → emit dice_rolled →
Frontend: Show dice results →
User:     Read card, select outcome →
Frontend: submit_manual_outcome →
Backend:  validate & resolve → emit play_resolved →
Frontend: Display result, update state
```

### Key Store Properties
```typescript
// Game Store (frontend-sba/store/game.ts)
needsDefensiveDecision  // Shows defensive panel
needsOffensiveDecision  // Shows offensive panel
canRollDice            // Enables dice roll button
canSubmitOutcome       // Enables outcome submission
```

---

## 🐛 Known Issues & Workarounds

### Issue 1: Frontend Compilation Warnings
**Symptom**: "Element is missing end tag" errors in console
**Impact**: None - server still runs fine
**Status**: Cosmetic, doesn't affect functionality

### Issue 2: Old Games Stuck in "idle"
**Symptom**: Games created before our fixes still show "Waiting for strategic decisions"
**Workaround**: Create fresh games - old games won't auto-advance
**Fix**: Old games need manual state update or recreation

---

## 🚀 Quick Start for Next Session

### 1. Check Server Status
```bash
# Backend should be running on port 8000
# Frontend should be running on port 3001
```

### 2. Test Defensive → Offensive Transition
1. Go to current game: `http://localhost:3001/games/0411d0ce-f41f-46eb-b0ac-23bae818d6ad`
2. Submit defensive decision
3. **Should** see offensive panel appear now (after latest fix)

### 3. If Offensive Panel Appears - Continue Testing!
- Submit offensive decision
- Click "Roll Dice"
- Check dice results display
- Submit outcome
- Verify play resolution

### 4. If Still Stuck - Create Fresh Game
```
http://localhost:3001/games/create
```
New games will have all fixes applied.

---

## 📝 Pending Commits

### Gameplay Loop Connection (Already Committed)
```bash
git log --oneline -1
# 58b5deb CLAUDE: Connect gameplay loop - dice rolling and play resolution
```

### Decision Panel Fixes (Need Committing)
```bash
# Backend changes
backend/app/api/routes/games.py         # Added game_engine import
backend/app/core/game_engine.py         # Set decision_phase in start_game

# Frontend changes
frontend-sba/store/game.ts              # Check both decision_phase naming conventions
frontend-sba/composables/useWebSocket.ts # Request state after decision submissions
frontend-sba/pages/games/[id].vue       # Added debug logging
```

---

## 🎓 Lessons Learned

### 1. Backend/Frontend Contract Mismatches
**Issue**: Backend used "awaiting_defensive" but frontend checked for "defense"
**Solution**: Frontend now checks both variants for robustness

### 2. State Synchronization
**Issue**: Backend updated state but didn't broadcast changes
**Solution**: Frontend explicitly requests updated state after key events

### 3. Game Initialization
**Issue**: `start_game()` prepared play but didn't set decision_phase
**Solution**: Explicitly set initial decision_phase after prepare

### 4. Import Issues Can Fail Silently
**Issue**: Missing `game_engine` import caused silent failure with try/catch
**Solution**: Always verify imports are present and check logs for errors

---

## 📞 If You Get Stuck

### Check These First
1. **Backend logs**: `BashOutput` with filter for game ID or event names
2. **Browser console**: Look for `[Game Page] Panel visibility check:` log
3. **WebSocket events**: Check if events are being received
4. **Game state**: Look at `decision_phase` value in console log

### Common Fixes
- **Panels not showing**: Check `decision_phase` value, create fresh game
- **Events not working**: Check WebSocket connection status
- **State not updating**: Look for `game_state` or `game_state_update` events

---

## 🎯 Success Criteria

**Session Complete When**:
- [x] Defensive panel appears ✅
- [ ] Offensive panel appears after defensive submission
- [ ] Dice can be rolled
- [ ] Outcome can be submitted
- [ ] Play resolves and appears in feed
- [ ] Second at-bat starts automatically
- [ ] All changes committed

**Current Progress**: ~60% complete

---

## 📚 References

- **Backend Handlers**: `backend/app/websocket/handlers.py` (15 handlers, all implemented)
- **Game Engine**: `backend/app/core/game_engine.py` (Phase 3E-Final complete)
- **Frontend Components**: `frontend-sba/components/Gameplay/` (all built, partially connected)
- **Main Session Context**: `CLAUDE.md` in project root

---

**Next Session Goal**: Complete offensive decision → dice rolling → outcome submission flow

Good luck! 🚀
