# Recommendation & Vibe Specification

This document defines the logic for the "Vibe" engine, moving from simple similarity to a continuous, evolving listening experience.

## 1. The "Vibe" Concept
The "Vibe" is an infinite, stateful listening session. Unlike a static playlist, it is a **Rolling Window** that evolves based on user interaction.

## 2. Scoring Logic

When generating a sequence, every candidate track is assigned a score.

$$Score = (W_{genre} \cdot S_{genre}) + (W_{artist} \cdot S_{artist}) + (W_{random} \cdot R)$$

### **Scoring Components**
* **$S_{genre}$ (Genre Match):** 
    * Uses hierarchical weights (e.g., `Deep House` (1.0) $\rightarrow$ `House` (0.8) $\rightarrow$ `Electronic` (0.5)).
    * Calculated as the highest weight match between candidate and "Center Track."
* **$S_{artist}$ (Artist Similarity):** 
    * A binary or weighted score based on whether the artist is in the user's "Liked" list or frequent listening history.
* **$R$ (Randomness/Exploration):** 
    * A jitter factor to ensure the queue doesn't feel repetitive.

## 3. The Rolling Window Algorithm

The backend does not return a fixed list. It returns a **Sequence Chunk**.

### **Step-by-Step Generation**
1.  **Identify the Center:** Find the `last_successfully_played_track_id`.
2.  **Candidate Selection:**
    * **Local Pool (80%):** Tracks from the user's library similar to the center track.
    * **Probation Pool (20%):** Tracks from the `recommendation_batch` that have `probation=1`.
3.  **Constraint Application (Batch Rules):**
    * **Diversity Check:** No more than 1 track from the same artist per chunk.
    * **Genre Cap:** No more than 2 tracks from the same genre per chunk.
4.  **Chunking:** Return a sequence of $N$ tracks (e.g., 20).

## 4. The "Vibe" Session Lifecycle

A "Vibe" is represented by a `recommendation_batch` record.

| State | Description |
| :--- | :--- |
| **ACTIVE** | The user is currently listening. The stream is being generated. |
| **RESOLVED** | The session has ended naturally or timed out. |
| **FAILED** | The session was interrupted by a critical error or manual reset. |

### **Transition Logic**
* **Start:** User clicks "Start Vibe" $\rightarrow$ Create `ACTIVE` batch.
* **Progress:** User listens $\rightarrow$ Update `last_interaction_at` in the batch.
* **Termination:** 
    * **Natural:** User exits the app $\rightarrow$ Session marked `RESOLVED` after 24h.
    * **Manual:** User ends session $\rightarrow$ Mark `RESOLVED` immediately.
    * **Timeout:** No interaction for 24h $\rightarrow$ Mark `RESOLVED`.

## 5. Success/Failure Feedback Loop

The engine learns from the `feedback` table:
* **`action = 'promoted'`:** (High Score) Increase weight of this genre/artist in future seeds.
* **`action = 'disliked'`:** (Negative Signal) Decrease weight of this genre/artist.
* **`action = 'skipped'`:** (Transient Negative) Do not adjust long-term weights, but avoid this specific track in the current session window.
