---
phase: 03-backing-track-finalization
type: execute
---

<objective>
Add comprehensive error handling, loading states, and resilience to the backing track player.

Purpose: Transform the player from working-in-happy-path to production-ready with proper error handling for jamClient failures, file errors, network issues, and graceful degradation.

Output: Robust backing track player with error states, loading indicators, disabled controls during transitions, and user-friendly error messages.
</objective>

<execution_context>
@./.claude/get-shit-done/workflows/execute-phase.md
@./.claude/get-shit-done/templates/summary.md
</execution_context>

<context>
@.planning/PROJECT.md
@.planning/ROADMAP.md
@.planning/STATE.md
@.planning/phases/02-backing-track-seek-controls/02-01-SUMMARY.md
@.planning/phases/03-backing-track-finalization/03-01-SUMMARY.md
@jam-ui/src/components/client/JKSessionBackingTrackPlayer.js

**Error patterns from Phase 2:**
- Current error handling: console.error() but continues (doesn't inform user)
- No loading states during async operations
- No disabled states during transitions
- jamClient calls can fail (network, file issues, state errors)

**Established patterns:**
- jamClient always async/await
- jamClient returns strings - parseInt before use
- Defensive checks for null/undefined (formatTime already does this)

**Current error handling locations:**
- fetchDuration: logs error, sets '0:00' (lines 56-60)
- Polling interval: logs error, continues (line 98)
- handlePlay: logs error (line 123)
- handleStop: logs error (line 134)
- handleVolumeChange: logs error (line 155)
- handleLoopChange: logs error (line 170)
- handleSeek: logs error (line 194)
- handleClose: logs error, closes anyway (lines 202-209)

All current error handling is silent to user - just console.error().
</context>

<tasks>

<task type="auto">
  <name>Task 1: Add comprehensive error handling with user feedback</name>
  <files>jam-ui/src/components/client/JKSessionBackingTrackPlayer.js</files>
  <action>Add error state management and user-facing error handling:

**1. Add error state (after line 23):**
```javascript
const [error, setError] = useState(null);
const [errorType, setErrorType] = useState(null); // 'file', 'network', 'playback', 'general'
```

**2. Create error handler utility:**
```javascript
const handleError = (errorType, message, error) => {
  console.error(`[BTP] ${errorType}:`, message, error);
  setError(message);
  setErrorType(errorType);
};

const clearError = () => {
  setError(null);
  setErrorType(null);
};
```

**3. Enhance each error handler with user messages:**

- **fetchDuration failure (lines 56-60):**
  - Message: "Failed to load track duration"
  - Type: 'file'
  - Don't allow playback if duration fails

- **Polling failure (line 98):**
  - If repeated failures (3+ in a row), show error
  - Message: "Lost connection to audio engine"
  - Type: 'network'
  - Stop playback, allow retry

- **handlePlay failure (line 123):**
  - Message: "Failed to start playback"
  - Type: 'playback'
  - Reset isPlaying to false

- **handleStop failure (line 134):**
  - Message: "Failed to stop playback"
  - Type: 'playback'
  - Force reset UI state anyway

- **handleSeek failure (line 194):**
  - Message: "Failed to seek to position"
  - Type: 'playback'
  - Revert UI position to last known good

- **handleVolumeChange failure:**
  - Message: "Failed to adjust volume"
  - Type: 'playback'
  - Keep UI at last known good volume

- **handleLoopChange failure:**
  - Message: "Failed to toggle loop"
  - Type: 'playback'
  - Revert checkbox to previous state

**4. Add error display in UI (both modal and popup):**
- Show error alert/banner above controls when error exists
- Include error message and "Retry" or "Dismiss" button
- Use errorType to style differently (red for critical, yellow for warning)
- Add retry logic based on error type

**5. Add null jamClient checks:**
- Before every jamClient call, check if jamClient exists
- If null: show error "Audio engine not available", disable all controls

**Pattern to follow:**
```javascript
try {
  if (!jamClient) {
    handleError('general', 'Audio engine not available', null);
    return;
  }
  // ... existing logic
} catch (error) {
  handleError('playback', 'Failed to ...', error);
  // Revert UI state or prevent action
}
```</action>
  <verify>
Test error scenarios:
- Disconnect jamClient (set to null), verify error shown and controls disabled
- Simulate jamClient method failures, verify user sees error messages
- Verify error messages are clear and actionable
- Verify retry/dismiss buttons work correctly
- Verify UI state reverts appropriately on failures
  </verify>
  <done>Error state management implemented, all jamClient calls have user-facing error handling, errors displayed in UI with retry/dismiss options</done>
</task>

<task type="auto">
  <name>Task 2: Add loading and disabled UI states</name>
  <files>jam-ui/src/components/client/JKSessionBackingTrackPlayer.js</files>
  <action>Add loading states and disable controls during async operations:

**1. Add loading state flags (after line 23):**
```javascript
const [isLoading, setIsLoading] = useState(false);
const [isLoadingDuration, setIsLoadingDuration] = useState(true);
const [isOperating, setIsOperating] = useState(false); // General operation in progress
```

**2. Track duration loading (lines 47-61):**
- Set isLoadingDuration = true before fetch
- Set isLoadingDuration = false after fetch (success or error)
- Disable play button while isLoadingDuration = true

**3. Add operation flags for async handlers:**

- **handlePlay (lines 118-133):**
  - Set isOperating = true at start
  - Set isOperating = false at end (finally block)
  - Disable play/pause button while isOperating

- **handleStop (lines 161-171):**
  - Set isOperating = true at start
  - Set isOperating = false at end (finally block)
  - Disable stop button while isOperating

- **handleSeek (lines 208-227):**
  - Set isOperating = true at start
  - Set isOperating = false at end (finally block)
  - Disable slider while isOperating (prevent rapid seeks)

**4. Update button disabled logic:**

Current buttons disabled only when !backingTrack. Add additional conditions:
```javascript
disabled={!backingTrack || isLoadingDuration || isOperating || error}
```

For slider:
```javascript
disabled={!backingTrack || isLoadingDuration || isOperating}
```

**5. Add loading indicators:**

- While isLoadingDuration: Show "Loading..." text near duration display
- While isOperating: Show spinner icon on active button (play/stop/etc.)
- Use reactstrap Spinner component or FontAwesome spinner icon

**6. Prevent rapid clicks:**

Add debouncing to prevent multiple simultaneous operations:
- If isOperating = true, early return from handlers
- Clear check at start of each handler:
```javascript
if (isOperating) return;
setIsOperating(true);
```

**Pattern for handlers:**
```javascript
const handleAction = async () => {
  if (isOperating) return;
  setIsOperating(true);
  clearError();

  try {
    // ... existing logic
  } catch (error) {
    handleError(...);
  } finally {
    setIsOperating(false);
  }
};
```</action>
  <verify>
- Duration loading state shows "Loading..." before track ready
- Play button disabled until duration loaded
- Controls disabled during operations (can't double-click play)
- Loading indicators visible during async operations
- No way to trigger multiple simultaneous operations
- Smooth state transitions without flicker
  </verify>
  <done>Loading states implemented, controls properly disabled during transitions, loading indicators visible, no rapid-click issues</done>
</task>

<task type="auto">
  <name>Task 3: Handle file and network edge cases</name>
  <files>jam-ui/src/components/client/JKSessionBackingTrackPlayer.js</files>
  <action>Add defensive handling for edge cases and failure scenarios:

**1. Invalid/missing file handling:**

In fetchDuration (lines 47-61):
- If durationInMs is null, undefined, or '0', treat as invalid file
- Show specific error: "Invalid or unsupported audio file"
- Prevent playback (disable play button)
- Provide "Close" option to return to file browser

**2. Network disconnection handling:**

In polling interval (lines 68-109):
- Track consecutive failures (add `consecutiveErrors` ref)
- If 3+ consecutive polling errors:
  - Stop polling (clearInterval)
  - Show error: "Lost connection to audio engine"
  - Provide "Reconnect" button to restart polling
- Reset consecutiveErrors on successful poll

**3. jamClient null/undefined guards:**

Add defensive checks at component entry points:
- useEffect initialization (line 39): Check jamClient exists before setup
- Each handler: Early return with error if !jamClient
- Polling: Check jamClient before each poll iteration

**4. Stale state protection:**

Add cleanup on unmount:
```javascript
useEffect(() => {
  return () => {
    // Cleanup: stop playback on unmount
    if (jamClient && isPlaying) {
      jamClient.SessionStopPlay().catch(console.error);
    }
  };
}, [jamClient, isPlaying]);
```

**5. Invalid state recovery:**

If player gets into inconsistent state (e.g., isPlaying=true but jamClient says not playing):
- Polling should detect this (trackIsPlaying !== isPlaying)
- Force sync UI to jamClient state
- Log warning to help debugging

**6. Graceful degradation:**

If critical features fail (duration, playback):
- Show error state but keep player open
- Provide "Close" and "Retry" options
- Don't crash or freeze UI

**7. File format validation (defensive):**

Add check in fetchDuration:
- If duration is very large (>10 hours) or very small (<1 second), show warning
- Suspicious durations might indicate parsing errors
- Still allow playback but log warning

**Pattern for edge case handling:**
```javascript
// Check for invalid states
if (anomalousCondition) {
  console.warn('[BTP] Anomalous condition detected:', details);
  handleError('validation', 'Unexpected state detected', null);
  // Attempt recovery or safe fallback
}
```</action>
  <verify>
Test edge cases:
- Load invalid audio file (wrong format, corrupt), verify error shown
- Simulate jamClient becoming null mid-session, verify graceful handling
- Simulate repeated polling failures, verify reconnect option
- Close player while playing, verify proper cleanup
- Verify no uncaught exceptions in any error scenario
- Check browser console for proper warning/error logging
  </verify>
  <done>Edge cases handled with defensive coding, graceful degradation for failures, proper cleanup on unmount, no uncaught exceptions</done>
</task>

</tasks>

<verification>
Before declaring plan complete:
- [ ] Error state management implemented with user-facing messages
- [ ] All jamClient calls have proper error handling
- [ ] Error UI displayed with retry/dismiss options
- [ ] Loading states show during async operations
- [ ] Controls disabled appropriately during transitions
- [ ] No rapid-click issues (operations properly debounced)
- [ ] Edge cases handled: invalid files, network loss, null jamClient
- [ ] Cleanup on unmount prevents memory leaks
- [ ] No uncaught exceptions in error scenarios
- [ ] User always has clear feedback on what's happening
</verification>

<success_criteria>

- Comprehensive error handling for all jamClient operations
- User-facing error messages with retry options
- Loading states during all async operations
- Controls disabled during transitions
- Edge cases handled gracefully
- No uncaught exceptions or crashes
- Proper cleanup on component unmount
- All changes committed with descriptive messages
- Ready for Plan 03-03 (performance optimization and UAT)
</success_criteria>

<output>
After completion, create `.planning/phases/03-backing-track-finalization/03-02-SUMMARY.md`:

# Phase 3 Plan 2: Error Handling & Resilience Summary

**Added production-ready error handling, loading states, and resilience to backing track player**

## Accomplishments

- Implemented error state management with user-facing messages
- Added loading states and disabled controls during transitions
- Handled edge cases: invalid files, network issues, null jamClient
- Added proper cleanup on component unmount
- No uncaught exceptions in any scenario

## Files Created/Modified

- `jam-ui/src/components/client/JKSessionBackingTrackPlayer.js` - Error handling, loading states, edge cases

## Decisions Made

- Error display approach: [Banner/alert above controls with retry/dismiss]
- Loading indicator style: [Spinner on buttons or separate indicator]
- Debounce strategy: [isOperating flag to prevent rapid clicks]

## Issues Encountered

[Any unexpected issues during implementation, or "None"]

## Next Phase Readiness

Ready for Plan 03-03 (Performance Optimization & Final UAT). Player is now resilient and production-ready for error scenarios.
</output>
