---
phase: 26-jamtrack-polish
plan: 03
type: execute
wave: 3
depends_on: ["26-02"]
files_modified:
  - jam-ui/src/components/client/JKSessionScreen.js
  - jam-ui/src/components/client/JKSessionJamTrackPlayer.js
autonomous: true
gap_closure: true

must_haves:
  truths:
    - "Stems only appear in session screen after JamTrack is synchronized with backend"
    - "Player controls only appear after JamTrack is synchronized with backend"
    - "Already-synchronized JamTracks show stems/controls immediately without waiting"
  artifacts:
    - path: "jam-ui/src/components/client/JKSessionScreen.js"
      provides: "handleJamTrackSelect calls checkJamTrackSync before dispatching UI state"
      contains: "checkJamTrackSync"
    - path: "jam-ui/src/components/client/JKSessionScreen.js"
      provides: "Stems rendering gated by synchronized state only"
      contains: "jamTrackDownloadState.state === 'synchronized'"
    - path: "jam-ui/src/components/client/JKSessionJamTrackPlayer.js"
      provides: "Controls rendering gated by synchronized state only"
      contains: "downloadState.state === 'synchronized'"
  key_links:
    - from: "handleJamTrackSelect"
      to: "checkJamTrackSync thunk"
      via: "dispatch call before setting UI state"
      pattern: "dispatch\\(checkJamTrackSync"
    - from: "JKSessionScreen.js line 1406"
      to: "jamTrackDownloadState.state"
      via: "conditional rendering check"
      pattern: "jamTrackDownloadState\\.state === 'synchronized'"
    - from: "JKSessionJamTrackPlayer.js line 680"
      to: "downloadState.state"
      via: "conditional rendering check"
      pattern: "downloadState\\.state === 'synchronized'"
---

<objective>
Fix UAT issue where stems and controls appear before JamTrack is synchronized.

Two-part fix:
1. Call checkJamTrackSync in handleJamTrackSelect BEFORE dispatching UI state - this transitions downloadState from 'idle' to 'synchronized' (for cached tracks) or keeps it 'idle' (for non-synced tracks)
2. Remove 'idle' from render conditions - only 'synchronized' shows UI

Purpose: Ensure stems and controls only appear AFTER backend confirms the track is ready, while allowing already-synchronized tracks to appear immediately.
Output: Proper loading sequence: select → check sync → (download if needed) → show UI.
</objective>

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

<context>
@.planning/PROJECT.md
@.planning/ROADMAP.md
@.planning/STATE.md
@.planning/phases/26-jamtrack-polish/26-UAT.md
@.planning/debug/jamtrack-stems-before-sync.md
@jam-ui/src/components/client/JKSessionScreen.js (lines 1165-1190, 1400-1430)
@jam-ui/src/components/client/JKSessionJamTrackPlayer.js (lines 670-690)
@jam-ui/src/store/features/mediaSlice.js (checkJamTrackSync thunk)
</context>

<tasks>

<task type="auto">
  <name>Task 1: Call checkJamTrackSync in handleJamTrackSelect before dispatching UI state</name>
  <files>jam-ui/src/components/client/JKSessionScreen.js</files>
  <action>
The root cause is that handleJamTrackSelect (lines 1165-1190) dispatches UI state immediately without calling checkJamTrackSync. This means downloadState.state remains 'idle' (initial state) and never transitions to 'synchronized'.

**Step 1: Add checkJamTrackSync to the imports**

Find the mediaSlice imports (around line 40-60) and add checkJamTrackSync:

```javascript
import {
  // ... existing imports ...
  checkJamTrackSync,  // Add this
} from '../../store/features/mediaSlice';
```

**Step 2: Modify handleJamTrackSelect to call checkJamTrackSync first**

Replace lines 1165-1190 with:

```javascript
const handleJamTrackSelect = async (jamTrack) => {
  try {
    // Fetch jam track details with stems
    const response = await getJamTrack({ id: jamTrack.id });
    const jamTrackWithStems = await response.json();

    // Check sync state BEFORE dispatching UI state
    // This transitions downloadState from 'idle' to 'synchronized' (if already synced)
    // or keeps it 'idle' (if download needed)
    const syncResult = await dispatch(checkJamTrackSync({
      jamTrack: jamTrackWithStems,
      jamClient
    })).unwrap();

    // Set the selected jam track and stems (for display on session screen)
    dispatch(setSelectedJamTrack(jamTrackWithStems));
    dispatch(setJamTrackStems(jamTrackWithStems.tracks || []));

    // Open the JamTrack player popup (with full data needed for player)
    dispatch(setJamTrackData({
      jamTrack: jamTrackWithStems,
      session: currentSession,
      currentUser: currentUser
    }));

    // Show appropriate message based on sync state
    if (syncResult.isSynchronized) {
      toast.success(`Loaded JamTrack: ${jamTrackWithStems.name}`);
    } else {
      toast.info(`Loading JamTrack: ${jamTrackWithStems.name}...`);
    }
  } catch (error) {
    toast.error('Failed to load JamTrack');
  }
};
```

The key change is calling `checkJamTrackSync` BEFORE dispatching `setSelectedJamTrack` and `setJamTrackStems`. This ensures:
- For already-synced tracks: downloadState transitions from 'idle' to 'synchronized' → stems render immediately
- For non-synced tracks: downloadState stays 'idle' → stems don't render until download completes
  </action>
  <verify>
```bash
# Verify checkJamTrackSync is imported
grep -n "checkJamTrackSync" jam-ui/src/components/client/JKSessionScreen.js | head -3

# Verify it's called in handleJamTrackSelect
grep -A5 "const handleJamTrackSelect" jam-ui/src/components/client/JKSessionScreen.js | grep -q "checkJamTrackSync" && echo "checkJamTrackSync called in handleJamTrackSelect"
```
  </verify>
  <done>handleJamTrackSelect calls checkJamTrackSync before dispatching UI state, ensuring downloadState transitions from 'idle' to appropriate state</done>
</task>

<task type="auto">
  <name>Task 2: Remove 'idle' from stems render condition in JKSessionScreen</name>
  <files>jam-ui/src/components/client/JKSessionScreen.js</files>
  <action>
At line 1406, the render condition for JamTrack stems currently allows both 'synchronized' AND 'idle' states:

```javascript
(jamTrackDownloadState.state === 'synchronized' || jamTrackDownloadState.state === 'idle')
```

Now that Task 1 ensures checkJamTrackSync is called before UI state is set, we can safely remove 'idle' from the condition. The flow will be:
- Already-synced tracks: checkJamTrackSync → state='synchronized' → stems render
- Non-synced tracks: checkJamTrackSync → state='idle' → stems hidden until download completes

Change line 1406 to only check for 'synchronized':

```javascript
(jamTrackDownloadState.state === 'synchronized')
```

The full condition at line 1405-1406 should become:
```javascript
{selectedJamTrack && jamTrackStems.length > 0 &&
  (jamTrackDownloadState.state === 'synchronized') && (
```
  </action>
  <verify>
```bash
# Verify condition no longer includes 'idle'
grep -n "jamTrackDownloadState.state === 'synchronized'" jam-ui/src/components/client/JKSessionScreen.js | grep -v idle

# Verify 'idle' is NOT in the stems render condition
grep -n "jamTrackDownloadState.state === 'idle'" jam-ui/src/components/client/JKSessionScreen.js || echo "No 'idle' check found - correct"
```
  </verify>
  <done>JKSessionScreen stems render condition only checks for 'synchronized' state, not 'idle'</done>
</task>

<task type="auto">
  <name>Task 3: Remove 'idle' from controls render condition in JKSessionJamTrackPlayer</name>
  <files>jam-ui/src/components/client/JKSessionJamTrackPlayer.js</files>
  <action>
At line 680 (or nearby), the render condition for player controls currently allows both 'idle' AND 'synchronized' states:

```javascript
{(downloadState.state === 'idle' || downloadState.state === 'synchronized') && !isLoadingSync && (
```

Change to only check for 'synchronized':

```javascript
{(downloadState.state === 'synchronized') && !isLoadingSync && (
```

This ensures controls only appear AFTER the track is fully synchronized with the backend. The download progress UI (lines 593-670) already handles the loading states, so the user will see:
1. Select JamTrack → checkJamTrackSync runs
2. If not synced: loading indicator → download progress → controls appear
3. If already synced: controls appear immediately
  </action>
  <verify>
```bash
# Verify condition no longer includes 'idle'
grep -n "downloadState.state === 'synchronized'" jam-ui/src/components/client/JKSessionJamTrackPlayer.js | head -3

# Verify 'idle' is NOT in the controls render condition
grep -n "downloadState.state === 'idle'" jam-ui/src/components/client/JKSessionJamTrackPlayer.js || echo "No 'idle' check found - correct"
```
  </verify>
  <done>JKSessionJamTrackPlayer controls render condition only checks for 'synchronized' state, not 'idle'</done>
</task>

<task type="auto">
  <name>Task 4: Build verification</name>
  <files>None (verification only)</files>
  <action>
Run build to verify no syntax errors from the changes:

```bash
cd jam-ui && npm run build
```

The expected behavior after all changes:
1. User selects JamTrack
2. handleJamTrackSelect fetches data and calls checkJamTrackSync
3. If already synchronized: downloadState='synchronized' → stems render immediately
4. If not synchronized: downloadState='idle' → stems hidden, user sees loading
5. When download completes: downloadState='synchronized' → stems appear
  </action>
  <verify>
Build command exits with code 0 and no compilation errors.
  </verify>
  <done>Build passes with no errors, changes are syntactically correct</done>
</task>

</tasks>

<verification>
1. Build check: `cd jam-ui && npm run build` completes without errors
2. Code verification:
   - JKSessionScreen.js imports checkJamTrackSync
   - handleJamTrackSelect calls checkJamTrackSync BEFORE dispatching setSelectedJamTrack
   - JKSessionScreen.js line 1406: condition is `(jamTrackDownloadState.state === 'synchronized')` WITHOUT 'idle'
   - JKSessionJamTrackPlayer.js line 680: condition is `(downloadState.state === 'synchronized')` WITHOUT 'idle'
3. Grep confirms no references to 'idle' in render conditions for stems/controls
</verification>

<success_criteria>
- handleJamTrackSelect calls checkJamTrackSync before dispatching UI state
- JKSessionScreen stems only render when jamTrackDownloadState.state === 'synchronized'
- JKSessionJamTrackPlayer controls only render when downloadState.state === 'synchronized'
- Already-synchronized JamTracks show stems/controls immediately (checkJamTrackSync returns synchronized)
- Non-synchronized JamTracks don't show stems/controls until download completes
- Build passes with no errors
- UAT gap "Controls and stems should only appear after JamTrack is synchronized" is closed
</success_criteria>

<output>
After completion, create `.planning/phases/26-jamtrack-polish/26-03-SUMMARY.md`
</output>
