fix(db): apply sqlc's actual output for SuggestArtistsForUser — #2380
test-go / test (push) Successful in 1m2s
test-go / integration (push) Successful in 4m55s

The new codegen check failed on its first run, against the slice-1 hand-edit,
which is precisely why it landed on its own commit.

What I got wrong: sqlc does not embed the leading `--` header block in the SQL
const. It strips those lines and promotes them to the generated method's Go doc
comment, gofmt-formatted — blank `//` separators around the indented list, tabs
for the indent. My hand-edit left the header inside the string AND left the
stale M5c doc comment sitting on the function, so the generated file described
behaviour the query no longer had.

Comments *inside* the statement body are kept as-is; only the header block moves.
Worth knowing before slices 5 and 6 add more queries.

Taken verbatim from the diff the check printed, which is the reason it prints
before asserting. Round-trip cost: one CI run, no guessing.

Note the integration lane passed on the previous push even with the wrong
generated file — the SQL text was valid and the signature was unchanged, so
executing it against real Postgres proved nothing about whether the committed
Go matched its source. That gap is exactly what #2380 closes.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-01 22:23:35 -04:00
co-authored by Claude Opus 5
parent 94e2cac03b
commit e006de5d4b
+17 -23
View File
@@ -1022,22 +1022,6 @@ func (q *Queries) LoadRadioCandidatesV2(ctx context.Context, arg LoadRadioCandid
}
const suggestArtistsForUser = `-- name: SuggestArtistsForUser :many
-- Per-user artist suggestions ranked by taste signal x similarity, projected
-- through artist_similarity_unmatched (out-of-library candidates only).
--
-- Seeds are TIERED (rule #131) so the surface never empties:
-- tier 1 - taste_profile_artists.weight: engagement-graded, time-decayed and
-- SIGNED by internal/taste, so an artist the user has drifted away
-- from stops contributing instead of accumulating forever.
-- tier 2 - likes + completed plays, used ONLY when the profile has no rows
-- (new account, or before the first daily recompute).
--
-- The signal is log-damped: contribution is signal x similarity, and the old
-- undamped sum let one heavily-played artist's neighbours take every slot --
-- entrenching harder the MORE the user listened (issue #2367 mechanism 2).
--
-- Candidates already in the library, or already requested and not terminal,
-- are excluded. $1=user_id, $2=half_life_days (tier 2 decay), $3=limit.
WITH artist_plays AS (
-- Completed plays only. The previous seed query counted every play_event,
-- so skipping an artist repeatedly INCREASED its signal and pushed more of
@@ -1128,13 +1112,23 @@ type SuggestArtistsForUserRow struct {
TopPlayCounts []int64
}
// M5c: per-user artist suggestions ranked by signal x similarity. The
// seeds CTE collects the user's likes (x5) plus recency-decayed plays
// (exp(-age_days / $2)). The contributions CTE joins those seeds against
// artist_similarity_unmatched and filters out candidates already in
// library or already in a non-terminal lidarr_request. The outer SELECT
// aggregates per candidate, returning the top-3 contributing seeds for
// attribution. $1=user_id, $2=half_life_days, $3=limit.
// Per-user artist suggestions ranked by taste signal x similarity, projected
// through artist_similarity_unmatched (out-of-library candidates only).
//
// Seeds are TIERED (rule #131) so the surface never empties:
//
// tier 1 - taste_profile_artists.weight: engagement-graded, time-decayed and
// SIGNED by internal/taste, so an artist the user has drifted away
// from stops contributing instead of accumulating forever.
// tier 2 - likes + completed plays, used ONLY when the profile has no rows
// (new account, or before the first daily recompute).
//
// The signal is log-damped: contribution is signal x similarity, and the old
// undamped sum let one heavily-played artist's neighbours take every slot --
// entrenching harder the MORE the user listened (issue #2367 mechanism 2).
//
// Candidates already in the library, or already requested and not terminal,
// are excluded. $1=user_id, $2=half_life_days (tier 2 decay), $3=limit.
func (q *Queries) SuggestArtistsForUser(ctx context.Context, arg SuggestArtistsForUserParams) ([]SuggestArtistsForUserRow, error) {
rows, err := q.db.Query(ctx, suggestArtistsForUser, arg.UserID, arg.Column2, arg.Limit)
if err != nil {