-- Recommendation tuning lab (milestone #127, Scribe #1250).
--
-- The scoring weights move out of YAML (radio profile) and out of the
-- systemMixWeights hard-code (daily_mix profile) into DB-backed
-- settings with live effect — the defaults-discovery lab (decision
-- #1247): the operator turns knobs here to FIND good values, which
-- then get baked into shipped defaults; end users and other operators
-- should never need this card.
--
-- Rows are seeded by the recsettings service's boot reconcile (the
-- coverart SettingsService pattern), not by this migration, so shipped
-- defaults live in exactly one place (Go).

CREATE TABLE recommendation_weight_profiles (
    profile           text PRIMARY KEY
        CONSTRAINT recommendation_weight_profiles_profile_check
        CHECK (profile IN ('radio', 'daily_mix')),
    base_weight       double precision NOT NULL,
    like_boost        double precision NOT NULL,
    recency_weight    double precision NOT NULL,
    skip_penalty      double precision NOT NULL,
    jitter_magnitude  double precision NOT NULL,
    context_weight    double precision NOT NULL,
    similarity_weight double precision NOT NULL,
    taste_weight      double precision NOT NULL,
    updated_at        timestamptz NOT NULL DEFAULT now()
);

-- Taste-profile build knobs: engagement half-life + the completion→
-- engagement curve points (taste.Config's tunable subset).
CREATE TABLE taste_tuning (
    singleton            boolean PRIMARY KEY DEFAULT true
        CONSTRAINT taste_tuning_singleton_check CHECK (singleton),
    half_life_days       double precision NOT NULL,
    engagement_hard_skip double precision NOT NULL,
    engagement_neutral   double precision NOT NULL,
    engagement_full      double precision NOT NULL,
    updated_at           timestamptz NOT NULL DEFAULT now()
);

-- Every knob turn writes one audit row; the metrics trend view
-- (#1251) annotates these on its timeline so cause→effect is visible
-- after a change. changes is a jsonb array of {field, old, new}.
CREATE TABLE recommendation_tuning_audit (
    id         bigserial PRIMARY KEY,
    changed_at timestamptz NOT NULL DEFAULT now(),
    scope      text NOT NULL
        CONSTRAINT recommendation_tuning_audit_scope_check
        CHECK (scope IN ('radio', 'daily_mix', 'taste')),
    action     text NOT NULL
        CONSTRAINT recommendation_tuning_audit_action_check
        CHECK (action IN ('update', 'reset')),
    changes    jsonb NOT NULL
);

CREATE INDEX recommendation_tuning_audit_changed_at_idx
    ON recommendation_tuning_audit (changed_at DESC);
