-- 0027_system_playlist_rotation.up.sql — sample-history dedup for -- system playlists (Fable #415). Two parts: -- -- 1. play_events.source: which system playlist a play originated -- from ('for_you' | 'discover' | future kinds), or NULL for any -- play not launched from a system-playlist surface (library, -- user playlist, radio, Subsonic). Lets the ingest path know a -- play should count against that playlist's rotation. -- -- 2. system_playlist_rotation_state: per (user, playlist_kind) set -- of track ids already played in the current rotation window. -- Shuffle-on-play prefers the unplayed tail; when the snapshot -- is exhausted the set resets and rotation_started_at advances. -- Centralized server-side so phone / web / watch share one -- rotation, mirroring how radio dedup already lives server-side. ALTER TABLE play_events ADD COLUMN source text; CREATE TABLE system_playlist_rotation_state ( user_id uuid NOT NULL REFERENCES users(id) ON DELETE CASCADE, playlist_kind text NOT NULL, played_track_ids uuid[] NOT NULL DEFAULT '{}', rotation_started_at timestamptz NOT NULL DEFAULT now(), updated_at timestamptz NOT NULL DEFAULT now(), PRIMARY KEY (user_id, playlist_kind) );