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:
@@ -1,9 +1,18 @@
|
||||
import { useEffect, useRef } from 'react';
|
||||
import { usePlaybackStore } from '../store/usePlaybackStore';
|
||||
import { useVibeStore } from '../store/useVibeStore';
|
||||
import { trackService } from '../services/trackService';
|
||||
import { vibeService } from '../services/vibeService';
|
||||
import type { Track } from '../types';
|
||||
|
||||
// Track ids whose next natural feedback transition should be skipped because
|
||||
// the caller (e.g. Vibe.tsx's dislike button) already recorded feedback for
|
||||
// them explicitly. Consumed once, then cleared.
|
||||
const suppressedFeedbackIds = new Set<string>();
|
||||
export function suppressAutoFeedback(trackId: string): void {
|
||||
suppressedFeedbackIds.add(trackId);
|
||||
}
|
||||
|
||||
// Threshold (seconds) above which a store position change is treated as a user
|
||||
// scrub and applied to the audio element. Keeps the timeupdate -> setPosition ->
|
||||
// effect loop from fighting itself.
|
||||
@@ -39,9 +48,6 @@ export const AudioEngine = () => {
|
||||
const endedNaturallyRef = useRef(false);
|
||||
// Track whether the current track has crossed the completion threshold.
|
||||
const crossedThresholdRef = useRef(false);
|
||||
// Track whether we've already recorded a completed play for the current track
|
||||
// (to avoid double-recording when both threshold crossed AND ended fires).
|
||||
const recordedCompletedRef = useRef(false);
|
||||
|
||||
// --- DOM -> store: media events -----------------------------------------
|
||||
useEffect(() => {
|
||||
@@ -73,16 +79,10 @@ export const AudioEngine = () => {
|
||||
if (store().isPlaying) store().pause();
|
||||
};
|
||||
const onEnded = () => {
|
||||
const trackId = loadedIdRef.current;
|
||||
if (trackId && !recordedCompletedRef.current) {
|
||||
endedNaturallyRef.current = true;
|
||||
recordedCompletedRef.current = true;
|
||||
try {
|
||||
void vibeService.feedback(trackId, 'completed').catch(() => {});
|
||||
} catch {
|
||||
/* best-effort */
|
||||
}
|
||||
}
|
||||
// Just flag it — applyTrack (below) is the single place that sends
|
||||
// feedback, on the resulting track-change, so completion is recorded
|
||||
// exactly once per track.
|
||||
endedNaturallyRef.current = true;
|
||||
store().next();
|
||||
};
|
||||
|
||||
@@ -114,21 +114,23 @@ export const AudioEngine = () => {
|
||||
// If it crossed the threshold OR ended naturally, record as completed.
|
||||
const prevId = loadedIdRef.current;
|
||||
const completed = endedNaturallyRef.current || crossedThresholdRef.current;
|
||||
if (prevId) {
|
||||
try {
|
||||
if (completed) {
|
||||
recordedCompletedRef.current = true;
|
||||
void vibeService.feedback(prevId, 'completed').catch(() => {});
|
||||
} else {
|
||||
void vibeService.feedback(prevId, 'skipped').catch(() => {});
|
||||
// Only vibe sessions want this feedback — plain library browsing
|
||||
// shouldn't write skip/completed evidence for tracks merely sampled.
|
||||
const inVibeSession = !!useVibeStore.getState().activeSessionId;
|
||||
if (prevId && inVibeSession) {
|
||||
if (suppressedFeedbackIds.delete(prevId)) {
|
||||
// Caller already recorded explicit feedback (e.g. dislike) for
|
||||
// this track — don't also record the implicit transition.
|
||||
} else {
|
||||
try {
|
||||
void vibeService.feedback(prevId, completed ? 'completed' : 'skipped').catch(() => {});
|
||||
} catch {
|
||||
/* best-effort */
|
||||
}
|
||||
} catch {
|
||||
/* best-effort */
|
||||
}
|
||||
}
|
||||
endedNaturallyRef.current = false;
|
||||
crossedThresholdRef.current = false;
|
||||
recordedCompletedRef.current = false;
|
||||
loadedIdRef.current = id;
|
||||
|
||||
if (!id) {
|
||||
|
||||
Reference in New Issue
Block a user