Files
muzick/SESSION-07-07-2026.md
T

5.7 KiB
Raw Blame History

Session — 07 July 2026

Scaffolded: v2 Recommendation Engine — code complete, not yet deployed (Systems AE + Phase 4)

All six axioms encoded as running code. Every claim is evidence, not fact. MusicBrainz is the structural spine, not truth. Conflicts coexist in the graph.

Files created (8 new)

File Lines System
backend/src/services/generators.service.ts 446 C — 8 candidate generators
backend/src/services/session-director.service.ts 761 D — Session planner + fatigue + arcs
backend/src/services/discovery.service.ts 297 E — Graph walks + probation lifecycle
backend/src/services/image-enrichment.service.ts 105 Phase 4 — Image candidate pipeline
workers/src/mb-spine-writer.ts 136 A — MB artist-credit → claims writer (wired into enrichment.service.ts)
backend/src/routes/graph.routes.ts 152 Graph API (claims, fusion, sources, evidence)
backend/src/routes/v2.routes.ts 130 v2 vibe endpoints (start, next, feedback, state)
backend/src/routes/discovery.routes.ts 103 Discovery + image API endpoints

Files modified (3)

File Changes
backend/src/db/schema.sql +187 lines: 9 new tables + 2 ALTER TABLE + indexes
backend/src/services/db.service.ts +700 lines: 6 migrations, 12 new methods, 6 interfaces, evidence wiring in recordPlay/recordSkip/recordFeedback/dislikeTrack, listener-behavior writer in recordPlay
backend/src/app.ts +4 lines: imports + registrations for v2 + discovery routes

System-by-system

System A — Knowledge Graph (probabilistic fusion)

  • source_trust table: configurable trust weights (mb=0.90, tag=0.30, listener_behavior=0.40)
  • claims table: graph spine, unique on (subject, pred, object, source, user_id)
  • claim_fusion view: weighted vote SUM(trust × confidence × recency)
  • track_artists_v2 / album_artists_v2: compatibility views over fusion
  • recording_mbid on tracks: structural spine anchor
  • Methods: upsertClaim, upsertClaims, getClaimsBySubject, getFusedValue, getFusedTrackArtists
  • Backfill migration 20260707_backfill_claims: existing track_artists → claims (tag), artist_similar → same_scene_as (lastfm)

System B — Listener Model

  • evidence table: append-only signal stream
  • listener_beliefs table: per-profile beliefs with decay
  • Every play/skip/feedback writes evidence rows automatically
  • Methods: recordEvidence, recordEvidenceBatch, getListenerBeliefs, updateListenerBelief

System C — Candidate Generators (8 generators)

  • comfortGenerator: longterm affinity > 0.5 artists
  • adjacentGenerator: 2-hop graph walks from seed artist
  • discoveryGenerator: unfamiliar artists via same_scene_as from trusted artists, gated by novelty_tolerance
  • deepDiveGenerator: obsession album deep cuts in album order
  • revivalGenerator: stale high-affinity artists (>90d untouched)
  • experimentalGenerator: random unfamiliar genres
  • contextualGenerator: context-tagged preferences
  • noveltyGenerator: recent releases (≤60d) via same_scene_as/same_label_as/produced edges from trusted artists
  • All candidates carry non-empty ClaimEdge[] explanations (graph paths)

System D — Session Director (runs alongside v1; getNextVibeChunk not yet deleted)

  • buildState: energy from last 5 plays, novelty_hunger from discovery profile, session age
  • computeFatigue: exponential decay per dimension (track/7d-30d, artist/24h-8h, genre/24h-8h, language/2h-1h)
  • getBudgets: reads diversity_budgets, calculates spend from recent history
  • pickArc/getArcSlots: energy+novelty-based arc templates (comfort/discovery/energetic/late-night)
  • rankCandidates: multi-objective weighted sum (enjoyment, fatigue, diversity, entropy, repetition)
  • detectAntiLoop: Herfindahl-Hirschman Index + fatigue threshold
  • buildPlan/replan: full orchestration loop with slot filling
  • 27KB of planner logic

System E — Acquisition Pipeline

  • walkGraphForDiscovery: walks same_scene_as/featured_on edges to artists not in library
  • evalCandidates: fused relevance + novelty tolerance + diversity check → acquire/retire
  • evalProbation/sweepProbation: evidence-based retain/retire lifecycle
  • runMetaLearning: discovery source retention analysis
  • discovery_candidates + probation_status columns

Phase 4 — Image Candidates

  • fetchImagesForArtist/fetchImagesForAlbum: write candidate rows per source
  • selectBestImage: source-priority-tiered selection, updates image_path/artwork_id
  • image_candidates table with source/verified tracking

Evidence wiring (every interaction)

  • recordPlay → playback_completed (longterm +0.10) + replay_within_24h if applicable + alias_of/same_scene_as behavior claims
  • recordSkip → skip_quick (negative -0.20)
  • recordFeedback(promoted) → add_to_favorites (longterm +0.60)
  • recordFeedback(disliked) → hidden (negative -0.60)
  • dislikeTrack → hidden (negative -0.60)

Verification

  • npx tsc --noEmit — 0 errors
  • npx vitest run — 30/30 pass (mocked shape checks, not DB-state)
  • No git repo — changes uncommitted
  • NOT deployed: live backend container is pre-v2; /api/v2/* and /api/graph/* return 404; DB has zero v2 tables. See docs/architecture/v2-fix-plan.md for the fix + deploy plan.

Next

  • Execute docs/architecture/v2-fix-plan.md (MV refresh, decay job, bug fixes, deploy)
  • After deploy + verify: wire the v2 endpoint into the frontend Vibe page (replace v1 vibeService calls)
  • Build yt-dlp worker for System E acquisition (download candidates)
  • After v2 is verified in production: delete v1 CTE (getNextVibeChunk), vibe.routes.ts, feedback table, artist_similar table per the doc's "Retiring v1" list