fix vibe engine audit findings: pg.Pool, plan replan, dead exclusions, legacy engine removal
Backend: - app.ts: switch shared pg.Client to pg.Pool with per-transaction clients (#205) - v2.routes.ts: replace plan instead of appending on replan, fixing self-duplication (#206) - session-director: populate recentExclusions, per-candidate ranking, batch repetition checks (#209/#211/#213/#215 + minor) - db.service.ts: claim-fusion watermark, legacy recommendation_batch engine removed (#216/#219/#232) - app.ts: drop test enqueue-job endpoint (#234) Frontend: - AudioEngine/Vibe/usePlaybackStore: dedupe completed feedback, gate feedback to vibe sessions, End Vibe stops playback, Keep toast, shuffle played-set (#207/#236/#237/#238/#239/#240) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -9,6 +9,8 @@ import { TrackRow } from '../components/TrackRow';
|
||||
import { PageContainer } from '../components/PageContainer';
|
||||
import type { Track } from '../types';
|
||||
import { VibeTimeline } from '../components/VibeTimeline';
|
||||
import { suppressAutoFeedback } from '../components/AudioEngine';
|
||||
import { toast } from '../store/useToastStore';
|
||||
|
||||
const INITIAL_BATCH_SIZE = 5;
|
||||
const PREFETCH_THRESHOLD = 3;
|
||||
@@ -19,7 +21,7 @@ function bestEffort(p: Promise<unknown>): void {
|
||||
}
|
||||
|
||||
export default function Vibe() {
|
||||
const { currentTrack, queue, setQueue, playTrack, next: playNext } = usePlaybackStore();
|
||||
const { currentTrack, queue, setQueue, playTrack, next: playNext, pause, setCurrentTrack } = usePlaybackStore();
|
||||
const {
|
||||
activeSessionId,
|
||||
buffer,
|
||||
@@ -117,23 +119,34 @@ export default function Vibe() {
|
||||
if (idx > 0) {
|
||||
setBuffer(buffer.slice(idx));
|
||||
}
|
||||
}, [activeSessionId, currentTrack]);
|
||||
}, [activeSessionId, currentTrack, buffer, setBuffer]);
|
||||
|
||||
const handleKeep = useCallback(() => {
|
||||
if (currentTrack) bestEffort(vibeService.feedback(currentTrack.id, 'promoted'));
|
||||
if (currentTrack) {
|
||||
bestEffort(vibeService.feedback(currentTrack.id, 'promoted'));
|
||||
toast.success(`Kept "${currentTrack.title}"`);
|
||||
}
|
||||
}, [currentTrack]);
|
||||
|
||||
const handleDislike = useCallback(() => {
|
||||
if (currentTrack) bestEffort(vibeService.feedback(currentTrack.id, 'disliked'));
|
||||
if (currentTrack) {
|
||||
bestEffort(vibeService.feedback(currentTrack.id, 'disliked'));
|
||||
// AudioEngine would otherwise also record a 'skipped' on the track
|
||||
// change caused by playNext() below — suppress that duplicate.
|
||||
suppressAutoFeedback(currentTrack.id);
|
||||
}
|
||||
playNext();
|
||||
}, [currentTrack, playNext]);
|
||||
|
||||
const handleEnd = useCallback(() => {
|
||||
// V2 plan expires via Redis TTL (2h). No explicit end endpoint.
|
||||
pause();
|
||||
setQueue([]);
|
||||
setCurrentTrack(null);
|
||||
reset();
|
||||
setEmpty(false);
|
||||
setError(null);
|
||||
}, [reset]);
|
||||
}, [reset, pause, setQueue, setCurrentTrack]);
|
||||
|
||||
const upcoming = currentTrack
|
||||
? (() => {
|
||||
@@ -208,12 +221,12 @@ export default function Vibe() {
|
||||
<div className="space-y-2">
|
||||
<h2 className="text-sm font-semibold text-muted">Or pick a seed track</h2>
|
||||
<ul className="max-h-72 space-y-1 overflow-y-auto">
|
||||
{libraryTracks.map((track) => (
|
||||
{libraryTracks.map((track, index) => (
|
||||
<li key={track.id}>
|
||||
<TrackRow
|
||||
track={track}
|
||||
queue={libraryTracks}
|
||||
index={libraryTracks.findIndex((t) => t.id === track.id)}
|
||||
index={index}
|
||||
showActions={false}
|
||||
/>
|
||||
</li>
|
||||
|
||||
Reference in New Issue
Block a user