Social Media20 min read

What the X Algorithm Actually Does: A Code-Level Breakdown of Reach on the For You Feed

X published code shaped like the system behind the For You feed. This is a file-by-file, formula-by-formula reading of what it rewards, what it removes, and what it almost certainly still does in production but does not reveal.

Looking for the plain-English version? Read Why Your X Reach Changes: A Plain-English Guide To The For You Feed instead. This piece assumes you can read code.

X (formerly Twitter) published code for a recommendation system shaped like the one that powers the "For You" feed. I read it. Not the marketing posts about it, but the Rust and Python files that retrieve posts, filter them, score them, blend them with other feed units, and ship a ranked response.

Below is what the code actually shows, what it rewards, what it removes, and what it probably still does in production but does not reveal in this release.

No speculation labeled as fact. No fact labeled as speculation. Just what is in the repo, with file paths so you can check.


How the System Is Wired

The easiest way to misunderstand this repo is to think there is one clean "algorithm" file. There isn't. The feed is a pipeline of sources, hydrators, filters, scorers, selectors, post-selection filters, and side effects.

There are two important layers:

  1. Organic scored-post ranking (home-mixer/candidate_pipeline/phoenix_candidate_pipeline.rs)

    • Sources collect post candidates from Thunder, Tweet Mixer, Phoenix Retrieval, Phoenix Topics, Phoenix MoE, and cached posts.
    • Hydrators attach metadata: author info, media, video duration, quote data, language, subscription status, topic ids, block state, and more.
    • Filters remove ineligible posts before scoring.
    • Phoenix predicts engagement probabilities.
    • RankingScorer combines Phoenix predictions with feature-switch weights, applies author diversity, and applies out-of-network weighting.
    • VMRanker, when enabled, can replace the score from RankingScorer with a value-model score from an external service.
    • TopKScoreSelector selects the top organic post candidates.
    • Post-selection hydrators and filters then run visibility, brand-safety, mutual-follow, tweet-type, and conversation-dedup logic.
  2. Final For You response blending (home-mixer/candidate_pipeline/for_you_candidate_pipeline.rs)

    • The final feed is not just ranked posts.
    • ForYouCandidatePipeline combines scored posts with ads, Who To Follow modules, prompts, and push-to-home posts.
    • BlenderSelector inserts or pins those non-post units into the feed.

That distinction matters. A post can win the organic ranking stage and still be removed by a post-selection filter. It can also be displaced by ads or other feed modules in the final response.

The architectural punchline from X's own README:

We have eliminated every single hand-engineered feature and most heuristics from the system. The Grok-based transformer does all the heavy lifting by understanding your engagement history.

That matters, but it needs a caveat. The code does show a transformer-heavy system, but it also shows feature-switched weights, explicit filters, source routing, author diversity, out-of-network multipliers, ad blending, and optional value-model reranking. The transformer is central. It is not the only thing that matters.


Part 1: What Helps Your Reach

The Engagement Signals the Ranker Scores

The active organic scorer is home-mixer/scorers/ranking_scorer.rs. Phoenix first predicts per-candidate engagement probabilities, then RankingScorer combines those predictions:

let combined_score = Self::apply(scores.favorite_score, weights.favorite)
    + Self::apply(scores.reply_score, weights.reply)
    + Self::apply(scores.retweet_score, weights.retweet)
    + Self::apply(scores.photo_expand_score, weights.photo_expand)
    + Self::apply(scores.click_score, weights.click)
    + Self::apply(scores.profile_click_score, weights.profile_click)
    + Self::apply(scores.vqv_score, vqv_weight)
    + Self::apply(scores.share_score, weights.share)
    + Self::apply(scores.share_via_dm_score, weights.share_via_dm)
    + Self::apply(scores.share_via_copy_link_score, weights.share_via_copy_link)
    + Self::apply(scores.dwell_score, weights.dwell)
    + Self::apply(scores.quote_score, weights.quote)
    + Self::apply(scores.quoted_click_score, weights.quoted_click)
    + Self::apply(scores.quoted_vqv_score, quoted_vqv_weight)
    + Self::apply(scores.dwell_time, weights.cont_dwell_time)
    + Self::apply(scores.click_dwell_time, weights.cont_click_dwell_time)
    + Self::apply(scores.follow_author_score, weights.follow_author)
    + Self::apply(scores.not_interested_score, weights.not_interested)
    + Self::apply(scores.block_author_score, weights.block_author)
    + Self::apply(scores.mute_author_score, weights.mute_author)
    + Self::apply(scores.report_score, weights.report)
    + Self::apply(scores.not_dwelled_score, weights.not_dwelled);

The simple formula is:

Ranking score = weighted sum of predicted actions

Where P(action) is Phoenix's predicted probability or predicted value for that action.

Positive signals:

  • P(favorite) - like
  • P(reply) - reply
  • P(retweet) - repost
  • P(quote) - quote post
  • P(click) - click
  • P(quoted_click) - click within a quote
  • P(profile_click) - tap to your profile
  • P(photo_expand) - tap to expand an image
  • P(video_quality_view) - meaningful video view, gated by video duration
  • P(quoted_video_quality_view) - meaningful video view inside a quote, also gated by video duration when enabled
  • P(share) - share action
  • P(share_via_dm) - DM share
  • P(share_via_copy_link) - copy-link share
  • P(dwell) - binary dwell signal
  • dwell_time - continuous dwell time
  • click_dwell_time - dwell following a click
  • P(follow_author) - did this post make the viewer follow the author?

Negative signals:

  • P(not_interested) - taps "Not Interested"
  • P(block_author) - blocks the author
  • P(mute_author) - mutes the author
  • P(report) - reports the post
  • P(not_dwelled) - scrolls past without dwelling

Every one of these is a prediction. The model does not need to wait for a report, a block, or a mute. If the post looks like something this viewer is likely to reject, the predicted rejection hurts it before the viewer ever sees it.

Practical Takeaways

1. Dwell-worthy content is heavily rewarded. The scorer includes both binary dwell and continuous dwell time, plus click-dwell time. Hooks that make people stop, visuals that reward inspection, and posts that earn actual reading time have multiple ways to score.

2. Replies are valuable and explicit. Reply probability has its own weight. Posts that invite a real response can score better than posts that generate only passive impressions.

3. Private sharing matters. The scorer splits sharing into public and private-ish rails: reposts, shares, DM shares, and copy-link shares. Content people send to one person can matter even if it does not look publicly viral.

4. Profile clicks and follow predictions count. Posts that make people curious about the author feed profile_click_score and follow_author_score.

5. Video helps only if it qualifies. Video-quality-view weight is gated by duration:

let vqv_weight = crate::util::candidates_util::vqv_weight(
    query,
    candidate,
    weights.min_video_duration_ms,
    weights.vqv,
);

The exact threshold comes from feature-switch config (MinVideoDurationMs). The visible rule is clear: videos below the configured minimum do not get the VQV weight.

In-Network Reach Is Structurally Easier

RankingScorer applies an out-of-network multiplier after weighted scoring and author diversity:

let final_score = match c.in_network {
    Some(false) => after_diversity * effective_oon,
    _ => after_diversity,
};

Out-of-network posts are on a harder track unless the effective OON factor is configured otherwise. Translation: building real followers still matters. Followers put your posts into the in-network lane, where this specific multiplier does not apply.

Topic Context Changes the OON Multiplier

home-mixer/scorers/ranking_scorer.rs:

if !query.topic_ids.is_empty() {
    return query.params.get(TopicOonWeightFactor);
}

If the request is in a topic context, the system uses TopicOonWeightFactor instead of the default OON factor. The repo does not reveal whether that factor is larger or smaller in production, but it does show that topic context changes the math.

There are also explicit topic filters:

  • TopicIdsFilter keeps or removes candidates based on requested topics and excluded topics.
  • NewUserTopicIdsFilter can restrict out-of-network posts for new-user topic onboarding while allowing in-network posts through.

So topic alignment is not just a vague semantic idea. Topic ids are hydrated and filtered explicitly.

New Viewers Get a Bootstrap Path

let is_eligible_new_user = duration_since_creation_opt(query.user_id)
    .map(|age| age < new_user_age_threshold)
    .unwrap_or(false)
    && query.user_features.followed_user_ids.len() >= NEW_USER_MIN_FOLLOWING;

if is_eligible_new_user {
    NEW_USER_OON_WEIGHT_FACTOR
} else {
    oon_weight_factor
}

This is viewer-side, not author-side. New accounts can receive a different OON weight if they are young enough and follow at least NEW_USER_MIN_FOLLOWING accounts. If a new viewer follows nobody, the system has less to work with.

Mutual Follow Overlap Is Computed, But Not Where You Might Think

home-mixer/candidate_hydrators/mutual_follow_jaccard_hydrator.rs computes Jaccard similarity between the viewer's follow graph and the author's follow graph using 256-element MinHash sketches:

fn jaccard_from_minhash(a: &[i64], b: &[i64]) -> f64 {
    let len = a.len().min(b.len());
    if len == 0 { return 0.0; }
    let matching = a.iter().zip(b.iter()).filter(|(x, y)| x == y).count();
    matching as f64 / len as f64
}

But in the visible pipeline, this hydrator runs after selection, in the post-selection hydrator list. That means this repo does not show mutual-follow Jaccard feeding the main RankingScorer score. It may be used for logging, stats, downstream blending, experiments, or production logic not visible here. The safe takeaway is: X cares enough about mutual-follow overlap to compute it per selected candidate, but this release does not prove it is a primary ranking feature.


Part 2: What Hurts Your Reach

Hard Filters: These Delete Posts From Consideration

The pre-scoring filters in phoenix_candidate_pipeline.rs are binary. Pass or vanish.

Filter What kills the post File
DropDuplicatesFilter Duplicate tweet IDs in the candidate set filters/drop_duplicates_filter.rs
CoreDataHydrationFilter Posts that failed core metadata hydration filters/core_data_hydration_filter.rs
AgeFilter Posts older than configurable MAX_POST_AGE filters/age_filter.rs
SelfTweetFilter The viewer's own posts filters/self_tweet_filter.rs
RetweetDeduplicationFilter Multiple reposts of the same original post filters/retweet_deduplication_filter.rs
IneligibleSubscriptionFilter Subscriber-only content for viewers who are not subscribed filters/ineligible_subscription_filter.rs
PreviouslySeenPostsFilter Posts already seen by the user, including related quoted/reposted ids filters/previously_seen_posts_filter.rs
PreviouslySeenPostsBackupFilter Posts in the viewer's impressed-post history filters/previously_seen_posts_backup_filter.rs
PreviouslyServedPostsFilter Posts recently served in this session/request context filters/previously_served_posts_filter.rs
MutedKeywordFilter Posts matching the viewer's muted keyword token sequences filters/muted_keyword_filter.rs
AuthorSocialgraphFilter Authors the viewer blocked/muted, authors who block the viewer, quoted authors who block the viewer, quoted authors the viewer blocked, and retweeted authors the viewer blocked filters/author_socialgraph_filter.rs
VideoFilter Video candidates when the request excludes videos filters/video_filter.rs
TopicIdsFilter Candidates outside the requested topic context or inside excluded topics filters/topic_ids_filter.rs
NewUserTopicIdsFilter Out-of-network candidates outside selected new-user topics filters/new_user_topic_ids_filter.rs

The post-selection filters run after top-K selection:

Filter What kills the post File
VFFilter Visibility filtering says to drop, or returns another filtered reason filters/vf_filter.rs
AncillaryVFFilter Visibility filtering says ancillary posts should be dropped filters/ancillary_vf_filter.rs
DedupConversationFilter Lower-scoring posts in the same conversation are removed filters/dedup_conversation_filter.rs

A few of these deserve their own paragraph.

Tweet age is checked from the Snowflake ID. AgeFilter calls duration_since_creation_opt(tweet_id), so post age does not need an expensive database lookup. If the configured max age is strict, old posts are cheap to remove.

Muted keywords are a hard viewer-specific filter. MutedKeywordFilter tokenizes the viewer's muted keywords and the candidate text, then removes matching posts before scoring.

Subscriber-only content is invisible to non-subscribers. IneligibleSubscriptionFilter does not downrank paywalled posts. It removes them for viewers who are not subscribed to that author.

Conversation dedup is winner-takes-all after selection. DedupConversationFilter groups posts by conversation id, using the minimum ancestor tweet id when present, and keeps only the highest-scoring post in that conversation. A long self-reply thread can compete against itself in the final selected set.

Negative Engagement Is A Direct Score Penalty

home-mixer/scorers/ranking_scorer.rs:

let negative_sum = -(not_interested + block_author + mute_author + report + not_dwelled);

Phoenix predicts whether a viewer is likely to not-interest, block, mute, report, or skip-dwell on a post. Those predictions are multiplied by negative weights and reduce score. You do not need anyone to actually report you. The model only needs to predict that this viewer might.

Posts that pattern-match to ragebait, spam, reportable material, or low-quality engagement bait can lose before the first impression.

Author Diversity Punishes Eligible Burst-Posting

home-mixer/scorers/ranking_scorer.rs applies author diversity inside the active scorer:

fn diversity_multiplier(decay_factor: f64, floor: f64, position: usize) -> f64 {
    (1.0 - floor) * decay_factor.powf(position as f64) + floor
}

Candidates are sorted by weighted score, then repeated authors get progressively lower multipliers. If five of your posts are eligible at once, the first one is fine; later ones from the same author are attenuated. There is a floor, but the penalty is real.

Brand Safety Has Three Levels, But It Is Mostly Post-Selection Here

home-mixer/models/brand_safety.rs:

pub fn compute_verdict(...) -> BrandSafetyVerdict {
    if MEDIUM_RISK_LABELS.iter().any(|l| labels.contains_key(l)) {
        return BrandSafetyVerdict::MediumRisk;
    }
    if !scored_by_grok {
        return BrandSafetyVerdict::MediumRisk;
    }
    if tweet_id >= PTOS_CUTOFF_TWEET_ID && !labels.contains_key(&SafetyLabelType::PTOS_REVIEWED) {
        return BrandSafetyVerdict::MediumRisk;
    }
    if LOW_RISK_LABELS.iter().any(|l| labels.contains_key(l)) {
        return BrandSafetyVerdict::LowRisk;
    }
    BrandSafetyVerdict::Safe
}

A post can be Safe, LowRisk, or MediumRisk. Medium-risk labels include NSFW_HIGH_PRECISION, NSFW_HIGH_RECALL, NSFA_HIGH_PRECISION, NSFA_KEYWORDS_HIGH_PRECISION, GORE_AND_VIOLENCE_HIGH_PRECISION, DO_NOT_AMPLIFY, PDNA, EGREGIOUS_NSFW, GROK_NSFA, and NSFW_TEXT.

Posts created after PTOS_CUTOFF_TWEET_ID (2_054_275_414_225_846_272) default to MediumRisk unless they carry PTOS_REVIEWED.

But do not overread this as a visible organic ranking penalty. In the wired pipeline, brand-safety hydration runs after selection. It clearly matters for ad adjacency and downstream treatment. Separate visibility filtering (VFFilter) can drop posts outright based on visibility_reason, but VFFilter is not reading brand_safety_verdict directly in this code.

Grox Classifies Posts Into Trouble Buckets

The grox/ content-understanding pipeline runs classifiers and tasks that create labels used downstream:

  • SafetyPtosPolicyClassifier categorizes violations into AdultContent, ViolentMedia, Spam, IllegalAndRegulatedBehaviors, HateOrAbuse, ViolentSpeech, and SuicideOrSelfHarm.
  • SpamEapiLowFollowerClassifier targets reply spam, and TaskSpamDetection buckets reply context by follower counts (lte_100, lte_500, lte_1000, gt_1000).
  • TaskGrokUpaActionWithLabels and reply-spam label tasks write classifier results into label/action systems.

The practical takeaway is not "a keyword list kills you globally." It is that X has explicit content-understanding machinery for spam, safety, adult content, gore, violence, and related categories. Those labels can feed visibility, brand-safety, monetization, and other downstream decisions.


Part 3: The Final Feed Is Not Just Ranked Posts

Even after organic ranking, your post is entering a blended feed.

home-mixer/selectors/blender_selector.rs partitions the final candidates into:

  • organic scored posts
  • ads
  • Who To Follow modules
  • prompts
  • push-to-home posts

Then it:

  • blends ads with posts using either SafeGapAdsBlender or PartitionOrganicAdsBlender
  • inserts prompts
  • inserts Who To Follow
  • pins push-to-home content at the top when present

This matters for creators because "ranked high" and "appeared high in the final feed" are not exactly the same claim. Your organic post can rank well and still share the screen with ads, modules, prompts, or pinned push-to-home content.

The ads code also shows brand-safety-sensitive placement. PartitionOrganicAdsBlender separates safe and unsafe organic posts and avoids placing certain ads near posts with avoid signals. That is not the same as an organic downrank, but it changes the final feed layout.


Part 4: Why Reach Can Crater Without Users Vanishing

A lot of creators are currently saying their reach has cratered. Some of them are engagement farmers, aggregators, or content thieves. But some are legitimate posters who are not spamming, stealing, or obviously violating policy.

This code cannot prove what is happening on X right now. It can, however, explain how a lot of people can lose impressions at the same time without total platform traffic disappearing.

The key idea: the feed is a zero-sum allocation system. Every position in the feed goes to something. If one class of posts gets fewer impressions, those impressions usually moved to another class of posts, another source, another surface, or another feed unit.

Here are the most plausible explanations in light of this code.

1. The Weights May Have Changed

The repo shows many weights, but not their live production values.

If X increases the weight on not_dwelled, not_interested, mute_author, block_author, or report, posts that previously did fine can suddenly fall. This would hit obvious engagement bait first, but it can also hit legitimate content that is polarizing, repetitive, overly familiar to followers, or easy to scroll past.

If X increases weights on dwell_time, click_dwell_time, share_via_dm, follow_author, or VQV, traffic shifts toward posts that hold attention, travel privately, create follows, or perform as video.

Who gets the traffic? Posts with stronger predicted dwell, private sharing, follow-after-read, qualified video views, and lower predicted rejection.

2. The Source Mix May Have Shifted

The organic pipeline does not have only one source. It pulls from Thunder, Tweet Mixer, Phoenix Retrieval, Phoenix Topics, Phoenix MoE, and cached posts.

If feature switches change source budgets, retrieval clusters, topic retrieval, or new-user topic retrieval, the same total feed traffic can be redistributed. A creator may lose out-of-network impressions even if their followers still see them, because Phoenix is filling more slots from a different source or retrieval model.

Who gets the traffic? Candidates from whichever sources are being favored: more topic candidates, more Phoenix MoE candidates, more in-network Thunder candidates, more cached candidates, or more Tweet Mixer candidates.

3. The Optional Value Model Can Rewrite The Score

VMRanker runs after RankingScorer when enabled:

let score = score_map.get(&c.tweet_id).copied().or(c.score);

That means the visible weighted engagement formula may not be the final organic score. The request sent to VMRanker includes things like Phoenix scores, in-network status, retweet/reply flags, author follower count, viewer following count, and DPP parameters.

If VMRanker is enabled or retuned, creators can experience a sudden reach shift even though the basic Phoenix formula did not visibly change.

Who gets the traffic? Whatever the value model prefers. The repo does not show that model, so this is one of the biggest unknowns.

4. Negative Feedback May Be Predicted More Aggressively

A post does not need actual blocks, mutes, or reports to lose. Phoenix predicts those probabilities before serving.

That creates a path where legitimate content can be punished if it resembles content that historically led viewers to mute, block, report, not-interest, or skip. Examples could include repetitive political dunking, low-novelty AI slop, stale meme formats, contextless outrage, overused hooks, or posts that create replies but also create high rejection.

Who gets the traffic? Posts with cleaner engagement profiles: fewer predicted mutes, blocks, reports, not-interests, and skip-dwells.

5. Topic Filtering Can Make Reach Feel Random

The code has explicit topic request behavior, topic expansion, excluded topics, and new-user topic filtering.

If the platform leans harder into topic-routed distribution, a legitimate generalist account can lose reach because its posts are not cleanly legible to a topic graph. The post may be good, but not clearly eligible for the topic lanes currently receiving inventory.

Who gets the traffic? Accounts and posts that are easier for the system to place inside followed topics, new-user selected topics, and expanded topic categories.

6. Author Diversity Can Hit Frequent Legit Posters Too

Author diversity is meant to prevent one author from taking too many slots. That hurts burst posters and engagement farmers, but it can also hit legitimate writers who post many good things close together.

If more of your posts are eligible at once, they compete with each other. If the diversity decay or floor changes, the penalty can feel like a sudden reach cap.

Who gets the traffic? A broader set of authors, or authors who post fewer candidates that each individually clear the ranking bar.

7. Post-Selection Filters Can Create "I Was Ranking, Then Vanished"

Visibility filtering and conversation dedup run after selection. That means a post can survive candidate sourcing, hydration, filtering, scoring, and top-K selection, then still get removed.

Legitimate content near sensitive topics can get caught by safety or visibility systems. Long conversation threads can lose many posts to dedup. Quote/repost relationships can pull in blocked, muted, or unsafe related ids.

Who gets the traffic? The remaining selected posts after visibility and conversation cleanup.

8. Final Feed Units Can Displace Organic Posts

The final feed includes ads, prompts, Who To Follow modules, and push-to-home posts. If X changes ad load, prompt insertion, module placement, or push-to-home behavior, organic creators can lose visible positions even if organic ranking quality did not change.

Who gets the traffic? Not always another creator. Sometimes the slot goes to an ad, a module, a prompt, or a pinned feed unit.

9. A Crackdown On Aggregators Can Spill Over

If X is trying to reduce rewards for clickbait, stolen reposts, engagement farming, or aggregator behavior, the clean target is obvious. But classifiers and value models do not see moral intent. They see patterns.

Public reporting in April 2026 described X reducing payments to aggregators and habitual bait posters, with X's head of product saying that stolen reposts and clickbait had crowded out real creators. That was framed as a compensation change, not a reach change, but it is still a useful signal about what behavior X says it wants less of. (TechCrunch)

A legitimate account can resemble the bad pattern if it posts many similar hooks, summarizes others' work without enough original context, farms replies, reposts too much, or produces high engagement with high rejection.

Who gets the traffic? More original-seeming posts, accounts with cleaner negative-feedback profiles, and posts that produce value signals without looking manipulative.

10. Payout Drops And Reach Drops Can Be Confused

Creator complaints often mix two different things:

  • Reach: impressions and distribution.
  • Revenue: how much money those impressions earn.

The code here is about feed distribution. X can reduce payouts to certain behavior without reducing impressions by the same amount. It can also reduce impressions while payouts change for separate ad-market reasons. From the creator dashboard, both can feel like "the algorithm killed me."

So Where Did The Traffic Go?

If users did not suddenly stop using X, the traffic probably moved into some combination of:

  • in-network posts from accounts each viewer already follows
  • posts with stronger predicted dwell and private-share behavior
  • posts with lower predicted mute/block/report/not-interested risk
  • topic-aligned out-of-network candidates
  • video posts that clear the VQV eligibility path
  • candidates from a different retrieval source or model cluster
  • posts preferred by VMRanker
  • a broader set of authors due to author-diversity pressure
  • ads, prompts, Who To Follow modules, and push-to-home units

That is the uncomfortable truth of ranking systems: a reach collapse for one group can be a reach transfer to another group, not a disappearance of attention.


Part 5: The Unknowns. What Is Almost Certainly Affecting Reach But Is Not Fully Visible

This is the section every other writeup of this code skips. It matters more than the rest.

The released code is mostly architecture, formula, and service boundaries. The numbers, production model weights, and several decision systems are not present. Here is what is likely affecting reach but is not fully knowable from this repo:

1. The actual numeric weights. FavoriteWeight, ReplyWeight, RetweetWeight, BlockAuthorWeight, OonWeightFactor, AuthorDiversityDecay, MinVideoDurationMs, and many more are loaded from xai_feature_switches::Params. The code reveals parameter names and control flow, not production values. Public claims like "replies count more than likes" are not verifiable from this repo alone.

2. Feature switches and deciders. Many major behaviors are runtime-gated: VMRanker, Phoenix cluster selection, topic retrieval, topic filtering, video handling, served filters, brand-safety hydrators, and more. The released code shows switches. It does not show their production rollout values.

3. VMRanker internals. The code wires an optional VMRanker after RankingScorer, and the response can overwrite candidate scores. But the actual external value model is not in this repo.

4. Verification, Premium, and Premium+ tier effects. The visible code references subscription levels (Basic, Premium, PremiumPlus) in logging and ads side effects. I do not see a released scorer that directly boosts Premium accounts. If such an effect exists, it is upstream, feature-switched, hidden inside model weights, or outside this release.

5. Author reputation / quality score. Older Twitter systems had author reputation ideas such as TweepCred. This repo does not show a clear successor as a simple ranking feature.

6. The actual production Phoenix model. The included Phoenix artifacts are a mini release/demo checkpoint, not enough to prove production behavior. Production rankers are almost certainly larger, continuously trained, and much more deeply tuned.

7. Link / external-URL handling. There is no explicit released filter that says "downrank external links." If link suppression exists, it is learned by Phoenix, handled by hidden policy, or outside this code path.

8. Original-vs-reposted boost. RetweetDeduplicationFilter dedupes reposts of the same original post. I do not see a visible "original content gets a bonus" rule. If originals perform better, that may be learned behavior, source behavior, user behavior, or production logic not shown here.

9. Follower count and ratios. Follower count is not in the main RankingScorer formula, but it is sent to VMRanker as author_followers_count. Follower/following ratio is not visible as a direct feature in the released scoring formula.

10. Real-time virality detection. No explicit "this post is going viral, boost it" component appears in the visible scorer. Production systems often have velocity and trend systems. They may be upstream, model-learned, or outside this release.

11. Negative-feedback propagation beyond the viewer. Block, mute, not-interested, report, and not-dwelled are predicted per viewer and used in score. Whether high global rates suppress authors or posts beyond individual viewer prediction is not visible here.

12. Conversation health signals. X has publicly referenced reply health concepts. This release has reply-spam and safety machinery, but a complete conversation-health ranker is not visible.

13. Anti-bot / inauthentic-behavior penalties. Grox handles spam classification, and the repo references spam labels. Dedicated bot or coordinated-behavior penalties are not fully visible.

14. Notifications and re-engagement loops. This code returns feed responses. Push notifications and other session-start systems are separate and can massively affect reach without being part of this ranker.

15. Geo, language, and market treatment. Language codes are hydrated and passed into tweet info; IP, demographics, and country are part of query/context systems. The visible scorer does not expose a simple "same language boost" or "geo boost" formula.


What To Actually Do

Do:

  • Make posts that earn real dwell, not just drive-by impressions.
  • Invite replies without sliding into ragebait or spam patterns.
  • Create things people privately share: useful posts, jokes, clips, explanations, links worth sending.
  • Use images and video when they genuinely increase attention; make video long enough to qualify for the VQV path.
  • Build real followers in the communities you care about. In-network distribution avoids the OON multiplier.
  • Stay legible to a topic/community. Topic context has explicit source, filter, and multiplier paths.
  • Pace posting. Multiple eligible posts from the same author are attenuated by author diversity.
  • Keep posts broadly brand-safe and visibility-safe if you care about maximum distribution.

Do Not:

  • Burst-post and expect all posts to surface together.
  • Run long self-reply threads assuming every part gets feed space. Conversation dedup can keep only the best selected post.
  • Mark content subscriber-only when your goal is broad reach.
  • Use muted-keyword bait or spammy reply tactics.
  • Treat "Premium boost," "link penalty," or "original-content boost" as proven by this code. This repo does not prove those claims.
  • Confuse organic rank with final feed position. Ads, prompts, Who To Follow, and push-to-home units can alter what the user actually sees.

Always remember:

The released code shows the skeleton: source routing, filters, weighted action predictions, author diversity, OON multipliers, optional value-model reranking, post-selection safety, and final feed blending.

The flesh, production feature-switch values, model weights, hidden services, policy rollouts, and learned model taste, is what decides the exact distribution.

Read the code for the rules. Watch the platform for the numbers.


All findings above are from the open-source release X published. File paths are included so you can verify them yourself. Where I make an inference rather than a direct reading, I say so. Where information is missing from the code, it is placed in the Unknowns section instead of being silently filled in.

If you want the plain-English version of all this, see Why Your X Reach Changes: A Plain-English Guide To The For You Feed.

Comments