Skip to content

Add X like velocity to the paper trending score - #867

Merged
NielsRogge merged 2 commits into
mainfrom
claude/x-like-velocity
Nov 3, 2026
Merged

NielsRogge merged 2 commits into
mainfrom
claude/x-like-velocity

Conversation

@NielsRogge

@NielsRogge NielsRogge commented Nov 3, 2026 •

Copy link
Copy Markdown
Collaborator

First step toward merging / and /x-trending. This adds X like velocity as a third part of the paper trending score. Its weight defaults to 0, so deploying this changes no rankings.

What it does

  • New hourly CRON refresh_x_post_likes (:35). Each run adds an x_post_metrics row for every paper_x_threads post from the last 7 days. It then reads each post about 1, 2, 4, 8, 12, 24, 48, 72, 120 and 144 h after posting and keeps an EMA of likes per hour (α = 0.75, as for GitHub). The first reading uses the lifetime average.
  • Sources:
    • The free embed syndication endpoint is tried first.
    • Posts it cannot serve, or every remaining post once it returns 429, fall back to paid GET /2/tweets?ids= lookups in batches of 100.
    • Paid reads are capped at PWC_X_LIKES_API_DAILY_CAP (default 300) posts per UTC day.
    • Posts the API reports unavailable are marked gone_at.
    • A paid-API failure (for example HTTP 402) exits 1, so it shows on the dashboard.
  • Report mode: the job only reports, reading through syndication and rolling back, unless PWC_X_LIKES_APPLY=true.
  • Score: calculate_paper_trending_scores takes each paper's fastest live post and ranks it against the other papers' fastest posts. Posts under PWC_TRENDING_X_MIN_LIKES_PER_HOUR (default 1) count for nothing and are left out of that ranking. The result is weighted by PWC_TRENDING_X_WEIGHT; GitHub and HF share the rest equally (w_g = w_h = (1 − w_x)/2), so the score stays within 0–100 and pins keep working. The X part is stored in papers.x_trending_component.
  • Restricted scoring role: pwc_cron_trending gets SELECT on paper_x_threads and x_post_metrics, and UPDATE on papers.x_trending_component. This is done in both configure_db_roles.py and the migration. The launcher passes the two PWC_TRENDING_X_* settings through, and configure_host_env.py keeps them when it rewrites trending-cron.env.

Migration

backend/database/migrations/add_x_post_metrics.sql was already applied to public (2026-11-03 09:35 UTC) before merge. It uses lock_timeout = 10s for the papers column.

Verification

  • Tests: pytest backend/tests/test_x_post_likes_service.py backend/tests/test_trending_formula.py backend/tests/paper/test_trending_scores.py backend/tests/cron backend/tests/deployment/test_cron_environment.py gives 270 passed and 1 failure. That failure, test_cron_jobs_declare_bounded_execution_contracts, is not from this PR: it fails because of link_google_scholar_profiles' existing 3h timeout.
  • Lint: ruff check and ruff format are clean.
  • Report-only run on production data: 76 posts from the last week, all read through syndication with 0 paid reads, then rolled back (x_post_metrics still empty). Median 0.82 likes/h, 90th percentile 14, 33 posts ≥ 1/h, max 3,040/h.

Rollout (after deploy)

  1. Set PWC_X_LIKES_APPLY=true in production-cron.env and enable the timer.
  2. After 2–3 days, compare the would-be ranking at weight ⅓ with the current / and /x-trending.
  3. Once that comparison is approved, set PWC_TRENDING_X_WEIGHT=0.3333 in trending-cron.env.
  4. Open a separate frontend PR that removes the "trending (X)" tab, redirects /x-trending to /, and drops GET /papers/x-trending.

🤖 Generated with Claude Code


Note

Medium Risk
Changes paper trending formula and DB writes when X weight or apply flags are enabled; external X API usage and capped paid fallback add operational and cost failure modes, though default weight 0 limits ranking impact on deploy.

Overview
Adds an optional third signal for composite paper trending: smoothed likes-per-hour on linked paper_x_threads posts, wired end-to-end from collection through scoring and ops.

New pipeline: Hourly refresh_x_post_likes (:35) enrolls posts from the last 7 days into x_post_metrics, reads them on a decaying schedule (1–144h), prefers embed syndication, falls back to paid X API with a daily cap, and supports report-only mode (PWC_X_LIKES_APPLY) that rolls back DB writes. calculate_paper_trending_scores loads each paper’s fastest live post, quantile-ranks it (posts below PWC_TRENDING_X_MIN_LIKES_PER_HOUR excluded), blends via PWC_TRENDING_X_WEIGHT while GitHub/HF share (1 − w_x)/2, and persists papers.x_trending_component. DEFAULT_X_WEIGHT is 0, so production rankings stay unchanged until operators raise the weight.

Schema & access: Migration adds x_post_metrics and papers.x_trending_component; pwc_cron_trending and env tooling gain SELECT/UPDATE grants and passthrough for PWC_TRENDING_X_* / PWC_X_LIKES_*. Cron registry, systemd units, launcher, health docs, and tests are updated accordingly.

Reviewed by Cursor Bugbot for commit 2c917a8. Bugbot is set up for automated code reviews on this repo. Configure here.

New hourly CRON `refresh_x_post_likes` tracks linked X posts during their
first week in `x_post_metrics`: syndication first, paid X API fallback capped
at 300 posts/day, likes-per-hour EMA on a decaying schedule. The paper score
job adds the quantile rank of each paper's fastest post as a third component,
weighted by PWC_TRENDING_X_WEIGHT (default 0, so rankings are unchanged).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit f80c0b1. Configure here.

Comment thread deploy/configure_host_env.py Resolved
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@NielsRogge
NielsRogge merged commit 97c77f3 into main Nov 3, 2026
5 checks passed
@NielsRogge
NielsRogge deleted the claude/x-like-velocity branch November 3, 2026 09:46
@NielsRogge

Copy link
Copy Markdown
Collaborator Author

Status (2026-11-03 09:55 UTC): live in production as 97c77f3708de (smoke: /health, /, /x-trending, /tasks, trending + x-trending APIs all 200).

  • Done: install_deploy_tools from 97c77f3, so the pwc-cron-refresh-x-post-likes.timer unit is installed and enabled. PWC_X_LIKES_APPLY=true added to production-cron.env (backup production-cron.env.bak-*-x-likes). The first apply run stored 76 posts, all through syndication, with 0 paid reads.
  • Still open:
    1. Confirm that the 10:45 calculate_paper_trending_scores run (restricted role) writes x_trending_component.
    2. After 2–3 days, send the before/after top-30 comparison at X weight ⅓.
    3. On approval, set PWC_TRENDING_X_WEIGHT=0.3333 in /etc/paperswithcode/trending-cron.env.
    4. Open a frontend PR: remove the "trending (X)" tab, redirect /x-trending to /, and drop GET /papers/x-trending plus XTrendingService.feed().

NielsRogge added a commit that referenced this pull request Nov 5, 2026
X like velocity now lifts papers in the main trending score (#867, #871,
PWC_TRENDING_X_WEIGHT=1 since 2026-11-05), so the separate tab is gone:
/x-trending redirects to /, and GET /papers/x-trending,
XTrendingService.feed() and papersApi.xTrending are removed. The admin
PUT /papers/x-trending/{day} and the paper_x_trending table stay for the
sheet routine and curation priority.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant