60533073ad
The recommendation metrics table was observable but not actionable: raw source strings (album:<uuid> one-offs) drowned the stable surfaces, and manual plays were excluded so skip rates had no control group. - SQL: include NULL-source rows (the baseline) and carry completion_n so family merges can weight avg_completion correctly. - Handler buckets raw sources into stable families (radio:<uuid> → Radio, album:/artist: → direct plays, etc.) grouped by surface intent: go-to / discovery / direct — each band judged against its job, since discovery mixes are expected to skip hotter. Families under 20 plays are flagged low-confidence, not hidden. - Settings card renders the baseline row and per-surface deltas in percentage points vs baseline (worse-than-baseline deltas in danger color), intent hint copy per group, low-data rows dimmed. - Pure-unit test for the bucketing/merge; DB test updated to the new contract (baseline included, radio:<uuid> collapse). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TsF3cNoKrqCYsU78cXC8U6
44 lines
1.2 KiB
TypeScript
44 lines
1.2 KiB
TypeScript
import { createQuery } from '@tanstack/svelte-query';
|
|
import { api } from './client';
|
|
|
|
// Mirrors internal/api/me_recommendation_metrics.go: raw play sources are
|
|
// bucketed server-side into stable surface families, grouped by intent, and
|
|
// anchored by the manual-plays baseline (milestone #127).
|
|
export type SurfaceMetric = {
|
|
key: string;
|
|
label: string;
|
|
plays: number;
|
|
skips: number;
|
|
skip_rate: number;
|
|
avg_completion: number;
|
|
low_confidence: boolean;
|
|
};
|
|
|
|
export type SurfaceIntent = 'go_to' | 'discovery' | 'direct';
|
|
|
|
export type SurfaceGroup = {
|
|
intent: SurfaceIntent;
|
|
label: string;
|
|
surfaces: SurfaceMetric[];
|
|
};
|
|
|
|
export type RecommendationMetrics = {
|
|
window_days: number;
|
|
baseline: SurfaceMetric | null;
|
|
groups: SurfaceGroup[];
|
|
};
|
|
|
|
export function getRecommendationMetrics(): Promise<RecommendationMetrics> {
|
|
return api.get<RecommendationMetrics>('/api/me/recommendation-metrics');
|
|
}
|
|
|
|
export const REC_METRICS_QUERY_KEY = ['settings', 'recommendation-metrics'] as const;
|
|
|
|
export function createRecommendationMetricsQuery() {
|
|
return createQuery({
|
|
queryKey: REC_METRICS_QUERY_KEY,
|
|
queryFn: getRecommendationMetrics,
|
|
staleTime: 60_000
|
|
});
|
|
}
|