Skip to content

Add author reputation signal to trending algorithm #581

@realproject7

Description

@realproject7

Problem

The trending algorithm currently uses 5 signals (rating, price change, TVL, continuation rate, recency) but none account for the author's reputation. A story by a well-established author with thousands of followers should rank higher than an identical story by an anonymous wallet, all else being equal.

Requirements

1. Build a composite author reputation score

Using data already in the users table, compute a normalized reputation score (0–1) from these inputs:

Signal Source column Notes
Farcaster followers follower_count Log-scaled, larger following = more credible
X/Twitter followers x_followers_count Log-scaled, same logic
X verified x_verified Boolean bonus — verified accounts are more trustworthy
Neynar Score neynar_score Already 0–1 range from Neynar API
Quotient Score quotient_score Decimal score from Quotient Protocol

Suggested formula (T3 can refine):

function computeAuthorReputation(user: UserRow | null): number {
  if (!user) return 0; // anonymous wallet, no reputation data

  // Farcaster followers (log-scaled, 0-1)
  const fcFollowers = user.follower_count ?? 0;
  const fcSignal = Math.min(1, Math.log10(1 + fcFollowers) / 5); // 100k followers → 1.0

  // X followers (log-scaled, 0-1)
  const xFollowers = Number(user.x_followers_count ?? 0);
  const xSignal = Math.min(1, Math.log10(1 + xFollowers) / 5);

  // X verified bonus
  const xVerifiedBonus = user.x_verified ? 0.15 : 0;

  // Neynar score (already ~0-1)
  const neynarSignal = Number(user.neynar_score ?? 0);

  // Quotient score (normalize — typical range ~0-100?)
  const qScore = Number(user.quotient_score ?? 0);
  const quotientSignal = Math.min(1, qScore / 100);

  // Weighted composite
  return Math.min(1,
    fcSignal * 0.30 +
    xSignal * 0.25 +
    xVerifiedBonus +
    neynarSignal * 0.15 +
    quotientSignal * 0.15
  );
}

2. Integrate into trending algorithm

Add as the 6th signal in computeTrendScore(). Rebalance weights:

Signal Current Weight New Weight
Bayesian rating 0.25 0.20
24h price change 0.20 0.15
TVL 0.20 0.15
Continuation rate 0.15 0.15
Recency 0.20 0.15
Author reputation 0.20

3. Data fetching

  • In fetchCandidatesAndRatings() or getTrendingStorylines(), batch-fetch user data for all candidate storyline writers
  • Use writer_address → look up in users table by primary_address or verified_addresses
  • Single query for all candidates, not N+1

4. Graceful degradation

  • If author has no user record → reputation = 0 (not penalized beyond that)
  • If some fields are null (e.g., no X account) → those sub-signals contribute 0
  • Stories should still be rankable purely on content/market signals even with zero reputation

Files to modify

  • lib/ranking.ts — add computeAuthorReputation(), update computeTrendScore() weights, batch-fetch users
  • Possibly lib/supabase.ts if new type helpers needed

Branch

task/579-author-reputation-trending

Acceptance criteria

  • Author reputation score computed from FC followers, X followers, X verified, Neynar score, Quotient score
  • Integrated as 6th signal in trending algorithm with ~20% weight
  • Batch user lookup (not N+1 queries)
  • Stories by authors with no user record still rank correctly
  • Build passes

Metadata

Metadata

Assignees

No one assigned

    Labels

    agent/T3Assigned to T3 builder agent

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions