fix(vibe): let a dislike outlive the session that heard it

Disliking a track in a Vibe wrote one row to the session ledger and
nothing else. The ledger only excludes a track from the session it was
recorded in, so the same track came back the next evening, and the one
after that. A dislike in a Vibe is the same verdict as a dislike
anywhere else, so it now takes the same path.

Two more things undid a dislike that did land. The library scan rewrote
every track's state from the file on disk, which restored every HIDDEN
track to LIBRARY on every scan; finding a file again says nothing about
whether the listener wants to hear it. And hiding only matched tracks in
LIBRARY, so a disliked probation recommendation stayed eligible.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KENqSChfyqWnor6ud2WWH6
This commit is contained in:
kami
2026-08-10 13:59:16 +04:00
parent 0749f6ad10
commit 5a73a6a6f3
4 changed files with 55 additions and 3 deletions
+8 -1
View File
@@ -213,8 +213,15 @@ export class ScannerService {
mtime = EXTRACT(EPOCH FROM NOW()),
-- Existing recommendation rows stay recommendations during every
-- ordinary scan. This is load-bearing for probation and Vibe.
-- A dislike is a listener verdict on a file that is still on disk,
-- so finding that file again says nothing new: HIDDEN and DELETED
-- survive a rescan. Without this every scan restored every disliked
-- track to LIBRARY and the Vibe served it again.
state = CASE WHEN tracks.source_type = 'RECOMMENDATION'
THEN tracks.state ELSE EXCLUDED.state END,
THEN tracks.state
WHEN tracks.state IN ('HIDDEN', 'DELETED')
THEN tracks.state
ELSE EXCLUDED.state END,
source_type = CASE WHEN tracks.source_type = 'RECOMMENDATION'
THEN tracks.source_type ELSE $8::track_source_type END,
probation_status = CASE WHEN tracks.source_type = 'RECOMMENDATION'