fix: resolve governance gaps, patch credential exposure, and connect multi-platform dashboard
This commit is contained in:
1 parent
6f2e8e0c9d
commit
7fb7d775d8
5 files changed
+324
-387
No files matched your search
+39
-22
@@ -12,8 +12,8 @@ Ranks artists according to HIFFI formula stages:
|
||||
and effective weight serialization.
|
||||
- Publication Eligibility Gates: Decoupled public chart assigning consecutive ranks
|
||||
while enforcing multi-platform evidence tiers (Top 10 = Tier 3, Top 50 = Tier >= 2)
|
||||
conditioned on strict identity verification and UTC data freshness thresholds.
|
||||
Fail-closed on missing timestamp columns or unverified statuses.
|
||||
conditioned on strict identity verification, status_flag validation, and UTC data freshness thresholds.
|
||||
Fail-closed on missing timestamp columns, failed lookups, or unverified statuses.
|
||||
"""
|
||||
|
||||
from typing import Optional, Tuple, Union
|
||||
@@ -26,7 +26,7 @@ class HIFFIRankingEngine:
|
||||
@staticmethod
|
||||
def _log_scale(series: pd.Series) -> pd.Series:
|
||||
valid = series.dropna()
|
||||
log_vals = np.log10(1.0 + np.maximum(valid, 0.0))
|
||||
log_vals = np.log1p(np.maximum(valid.astype(float), 0.0))
|
||||
s_min, s_max = log_vals.min(), log_vals.max()
|
||||
if np.isclose(s_max, s_min) or pd.isna(s_min):
|
||||
return pd.Series(0.0, index=series.index)
|
||||
@@ -70,13 +70,15 @@ class HIFFIRankingEngine:
|
||||
"""
|
||||
out_bvi = pd.Series(np.nan, index=df.index, dtype=float)
|
||||
|
||||
status_col = df["status_flag"] if "status_flag" in df.columns else pd.Series("COMPLETE", index=df.index)
|
||||
|
||||
valid_mask = (
|
||||
df["subscriber_count"].notna()
|
||||
& (df["subscriber_count"] >= 10000)
|
||||
& df["daily_view_velocity"].notna()
|
||||
& (df["daily_view_velocity"] > 0.0)
|
||||
& (df["status_flag"] != "INACTIVE_OR_DORMANT")
|
||||
& (df["status_flag"] != "FAILED_LOOKUP")
|
||||
& (status_col != "INACTIVE_OR_DORMANT")
|
||||
& (status_col != "FAILED_LOOKUP")
|
||||
)
|
||||
|
||||
if not valid_mask.any():
|
||||
@@ -123,29 +125,31 @@ class HIFFIRankingEngine:
|
||||
|
||||
out["breakout_velocity_index"] = self.calculate_breakout_velocity(out)
|
||||
|
||||
status_col = out["status_flag"] if "status_flag" in out.columns else pd.Series("COMPLETE", index=out.index)
|
||||
|
||||
has_baseline = (
|
||||
out["subscriber_count"].notna()
|
||||
& out["lifetime_views"].notna()
|
||||
& (out["status_flag"] != "FAILED_LOOKUP")
|
||||
& (status_col != "FAILED_LOOKUP")
|
||||
)
|
||||
|
||||
out["is_rank_eligible"] = (
|
||||
has_baseline
|
||||
& (out["confidence_score"] >= min_confidence)
|
||||
& (out["status_flag"].isin(["COMPLETE", "CATALOG_ACTIVE_NO_RECENT_UPLOAD"]))
|
||||
& (out.get("confidence_score", pd.Series(1.0, index=out.index)) >= min_confidence)
|
||||
& (status_col.isin(["COMPLETE", "CATALOG_ACTIVE_NO_RECENT_UPLOAD"]))
|
||||
)
|
||||
|
||||
filled_momentum = out["momentum_30d"].fillna(0.0).clip(lower=-100.0, upper=300.0)
|
||||
filled_momentum = out["momentum_30d"].fillna(0.0).clip(lower=-100.0, upper=300.0) if "momentum_30d" in out.columns else pd.Series(0.0, index=out.index)
|
||||
score_momentum = self._min_max_scale(filled_momentum)
|
||||
|
||||
filled_velocity = out["daily_view_velocity"].fillna(0.0)
|
||||
filled_velocity = out["daily_view_velocity"].fillna(0.0) if "daily_view_velocity" in out.columns else pd.Series(0.0, index=out.index)
|
||||
score_velocity = self._log_scale(filled_velocity)
|
||||
|
||||
log_subs = self._log_scale(out["subscriber_count"].fillna(0.0))
|
||||
log_lifetime = self._log_scale(out["lifetime_views"].fillna(0.0))
|
||||
log_subs = self._log_scale(out["subscriber_count"].fillna(0.0)) if "subscriber_count" in out.columns else pd.Series(0.0, index=out.index)
|
||||
log_lifetime = self._log_scale(out["lifetime_views"].fillna(0.0)) if "lifetime_views" in out.columns else pd.Series(0.0, index=out.index)
|
||||
score_reach = 0.60 * log_subs + 0.40 * log_lifetime
|
||||
|
||||
score_consistency = self._log_scale(out["video_count"].fillna(0.0))
|
||||
score_consistency = self._log_scale(out["video_count"].fillna(0.0)) if "video_count" in out.columns else pd.Series(0.0, index=out.index)
|
||||
|
||||
hiffi_raw = (
|
||||
0.35 * score_momentum
|
||||
@@ -154,7 +158,7 @@ class HIFFIRankingEngine:
|
||||
+ 0.15 * score_consistency
|
||||
) * 100.0
|
||||
|
||||
conf_multiplier = 0.8 + 0.2 * out["confidence_score"].clip(0.0, 1.0)
|
||||
conf_multiplier = 0.8 + 0.2 * out.get("confidence_score", pd.Series(1.0, index=out.index)).clip(0.0, 1.0)
|
||||
out["production_hiffi_score"] = (hiffi_raw * conf_multiplier).round(2)
|
||||
|
||||
eligible_mask = out["is_rank_eligible"]
|
||||
@@ -183,6 +187,12 @@ class HIFFIRankingEngine:
|
||||
"""
|
||||
out = df.copy()
|
||||
|
||||
# Schema aliasing for raw input fallbacks
|
||||
if "production_hiffi_score" not in out.columns and "hiffi_score" in out.columns:
|
||||
out["production_hiffi_score"] = out["hiffi_score"]
|
||||
if "production_hiffi_rank" not in out.columns and "hiffi_rank" in out.columns:
|
||||
out["production_hiffi_rank"] = out["hiffi_rank"]
|
||||
|
||||
base_weights = {
|
||||
"yt": 0.50,
|
||||
"sp_monthly": 0.25,
|
||||
@@ -311,7 +321,8 @@ class HIFFIRankingEngine:
|
||||
- Top 10 requires all 3 platforms (Tier 3), strictly verified and fresh.
|
||||
- Top 50 requires at least 2 platforms (Tier >= 2), strictly verified and fresh.
|
||||
- Freshness Thresholds: YouTube <= 7d, Spotify <= 7d, Instagram <= 14d.
|
||||
- Fail-closed: missing timestamp columns or unverified statuses evaluate
|
||||
- Integrity Gate: Artists with status_flag == 'FAILED_LOOKUP' are disqualified from YouTube credit.
|
||||
- Fail-closed: missing timestamp columns, stale records, or unverified statuses evaluate
|
||||
strictly to False and are logged to evidence_exclusions.
|
||||
- Preserves raw hiffi_xp_score and raw hiffi_xp_rank completely unchanged.
|
||||
- Produces consecutive, unique ranks in 'hiffi_xp_published_rank' (1 to N).
|
||||
@@ -321,8 +332,11 @@ class HIFFIRankingEngine:
|
||||
|
||||
exclusions = [[] for _ in range(len(out))]
|
||||
|
||||
# 1. YouTube Validation (Score present + Freshness <= 7 days)
|
||||
has_yt_val = out["production_hiffi_score"].notna()
|
||||
# 1. YouTube Validation (Score present + status not FAILED_LOOKUP + Freshness <= 7 days)
|
||||
status_col = out["status_flag"] if "status_flag" in out.columns else pd.Series("COMPLETE", index=out.index)
|
||||
has_yt_val = out["production_hiffi_score"].notna() if "production_hiffi_score" in out.columns else pd.Series(False, index=out.index)
|
||||
is_lookup_failed = status_col == "FAILED_LOOKUP"
|
||||
|
||||
if "youtube_updated_at" in out.columns:
|
||||
yt_fresh = out["youtube_updated_at"].apply(
|
||||
lambda x: self._is_signal_fresh(x, max_days=7.0, reference_time=ref_time)
|
||||
@@ -330,13 +344,16 @@ class HIFFIRankingEngine:
|
||||
else:
|
||||
yt_fresh = pd.Series(False, index=out.index)
|
||||
|
||||
for idx, (val, fresh) in enumerate(zip(has_yt_val, yt_fresh)):
|
||||
if val and not fresh:
|
||||
for idx, (val, failed, fresh) in enumerate(zip(has_yt_val, is_lookup_failed, yt_fresh)):
|
||||
if failed:
|
||||
exclusions[idx].append("FAILED_YOUTUBE_LOOKUP")
|
||||
elif val and not fresh:
|
||||
exclusions[idx].append("STALE_OR_MISSING_YOUTUBE_TIMESTAMP")
|
||||
valid_yt = has_yt_val & yt_fresh
|
||||
|
||||
valid_yt = has_yt_val & (~is_lookup_failed) & yt_fresh
|
||||
|
||||
# 2. Spotify Validation (Telemetry present + Freshness <= 7 days)
|
||||
has_sp_val = out["spotify_monthly_listeners"].notna()
|
||||
has_sp_val = out["spotify_monthly_listeners"].notna() if "spotify_monthly_listeners" in out.columns else pd.Series(False, index=out.index)
|
||||
if "spotify_updated_at" in out.columns:
|
||||
sp_fresh = out["spotify_updated_at"].apply(
|
||||
lambda x: self._is_signal_fresh(x, max_days=7.0, reference_time=ref_time)
|
||||
@@ -350,7 +367,7 @@ class HIFFIRankingEngine:
|
||||
valid_sp = has_sp_val & sp_fresh
|
||||
|
||||
# 3. Instagram Validation (Followers present + Approved Status + Freshness <= 14 days)
|
||||
has_ig_val = out["instagram_followers"].notna()
|
||||
has_ig_val = out["instagram_followers"].notna() if "instagram_followers" in out.columns else pd.Series(False, index=out.index)
|
||||
verified_statuses = {"AUTOMATED_VERIFIED", "MANUAL_VERIFIED"}
|
||||
|
||||
if "instagram_verification_status" in out.columns:
|
||||
|
||||
Reference in new issue
Block a user