---
phase: 05-jamtrack-implementation
plan: 05
type: execute
---

<objective>
Add comprehensive error handling, apply performance optimizations, and conduct user acceptance testing.

Purpose: Complete JamTrack player with production-ready error handling, React performance optimizations from Phase 3, and validate all functionality through systematic UAT.
Output: Production-ready JamTrack player with documented known issues (if any).
</objective>

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

<context>
@.planning/PROJECT.md
@.planning/ROADMAP.md
@.planning/STATE.md
@.planning/phases/05-jamtrack-implementation/05-CONTEXT.md
@.planning/phases/05-jamtrack-implementation/05-04-SUMMARY.md
@.planning/phases/04-jamtrack-research-design/IMPLEMENTATION_ROADMAP.md
@.planning/phases/03-backing-track-finalization/03-03-SUMMARY.md
@jam-ui/src/components/client/JKSessionBackingTrackPlayer.js
@jam-ui/src/components/client/JKSessionJamTrackPlayer.js

**From Phase 3 patterns:**
- Error types: file (red), network (red), playback (yellow), general (yellow)
- Error display: banner with dismiss and retry buttons
- Network resilience: stop polling after 3 consecutive failures
- Edge cases: invalid files, null jamClient, disconnected native client
- Cleanup on unmount: prevent stale state bugs
- Performance: useCallback, useMemo, conditional updates, remove diagnostic logging

**From Phase 4 risk analysis:**
- HIGH risks: Download/sync state machine complexity, native client race conditions
- Expected: 2-4 deferred issues similar to Phase 3 (end-of-track double-click, loop not working)
- UAT deferral threshold: Defer minor only, fix medium+ issues

**From Phase 5 context:**
- Match Backing Track player quality bar
- All three pillars equally important (download, playback, mixdown selection)
</context>

<tasks>

<task type="auto">
  <name>Task 1: Add comprehensive error handling</name>
  <files>jam-ui/src/components/client/JKSessionJamTrackPlayer.js</files>
  <action>
Enhance error handling throughout the component:

**1. Add error types:**
```javascript
const ERROR_TYPES = {
  FILE: 'file', // Red - critical
  NETWORK: 'network', // Red - critical
  DOWNLOAD: 'download', // Red - critical
  PLAYBACK: 'playback', // Yellow - warning
  GENERAL: 'general' // Yellow - warning
};
```

**2. Enhance error display in render:**
```javascript
{error && (
  <div
    style={{
      background: (error.type === ERROR_TYPES.FILE || error.type === ERROR_TYPES.NETWORK || error.type === ERROR_TYPES.DOWNLOAD) ? '#fee' : '#ffd',
      padding: '10px',
      marginBottom: '10px',
      border: '1px solid',
      borderColor: (error.type === ERROR_TYPES.FILE || error.type === ERROR_TYPES.NETWORK || error.type === ERROR_TYPES.DOWNLOAD) ? '#fcc' : '#fc6'
    }}
  >
    <strong>{error.type.toUpperCase()} ERROR:</strong> {error.message}
    <div style={{ marginTop: '5px' }}>
      <button onClick={() => setError(null)}>Dismiss</button>
      {(error.type === ERROR_TYPES.NETWORK || error.type === ERROR_TYPES.DOWNLOAD || error.type === ERROR_TYPES.FILE) && (
        <button onClick={handleRetryError} style={{ marginLeft: '5px' }}>Retry</button>
      )}
    </div>
  </div>
)}
```

**3. Add handleRetryError:**
```javascript
const handleRetryError = useCallback(async () => {
  if (!error || isOperating) return;

  setError(null);

  // Retry based on error type
  if (error.type === ERROR_TYPES.DOWNLOAD || error.type === ERROR_TYPES.FILE) {
    await handleRetryDownload();
  } else if (error.type === ERROR_TYPES.NETWORK) {
    // Re-initialize player
    if (jamTrack && jamClient) {
      const fqId = await buildFqId();
      fqIdRef.current = fqId;
      await dispatch(loadJamTrack({ jamTrack, mixdownId: selectedMixdownId, autoPlay: false, jamClient }));
    }
  }
}, [error, isOperating, jamTrack, jamClient, selectedMixdownId, handleRetryDownload, buildFqId, dispatch]);
```

**4. Add network resilience to polling:**
```javascript
const consecutiveFailuresRef = useRef(0);

// In polling effect, wrap try/catch:
try {
  // ... existing polling logic ...
  consecutiveFailuresRef.current = 0; // Reset on success
} catch (err) {
  console.error('[JamTrack] Polling error:', err);
  consecutiveFailuresRef.current += 1;

  if (consecutiveFailuresRef.current >= 3) {
    setError({ type: ERROR_TYPES.NETWORK, message: 'Lost connection to native client. Check if JamKazam is running.' });
    // Stop polling by setting isPlaying to false
    dispatch(setJamTrackState({ isPlaying: false }));
  }
}
```

**5. Add edge case handling:**
```javascript
// In initializePlayer, before any jamClient calls:
if (!jamClient) {
  setError({ type: ERROR_TYPES.GENERAL, message: 'Native client not available. Please ensure JamKazam is running.' });
  return;
}

if (!jamTrack || !jamTrack.id) {
  setError({ type: ERROR_TYPES.FILE, message: 'Invalid JamTrack data' });
  return;
}
```

**Follow Phase 3 patterns:**
- Typed errors with color coding (red/yellow)
- User-friendly error messages
- Retry buttons for recoverable errors
- Network resilience (3 consecutive failures)
- Edge case validation (null jamClient, invalid jamTrack)
  </action>
  <verify>
1. grep "const ERROR_TYPES" jam-ui/src/components/client/JKSessionJamTrackPlayer.js (error types defined)
2. grep "consecutiveFailuresRef" jam-ui/src/components/client/JKSessionJamTrackPlayer.js (network resilience)
3. grep "handleRetryError" jam-ui/src/components/client/JKSessionJamTrackPlayer.js (retry handler)
4. Count error.type checks: should have file, network, download, playback, general
  </verify>
  <done>
- ERROR_TYPES constant defined (file, network, download, playback, general)
- Error display color-coded (red for critical, yellow for warnings)
- Retry button for recoverable errors (network, download, file)
- handleRetryError implemented with type-specific retry logic
- Network resilience: stop polling after 3 consecutive failures
- Edge case validation: null jamClient, invalid jamTrack data
- User-friendly error messages
- Dismiss button for all errors
  </done>
</task>

<task type="auto">
  <name>Task 2: Apply performance optimizations</name>
  <files>jam-ui/src/components/client/JKSessionJamTrackPlayer.js</files>
  <action>
Apply React performance optimizations from Phase 3:

**1. Add useMemo for computed values:**
```javascript
// Format time with useMemo
const formattedPosition = useMemo(
  () => formatTime(jamTrackState.currentPositionMs),
  [jamTrackState.currentPositionMs]
);

const formattedDuration = useMemo(
  () => formatTime(jamTrackState.durationMs),
  [jamTrackState.durationMs]
);

// Compute progress percentage
const progressPercent = useMemo(() => {
  if (!jamTrackState.durationMs || jamTrackState.durationMs === 0) return 0;
  return Math.round((jamTrackState.currentPositionMs / jamTrackState.durationMs) * 100);
}, [jamTrackState.currentPositionMs, jamTrackState.durationMs]);
```

**2. Verify all handlers use useCallback:**
- handlePlay ✓ (already has useCallback)
- handlePause ✓
- handleStop ✓
- handleSeek ✓
- handleMixdownChange ✓
- handleCancelDownload ✓
- handleRetryDownload ✓
- handleRetryError (add if not already)
- buildFqId ✓

**3. Verify conditional state updates in polling:**
```javascript
// Already implemented in Plan 3, verify:
if (
  position !== jamTrackState.currentPositionMs ||
  duration !== jamTrackState.durationMs
) {
  dispatch(setJamTrackState({ ... }));
}
```

**4. Verify visibility-aware polling:**
```javascript
// Already implemented in Plan 3, verify:
const isVisible = document.visibilityState === 'visible';
const pollInterval = isVisible ? 500 : 2000;
```

**5. Remove all diagnostic logging:**
```javascript
// Search for console.log statements and remove unless they're error logs
// Keep: console.error for error tracking
// Remove: console.log for debugging (e.g., "[JamTrack] Not synchronized, will download")
```

**6. Add React.memo if component re-renders unnecessarily:**
```javascript
// At export, wrap in memo if needed:
export default React.memo(JKSessionJamTrackPlayer);
```

**Follow Phase 3 patterns:**
- useMemo for computed values (formatted time, progress percentage)
- useCallback for all event handlers
- Conditional state updates (only update if values changed)
- Visibility-aware polling (500ms/2000ms)
- Clean console output (no diagnostic logs)
  </action>
  <verify>
1. grep "useMemo" jam-ui/src/components/client/JKSessionJamTrackPlayer.js (computed values memoized)
2. grep "useCallback" jam-ui/src/components/client/JKSessionJamTrackPlayer.js (all handlers wrapped)
3. grep "console.log" jam-ui/src/components/client/JKSessionJamTrackPlayer.js (should only find console.error, not console.log)
4. grep "React.memo" jam-ui/src/components/client/JKSessionJamTrackPlayer.js (component memoized)
  </verify>
  <done>
- useMemo added for formattedPosition, formattedDuration, progressPercent
- All handlers verified to use useCallback
- Conditional state updates verified in polling
- Visibility-aware polling verified (500ms/2000ms)
- Diagnostic console.log removed (only console.error remains)
- Component wrapped in React.memo at export
- Performance optimizations match Phase 3 Backing Track quality
  </done>
</task>

<task type="checkpoint:human-verify" gate="blocking">
  <what-built>Complete JamTrack player with download, playback, mixdown selection, error handling, and performance optimizations</what-built>
  <how-to-verify>
**Test Environment:**
1. Ensure JamKazam native client is running
2. Start jam-ui dev server: `cd jam-ui && npm run start`
3. Navigate to a session with JamTracks available
4. Open JamTrack player (modal or popup mode)

**Test Cases (40+ scenarios):**

**Initialization (4 cases):**
- [ ] JamTrack opens in modal mode
- [ ] JamTrack opens in popup mode (if supported)
- [ ] JamTrack already synced → shows player immediately
- [ ] JamTrack not synced → shows download UI

**Download/Sync (6 cases):**
- [ ] Download progress shows percentage (0-100%)
- [ ] Download progress shows step indicator ("Step X of Y")
- [ ] Download state transitions: checking → downloading → keying → synchronized
- [ ] Download completes, player becomes available
- [ ] Cancel button works during download (stops download)
- [ ] Download error shows error message with retry button

**Playback Controls (7 cases):**
- [ ] Play button starts playback
- [ ] Pause button pauses playback
- [ ] Stop button stops playback and resets position to 0
- [ ] Play after stop restarts from beginning
- [ ] Resume after pause continues from pause point
- [ ] Buttons disabled during operations (isOperating flag)
- [ ] Buttons disabled during sync check (isLoadingSync flag)

**Seek Slider (4 cases):**
- [ ] Seek slider moves during playback
- [ ] Drag seek slider to new position while playing → seeks immediately
- [ ] Drag seek slider while paused → updates UI, applies on resume (UAT-003 fix)
- [ ] Seek slider disabled before duration loads

**Mixdown Selection (5 cases):**
- [ ] Mixdown picker shows available mixdowns
- [ ] Mixdowns sorted: master → custom mixes → stems
- [ ] Visual indicators show mixdown types (🎵 🎨 🎸)
- [ ] Select different mixdown → playback stops and restarts
- [ ] Mixdown picker disabled during operations

**Display (5 cases):**
- [ ] Position displays in MM:SS format
- [ ] Duration displays in MM:SS format
- [ ] Seek slider position matches audio position
- [ ] Download progress updates in real-time
- [ ] Error messages display clearly

**Error Handling (5 cases):**
- [ ] Invalid JamTrack shows error
- [ ] Network failure during download shows error with retry
- [ ] Network failure during polling (after 3 failures) shows error
- [ ] Null jamClient shows "Native client not available" error
- [ ] Error dismiss button clears error

**Performance (4 cases):**
- [ ] No lag during playback
- [ ] Polling doesn't cause CPU spikes (check Activity Monitor)
- [ ] Visibility-aware polling: 500ms visible, 2000ms hidden (check intervals)
- [ ] Multiple JamTracks can be opened sequentially without issues

**Cleanup (4 cases):**
- [ ] Close modal → playback stops
- [ ] Close popup → playback stops
- [ ] Open different JamTrack → previous stops
- [ ] No console errors after interactions

**Known Issues from Phase 3 (check if they apply):**
- [ ] End-of-track restart requires double-click? (Minor - defer if present)
- [ ] Loop functionality? (Not in scope for Phase 5)
- [ ] Volume control in popup mode? (Not in scope - defer if issue)

**Pass Criteria:**
- Core functionality works (download, playback, mixdown selection)
- No critical errors (red errors should be rare, retryable)
- Performance acceptable (no lag, smooth playback)
- Known issues documented (minor issues OK to defer)

**If issues found:**
- CRITICAL (blocks functionality): Describe issue, I'll fix immediately
- MEDIUM (feature not working): Describe issue, decide fix now or defer
- MINOR (UX inconvenience): Document in ISSUES.md, defer to future work
  </how-to-verify>
  <resume-signal>Type "approved" if UAT passes, or describe issues found with severity (critical/medium/minor)</resume-signal>
</task>

</tasks>

<verification>
Before presenting UAT checkpoint:
- [ ] Error handling comprehensive (5 error types, retry logic, network resilience)
- [ ] Performance optimizations applied (useMemo, useCallback, conditional updates, clean logs)
- [ ] All code follows Phase 3 patterns
- [ ] Component ready for manual testing
</verification>

<success_criteria>

- Comprehensive error handling: 5 error types (file, network, download, playback, general)
- Error display color-coded (red for critical, yellow for warnings)
- Retry logic for recoverable errors
- Network resilience (stop polling after 3 failures)
- Edge case validation (null jamClient, invalid data)
- Performance optimizations: useMemo, useCallback, conditional updates, visibility-aware polling
- Diagnostic logging removed (only console.error)
- Component wrapped in React.memo
- UAT conducted with 40+ test cases
- Known issues documented (if any)
- Phase 5 complete: JamTrack player production-ready
</success_criteria>

<output>
After UAT completion, create `.planning/phases/05-jamtrack-implementation/05-05-SUMMARY.md`:

# Phase 5 Plan 5: Error Handling & Final UAT Summary

**[Substantive one-liner - production-ready JamTrack player]**

## Accomplishments

- Comprehensive error handling with 5 error types
- Performance optimizations applied
- UAT conducted: [X]/40+ test cases passed
- Known issues documented (if any)

## Files Created/Modified

- `jam-ui/src/components/client/JKSessionJamTrackPlayer.js` - Error handling + performance

## UAT Results

**Working Features:** [list]

**Known Issues (Deferred):** [if any, with severity and root cause]

## Issues Encountered

[Problems during UAT and resolutions]

## Phase 5 Complete

JamTrack player is production-ready with:
- ✅ Download/sync with progress tracking
- ✅ Playback controls (play/pause/stop/seek)
- ✅ Mixdown selection (master/custom/stems)
- ✅ Comprehensive error handling
- ✅ Performance optimizations
- ⚠️ Known issues documented (if any)

**If UAT revealed issues requiring fixes:** Create `05-05-ISSUES.md` documenting deferred issues for future work.

## Next Phase Readiness

Phase 5 complete. Project ready for next phase (Phase 6: Metronome Research & Design).
</output>
