feat(tuning): expose EnrichedTagScale in the tuning lab (#1520)
Promote the enriched-tag weight (#1490) from a taste.Config default into the DB-backed tuning lab so operators can dial how much folksonomy tags count vs raw ID3 genre (rule #25). - Migration 0044: taste_tuning.enriched_tag_scale (DEFAULT 0.5, backfills the existing row). - recsettings: TasteTuning gains the field; seeded/read/updated through reconcile + persistTaste; applyTastePatch validates it to [0,1] (generic non-half-life clamp) and diffTaste audits it; TasteConfig maps it into the profile build. - API: tasteTuningResp exposes enriched_tag_scale. - Web tuning card: a data-driven "Enriched tag weight" knob (0 = genre only). Tests: recsettings persist+range, web fixture field. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -38,12 +38,14 @@ const (
|
||||
)
|
||||
|
||||
// TasteTuning is the tunable subset of taste.Config: the engagement
|
||||
// half-life and the completion→engagement curve points.
|
||||
// half-life, the completion→engagement curve points, and the enriched-tag
|
||||
// weight (how much folksonomy tags count vs raw ID3 genre, #1520).
|
||||
type TasteTuning struct {
|
||||
HalfLifeDays float64
|
||||
EngagementHardSkip float64
|
||||
EngagementNeutral float64
|
||||
EngagementFull float64
|
||||
EnrichedTagScale float64
|
||||
}
|
||||
|
||||
// ShippedRadioWeights are the shipped radio-profile defaults (moved
|
||||
@@ -86,6 +88,7 @@ func ShippedTasteTuning() TasteTuning {
|
||||
EngagementHardSkip: d.Engagement.HardSkip,
|
||||
EngagementNeutral: d.Engagement.NeutralCompletion,
|
||||
EngagementFull: d.Engagement.FullCompletion,
|
||||
EnrichedTagScale: d.EnrichedTagScale,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -133,6 +136,7 @@ func (s *Service) reconcile(ctx context.Context) error {
|
||||
EngagementHardSkip: st.EngagementHardSkip,
|
||||
EngagementNeutral: st.EngagementNeutral,
|
||||
EngagementFull: st.EngagementFull,
|
||||
EnrichedTagScale: st.EnrichedTagScale,
|
||||
}); err != nil {
|
||||
return fmt.Errorf("seed taste tuning: %w", err)
|
||||
}
|
||||
@@ -156,6 +160,7 @@ func (s *Service) reconcile(ctx context.Context) error {
|
||||
EngagementHardSkip: tt.EngagementHardSkip,
|
||||
EngagementNeutral: tt.EngagementNeutral,
|
||||
EngagementFull: tt.EngagementFull,
|
||||
EnrichedTagScale: tt.EnrichedTagScale,
|
||||
}
|
||||
s.mu.Unlock()
|
||||
|
||||
@@ -205,6 +210,7 @@ func (s *Service) TasteConfig() taste.Config {
|
||||
NeutralCompletion: t.EngagementNeutral,
|
||||
FullCompletion: t.EngagementFull,
|
||||
}
|
||||
cfg.EnrichedTagScale = t.EnrichedTagScale
|
||||
return cfg
|
||||
}
|
||||
|
||||
@@ -301,6 +307,7 @@ func (s *Service) persistTaste(
|
||||
EngagementHardSkip: t.EngagementHardSkip,
|
||||
EngagementNeutral: t.EngagementNeutral,
|
||||
EngagementFull: t.EngagementFull,
|
||||
EnrichedTagScale: t.EnrichedTagScale,
|
||||
}); err != nil {
|
||||
return fmt.Errorf("update taste tuning: %w", err)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user