Skip to content

Latest commit

 

History

History
598 lines (427 loc) · 30.9 KB

File metadata and controls

598 lines (427 loc) · 30.9 KB

Algorithm deep-dive

The full operational map of X's For-You feed algorithm. Sourced from xai-org/x-algorithm (May 2026), twitter/the-algorithm (March 2023, parts still in production), twitter/communitynotes, and public analyses.

Confidence markers: 🟢 confirmed by xAI / 🟡 likely (2023 published, 2026 structurally preserved) / 🟠 reasoned from recsys literature


TL;DR

Two stages to survive:

  1. Banger screen on write — every original post is screened by a Grok classifier the moment it's published. Pass threshold = quality_score >= 0.4. The classifier also returns an explicit slop_score (AI-slop detector) that influences distribution labels.
  2. For-You ranker on read — the Phoenix transformer scores every candidate per viewer using ~22 action probabilities, then a weighted sum + Author Diversity + OON/VMRanker (with DPP diversity) picks the order.

The 4-rule TLDR:

  1. TweepCred ≥ 65 — below this, only ~3 of your tweets get distributed at a time.
  2. reply_engaged_by_author is +75 weight = 150× a like. Reply hand-typed within first hour.
  3. 10+ replies in 15 minutes triggers OON cascade.
  4. report is −369 weight — single report kills ~700 likes of signal.

System architecture

POST PUBLISHED  →  GROX CONTENT UNDERSTANDING (parallel, 9 plans)
   │
   ├─ BangerInitialScreen        — quality_score (≥0.4 pass), slop_score, has_minor_score
   ├─ SafetyPtosCategory (VLM)   — 7-category policy detection
   ├─ SafetyPtosPolicy           — per-category policy assignment
   ├─ PostSafetyScreenDeluxe     — second-pass critical-model check
   ├─ GrokUpaActionWithLabels    — applies distribution labels
   ├─ SpamDetection (replies)    — follower-bucketed spam classifier
   ├─ ReplyRanking               — VLM_MINI_CRITICAL scorer, 0.0-3.0
   ├─ MultimodalPostEmbedderV5   — 1024-dim text+image+transcript embedding
   └─ PostEmbeddingWithSummary   — text-summarized embedding for context

   ↓  decorates post with labels + safety + embeddings

FOR-YOU FEED REQUEST (per viewer)
   │
   ├─ QUERY HYDRATION (21 hydrators)
   │    blocked/muted users, follow list, mutual-follow MinHash (256+),
   │    served history, impression bloom filter, user_action_seq (Dense
   │    for retrieval / DenseWithNotInterestedIn for scoring),
   │    inferred_grok_topics, followed_starter_packs, user_demographics,
   │    inferred_gender, IP, past_request_timestamps
   │
   ├─ CANDIDATE SOURCES (parallel)
   │    ThunderSource           — in-network (followed accounts)
   │    PhoenixSource           — OON two-tower retrieval
   │    PhoenixMOESource        — OON mixture-of-experts (new May 2026)
   │    PhoenixTopicsSource     — topic-targeted retrieval
   │    TweetMixerSource        — legacy fallback
   │    AdsSource               — paid candidates
   │    WhoToFollowSource       — 3 account recs (WTF module)
   │    PromptsSource           — system inline/cover prompts
   │    PushToHomeSource        — pinned-at-top with top-3 reply facepile
   │      (SimClusters' 145k communities feed ~85% of OON candidates)
   │
   ├─ CANDIDATE HYDRATION (17 hydrators)
   │    CoreData, Author (Gizmoduck), EngagementCounts (5/10-min TTL),
   │    HasMedia, VideoDuration, InNetwork, MutualFollowJaccard (256-hash),
   │    Quote expansion, Subscription, AdsBrandSafety, BlockedBy,
   │    FilteredTopics, FollowingRepliedUsers (≥1k follower viewers only),
   │    TweetTypeMetrics bitset, LanguageCode
   │
   ├─ PRE-SCORING FILTERS (14)
   │    DropDuplicates, CoreDataHydration, Age (max 80h), SelfTweet,
   │    RetweetDedup, IneligibleSubscription, PreviouslySeenPosts (bloom),
   │    PreviouslyServedPostsBackup, MutedKeyword (tokenized),
   │    AuthorSocialgraph (block/mute, both directions), TopicIds,
   │    NewUserTopicIds, Video (opt-out), AncillaryVF
   │
   ├─ SCORING (4 scorers chained)
   │    1. PhoenixScorer        — Grok transformer, ~22 P(action)
   │    2. WeightedScorer       — Σ weight × P(action) + offset
   │    3. AuthorDiversityScorer — (1−0.25) × 0.5^position + 0.25
   │    4. VMRanker (+ OON)     — value model with DPP diversity
   │
   ├─ SELECTION
   │    TopKScoreSelector → top-K by final score
   │    BlenderSelector   → mix posts + ads + WTF + prompts + PTH
   │
   └─ POST-SELECTION FILTERS
        VFFilter (drops on DO_NOT_AMPLIFY + 13 other Medium-Risk labels,
                  community notes, etc.)
        DedupConversationFilter (keeps best score per conversation root)

   ↓

RANKED FEED RESPONSE

1. The Grox content-understanding pipeline (runs on write)

Before your post enters any candidate pool, Grox runs 9 plans in parallel via asyncio.gather. Their outputs decorate the post with labels and embeddings that Home Mixer downstream consumes.

1a. BangerInitialScreen — "is this viral material?" 🟢

  • Filter: excludes replies and protected accounts. Only original public posts.
  • Runs BangerInitialScreenClassifier.classify(post, topics=cached_grok_topics) against a 1-hour-TTL cache of Grok topics.
  • Uses Grok VLM_PRIMARY at temperature 0.000001 (effectively deterministic).
  • Sees BOTH the post (text + media) AND the author. Your author identity is a feature of your own banger screening.

Returns:

quality_score: float       # 0.0–1.0, pass threshold = >= 0.4
description: str           # Grok's summary
tags: list[str]            # extracted tags
taxonomy_categories: list  # multi-category scores
tweet_bool_metadata        # boolean labels
is_image_editable_by_grok  # AI-vs-real-image flag
slop_score: int            # AI-slop detector
has_minor_score: float     # child-safety detector

Key implications:

  • Below 0.4, no distribution-label boost from downstream GrokUpaActionWithLabels.
  • slop_score is an explicit, first-class concern. Generic marketing vocabulary trips it.
  • has_minor_score is an independent child-safety detector — avoid ambiguous "kid", "child", "schoolboy" language.

1b. PostSafetyScreenDeluxe — second-pass critical check 🟢

Runs PostSafetyDeluxeClassifier (uses VLM_PRIMARY_CRITICAL) on every eligible original post. Feeds the same GrokUpaActionWithLabels label-application step.

1c. SafetyPtos — 7-category policy detection 🟢

Two-stage:

  1. SafetyPtosCategoryClassifier (VLM-based) flags violation categories
  2. SafetyPtosPolicyClassifier assigns a specific policy per violation (each category has its own Grok prompt)

The 7 enforced categories: ViolentMedia, AdultContent, Spam, IllegalAndRegulatedBehaviors, HateOrAbuse, ViolentSpeech, SuicideOrSelfHarm.

Deluxe mode uses Grok 4.2 reasoning (EAPI_REASONING) specifically for AdultContent + ViolentMedia. Always injects an AdultContent recheck for posts that didn't otherwise flag.

Note: the VLM examines BOTH text and image. A safe caption with a borderline image still trips the classifier.

1d. GrokUpaActionWithLabels — the AI moderation layer 🟢

Takes the union of BangerScreen + PostSafetyDeluxe outputs (a tweet_bool_metadata blob), sends it to StratoGrokUpaActionWithLabels, gets back a list of distribution-influencing labels.

No appeal mechanism in the pipeline. Labels are applied programmatically based on classifier outputs.

1e. Reply spam detection — follower-bucketed 🟢

SpamEapiLowFollowerClassifier runs on replies where both immediate-parent AND root author have follower_count ≤ threshold. Bucketed metrics: lte_100, lte_500, lte_1000, gt_1000.

Implication: replying to big-account posts is "free" (skips spam classifier). Replying to small-account posts is heavily scrutinized.

1f. Reply ranking — for big posts only 🟢

ReplyScorer computes a 0.0–3.0 score for replies on posts whose immediate-parent OR root author exceeds the follower threshold.

Models: VLM_MINI_CRITICAL primary + VLM_PRIMARY_CRITICAL fallback (when JSON output is malformed).

Signals fed into the Grok prompt (via ThreadRenderer with include_signals=True):

  • is_pasted — copy-pasted reply?
  • user_agent
  • composition_source
  • app_attestation_status — proves real device?
  • has_risky_user_safety_label (on the reply author)
  • num_legit_blocks_received_last_24hrs (on the reply author)

1g. MultimodalPostEmbedderV5 — what gets embedded 🟢

Embeds text + images + optional video transcript jointly via RECSYS_EMBED_V5. Output: 1024-dim normalized embedding (truncated from larger).

Text limit: 4096 chars. Multi-image supported. Transcript appended as "\nTranscript: …".

Only embeds original posts from non-protected accounts. Replies get a separate post_embedding_with_summary_for_reply track.

Implication: posts with images and videos get richer embeddings = tighter retrieval matches into the right Phoenix clusters.


2. Candidate sources

2a. ThunderSource — in-network 🟢

Kafka-fed in-memory store keyed per-user. Sub-millisecond reads. Returns recent posts from accounts the viewer follows. Trims posts after a retention window.

2b. PhoenixSource — main OON two-tower retrieval 🟢

User tower encodes the viewer's retrieval_sequence into a query embedding. Candidate tower has all posts pre-embedded. Top-K retrieval by dot-product similarity, K = PhoenixMaxResults.

New users (engagement history shorter than PhoenixRetrievalNewUserHistoryThreshold) get routed to a different model cluster tuned for cold-start.

2c. PhoenixMOESource — Mixture-of-Experts variant (NEW May 2026) 🟢

Same interface as PhoenixSource but uses a Mixture-of-Experts model cluster. Runs in parallel with main PhoenixSource when enabled. Adds an orthogonal retrieval path.

2d. PhoenixTopicsSource — topic-targeted retrieval 🟢

Activated for explicit topic_ids (For-You topic tabs) OR new users with inferred topic interests. Calls retrieval with topic_entity_ids constraints.

The topic universe is enumerated in home-mixer/filters/topic_ids_filter.rs (lines 113-290). 100+ topic IDs covering science, entertainment, business, sports, politics, AI, crypto, gaming, news, music, etc.

2e. TweetMixerSource — legacy fallback 🟡

The older Tweet Mixer service. Lower-weight contributor in 2026 but still in the candidate pool.

2f. SimClusters — still feeds ~85% of OON candidates 🟢

Not in the 2026 release, but still in production from 2023. SimClusters identifies 145,000 communities via sparse non-negative matrix factorization. Produces KnownFor (clusters an author belongs to via co-engagement) and InterestedIn (clusters a viewer engages with).

PhoenixSource pulls from SimClusters' output. You enter a cluster's KnownFor set by being co-engaged-with by accounts already in that cluster.

Source: SimClusters paper (KDD 2020).

2g. AdsSource, WhoToFollowSource, PromptsSource, PushToHomeSource 🟢

Paid candidates, "Who to Follow" module (3 user recs), system prompts (inline / full-cover / half-cover / relevance), and a pinned-to-top push-to-home slot (which includes a top-3 reply facepile from ReplyMixerClient.get_scored_replies()).


3. Hydration — what the model sees about each candidate

After candidates are sourced, 17 hydrators decorate each with features:

Hydrator What it adds Why it matters
CoreDataCandidateHydrator Text, media, timestamp Hard requirement
GizmoduckHydrator Author info (username, verification) In-network check
InNetworkCandidateHydrator in_network: bool flag Drives OON multiplier
EngagementCountsHydrator fav/reply/repost/quote counts, 5-min TTL <30min, 10-min TTL after Early velocity is what the model sees fresh
HasMediaHydrator Boolean Photo_expand / vqv eligibility
VideoDurationCandidateHydrator min_video_duration_ms Required for vqv weight
MutualFollowJaccardHydrator 256-MinHash Jaccard between viewer and author follow sets Tighter follow-graph overlap = better ranking
LanguageCodeHydrator Language detection Cross-language demotion
QuoteHydrator Quoted post expansion Enables quoted_click / quoted_vqv
SubscriptionHydrator subscription_author_id IneligibleSubscriptionFilter
AdsBrandSafetyHydrator(+Vf) Brand-safety annotations on ads Paid only
BlockedByHydrator Author blocks viewer? Mutual-block surface
FilteredTopicsHydrator filtered_topic_ids + unfiltered_topic_ids Topic filtering
FollowingRepliedUsersHydrator Facepile of viewer's follows who replied — viewers with ≥1k followers only Social proof at the highest-reach surface
TweetTypeMetricsHydrator Bitset of categorical features The model's "what kind of post is this" feature

TweetTypeMetricsHydrator bitset features

  • ANY_CANDIDATE, RETWEET, REPLY, SUBSCRIPTION_POST, HAS_ANCESTORS, IN_NETWORK, FULL_SCORING_SUCCEEDED
  • Author follower bucket: AUTHOR_FOLLOWERS_0_100, 100_1K, 1K_10K, 10K_100K, 100K_1M, 1M_PLUS
  • Video: VIDEO, VIDEO_LTE_10_SEC, VIDEO_BT_10_60_SEC, VIDEO_GT_60_SEC
  • Age buckets: TWEET_AGE_LTE_30_MINUTES, LTE_1_HOUR, LTE_6_HOURS, LTE_12_HOURS, GTE_24_HOURS
  • Request-state: EMPTY_REQUEST, NEAR_EMPTY, SERVED_SIZE_LESS_THAN_20, _10, _5

Author-follower cliffs are real categorical feature transitions. Reach scales non-linearly at 100, 1k, 10k, 100k, 1M.

EngagementCountsHydrator velocity math 🟢

  • Cache: 1M entry Moka cache
  • 5-minute TTL for tweets < 30min old
  • 10-minute TTL for tweets ≥ 30min old

Implication: the first 30 minutes of a post's life determine its trajectory. Engagement that arrives in those 30 minutes is what the Phoenix scorer sees fresh for everyone who pulls a For-You feed during that window.


4. Pre-scoring filters (14 — what gets dropped)

Filter What it drops
DropDuplicatesFilter Duplicate tweet_ids within the candidate set
CoreDataHydrationFilter Posts whose core data hydration failed
AgeFilter Posts older than max_age (capped by MAX_POST_AGE)
SelfTweetFilter The viewer's own posts
RetweetDeduplicationFilter Reposts of an already-present underlying tweet
IneligibleSubscriptionFilter Paywalled posts the viewer isn't subscribed to
PreviouslySeenPostsFilter Posts in seen_ids OR matching impression Bloom filter
PreviouslyServedPostsBackupFilter Backup against re-serving recently-served
MutedKeywordFilter Tokenized match against viewer's muted keywords
AuthorSocialgraphFilter Bidirectional block/mute check
TopicIdsFilter Posts not matching requested topic IDs (with super-topic expansion)
NewUserTopicIdsFilter New users: keeps in-network OR topic-matching posts
VideoFilter When exclude_videos is set
AncillaryVFFilter Drops if upstream flagged drop_ancillary_posts

Writer leverage notes:

  • Bloom filter for previously-seen means once a viewer has scrolled past, the post won't re-surface. Edits don't help. One post = one shot per viewer.
  • MutedKeywordFilter is tokenized, not substring. Compound words match the muted root.
  • AuthorSocialgraphFilter checks both directions. If a target user has blocked your account, you don't reach them — track block rate.

5. The scoring pipeline (4 scorers)

5a. PhoenixScorer — Grok-transformer multi-action predictor 🟢

Takes the viewer's scoring_sequence (engagement history with DenseWithNotInterestedIn aggregation — explicitly includes negative feedback) + candidate batch → returns ~22 action probabilities per candidate.

Candidate isolation: candidates can attend to the user and history, but NOT to each other. Scores are independent and cacheable.

New users (engagement history < PhoenixRankerNewUserHistoryThreshold) get a separate cold-start model cluster.

Production model:

  • Mini config (released): 128–256 dim embeddings, 2–4 layers, 4 heads, 1M-each user/item/author vocab, 2 hashes per entity, 19 action outputs.
  • Production: wider + deeper (exact dimensions not published).
  • history_seq_len = 128, candidate_seq_len = 32
  • Continuous values clamp at 30s (NormConfig.norm_scale = 30) — dwell time saturates.
  • 16 product surfaces (For-You, Following, Notifications, Search, etc.). Same post scores differently on different surfaces.
  • mask_neg_feedback_on_negatives = True — training masks negative feedback on already-negative posts.

Phoenix retrieval (user tower): mean-pools history transformer outputs, then L2-normalizes. Recent engagement spikes pull the user vector strongly toward that cluster.

Phoenix retrieval (candidate tower): 2-layer SiLU MLP. Author embedding is mixed into the candidate embedding — same author posting similar content lands geometrically close.

5b. WeightedScorer / RankingScorer — Σ weight × P(action) 🟢

score = Σ (weight_i × P(action_i)) + offset

The 22 weighted signals (full list with 2023 published weights where available):

Positive-weight (write to maximize):

  • favorite — +0.5 (2023)
  • reply — +13.5 (2023)
  • retweet — +1.0 (2023)
  • quote — (not disclosed 2023, likely high)
  • quoted_click — (not disclosed 2023)
  • quoted_vqv — (not disclosed 2023)
  • click / good_click — +10 to +11 (2023)
  • good_profile_click — +12.0 (2023)
  • profile_click — likely lower than good_profile_click
  • vqv — (not disclosed 2023, likely high — video is heavily promoted)
  • share, share_via_dm, share_via_copy_link — (not disclosed 2023)
  • dwell, cont_dwell_time, cont_click_dwell_time — (saturates at 30s)
  • follow_author — (not disclosed 2023, likely high)
  • reply_engaged_by_author+75.0 (2023) — 150× a like

Negative-weight (write to NOT trigger):

  • not_interested, block_author, mute_author (individual)
  • negative_feedback_v2−74.0 (2023) — aggregate of block/mute/not-interested
  • report−369.0 (2023) — 5× more catastrophic
  • not_dwelled — scroll-past penalty

Offset behavior: Negative-predicted posts aren't fully killed; they're compressed by (combined + negative_sum) / total_sum × NEGATIVE_SCORES_OFFSET. So even a negative-predicted post can surface if nothing else fills the slot.

5c. AuthorDiversityScorer — attenuates repeat authors 🟢

multiplier(position) = (1 − floor) × decay^position + floor

2023 values (likely-preserved in 2026): floor=0.25, decay=0.5.

Position Multiplier
0 (first post from author this feed) 1.000
1 0.625
2 0.438
3 0.344
0.250

Implication: the 5th tweet in a thread runs at ~30% of standalone score in any given feed. One banger > 10-tweet thread.

5d. VMRanker + OON — value model with DPP diversity 🟢

A separate gRPC-served Value Model Ranker that takes Phoenix scores + raw metadata (in_network, is_retweet, is_reply, author_followers_count, vqv_ineligible flag) + viewer_following_count as input and outputs a final score.

Has an A/B-testable value_model_id — multiple value models can run in parallel.

DPP (Determinantal Point Process) diversity via two params:

  • dpp_theta (>0 enables — controls diversity strength). 🟠 Typical 0.3–0.7 in academic literature; most production at ~0.5.
  • dpp_max_selected_rank (caps DPP-rerank scope). 🟠 Typical 20–40.

DPP demotes embedding-similar posts even from different authors. Same topic + same angle = DPP-attenuated. Same topic + different angle = DPP-friendly.

OON multiplier: OON candidates' final scores are multiplied by OON_WEIGHT_FACTOR = 0.75 (2023). New users get NEW_USER_OON_WEIGHT_FACTOR (higher). Topic requests use TopicOonWeightFactor. Blue Verified out-of-network: 2× extra (in-network: 4×).


6. Selection + post-selection filters + blender

TopKScoreSelector

Sorts by final score, takes top TOP_K_CANDIDATES_TO_SELECT.

Cached-posts fast path 🟢

CachedPostsSource: when a request has has_cached_posts == true (certain infinite-scroll continuations), the pipeline returns the cached posts verbatim and skips all sources, hydrators, filters, and scorers. Posts that scored well in the initial ranking pass get cached and re-surface to follow-on requests in the same session without being re-scored. Practical takeaway: your post's first scoring pass determines its re-surface eligibility for the next stretch of a viewer's session — another reason the first 30 minutes matter.

Post-selection filters

  • VFFilter — applies the visibility-filtering engine; drops candidates with Action::Drop (deleted, spam, gore, violence, DO_NOT_AMPLIFY, etc.). Also drops on any other FilteredReason::* variant.
  • DedupConversationFilter — for posts sharing a conversation root, keeps the highest-scored one and drops the rest.

Writer leverage on DedupConversation: when you reply in a viral thread, only your best-scoring post in that conversation survives into any given viewer's feed. One stellar reply > five mediocre.

Blender — final feed assembly

  • Partitions surviving items into: posts, ads, who-to-follow, prompts, push-to-home.
  • Runs an AdsBlender (default partition_organic, optional safe_gap) to interleave ads.
  • Inserts prompts at the top (PROMPTS_POSITION).
  • Inserts Who-to-Follow at WHO_TO_FOLLOW_POSITION.
  • Pins push-to-home at position 0 if present.

Ad insertion math:

  • MIN_POSTS_FOR_ADS = 5 — feed needs ≥5 organic posts before any ad inserts
  • MIN_REQUESTED_GAP = 3, default spacing { requested: 3, min: 2 }
  • Ads only insert between two LowRisk posts. MediumRisk posts get excluded from ad-adjacency.

7. Side effects → training data spine

Every served candidate triggers Kafka publishes that feed back into Phoenix's continuous training:

  • served_candidates_kafka_side_effect.rs — served candidates
  • client_events_kafka_side_effect.rs — every click, dwell, etc., with split by post_count / ad_count / wtf_count
  • Per-bit tweet_type events (each TweetTypeMetricsHydrator bit)
  • Per-served_type events (for_you_in_network, for_you_phoenix_retrieval, for_you_phoenix_retrieval_moe, for_you_tweet_mixer, etc.)
  • Query events × size buckets × request contexts (launch, foreground, pull_to_refresh, get_older, get_newer)
  • phoenix_request_cache_side_effect.rs + redis_post_candidate_cache_side_effect.rs — caching layers

The Phoenix model trains continuously on this stream. Yesterday's engagement shapes today's ranker.


8. Brand Safety Verdict — 4 levels 🟢

enum BrandSafetyVerdict {
    Unspecified = 0,    // not yet computed
    Safe = 1,           // best — full distribution + ad-adjacency
    LowRisk = 2,        // acceptable — ad-adjacency OK, slight reach reduction
    MediumRisk = 3,     // suppressed — no ad-adjacency
}

Medium-Risk labels (14 — these push you to suppression)

  • NSFW_HIGH_PRECISION, NSFW_HIGH_RECALL
  • NSFA_HIGH_PRECISION, NSFA_KEYWORDS_HIGH_PRECISION
  • GORE_AND_VIOLENCE_HIGH_PRECISION
  • NSFW_REPORTED_HEURISTICS, GORE_AND_VIOLENCE_REPORTED_HEURISTICS
  • NSFW_CARD_IMAGE (link preview was flagged)
  • DO_NOT_AMPLIFY — the canonical formal X distribution-suppression label
  • NSFA_COMMUNITY_NOTE — community notes can hard-suppress
  • PDNA — Photo DNA child-safety hash match
  • EGREGIOUS_NSFW
  • GROK_NSFA — Grok itself flagged as NSFA
  • NSFW_TEXT

Low-Risk labels (3)

  • NSFA_LIMITED_INVENTORY
  • GROK_NSFA_LIMITED
  • NSFA_HIGH_RECALL

Two critical default rules

  1. Default verdict = MediumRisk if NOT Grok-scored. Posts without GROK_SFA or GROK_NSFA_LIMITED labels are automatically MediumRisk. If your post slips through Grok's classification queue, you're suppressed by default.
  2. Posts newer than tweet_id 2_054_275_414_225_846_272 (late-2024 / early-2025 cutoff) without PTOS_REVIEWED are auto-MediumRisk.

BotMaker — the automated rules engine

1000-1099: Content
1100-1199: ContentLimited
1200-1399: Safety
1400-1499: Grok
1500-1600: Quote

Rules fire automatically without human review. A single rule hit can attach a safety label that cascades to MediumRisk.


9. TweepCred — the hidden account reputation score 🟢

Not in 2026 open source but widely documented. 0–100 PageRank-adapted score per account.

Threshold 65:

  • ≥ 65: ALL your tweets enter the For-You ranker candidate pool
  • < 65: Only ~3 of your tweets at a time are eligible for distribution

Inputs:

  • Account age (older = higher)
  • Follower-to-following ratio (more followers per follow = higher)
  • Engagement quality with high-TweepCred accounts (engaging with credible accounts lifts you)
  • Device patterns (mobile-native engagement scores better than headless/API)
  • Overall engagement quality history

Recalculated periodically (days-to-weeks), not real-time.

If your TweepCred is below 65, no individual post strategy matters much. Fix account reputation first.


10. SimClusters — the OON candidate gate (still live in 2026)

twitter/the-algorithm/src/scala/com/twitter/simclusters_v2

  • 145,000 communities (topic + social-relationship clusters)
  • Sparse non-negative matrix factorization
  • KnownFor assigns each producer (author) to small number of clusters they're known for. Computed from who follows them + co-engagement patterns.
  • InterestedIn assigns each consumer (viewer) to clusters they engage with.
  • Powers ~85% of OON candidate generation that flows into Phoenix retrieval.

You earn KnownFor status in a cluster by being co-engaged-with by accounts already in that cluster.

Fastest path: get retweets / replies from clearly-clustered figures. One retweet from a cluster-central account does more for your KnownFor than 100 retweets from peripheral accounts.


11. Community Notes / Birdwatch (drives NSFA_COMMUNITY_NOTE)

github.com/twitter/communitynotes — separately open-sourced, actively developed.

Once a note attaches: posts receive significantly fewer reposts, likes, replies, and views (research-confirmed). The NSFA_COMMUNITY_NOTE Medium-Risk label kicks in.

Implication: every factual claim must withstand cross-ideological scrutiny. The bridging algorithm specifically catches claims that one side will mark "helpful note" and the other side will agree on.


12. Visibility Library (the centralized VF engine) 🟡

twitter/the-algorithm/visibilitylib (2023). The 2026 vf_filter.rs calls into xai_visibility_filtering — almost certainly its descendant.

  • Centralized rule engine that instructs clients how to alter content display at read time
  • Supports: legal compliance, product quality, user trust, revenue protection via hard-filtering, visible product treatments, coarse-grained downranking
  • Manifestations: search ban, reply de-boosting (hidden under "show more replies"), recommendation suppression, reach-limiting

13. Earlybird — search and the alternate reach surface 🟡

The 2023 inverted-index search system. Almost certainly still alive.

Your post text is tokenized and indexed in Earlybird. Hashtag matches, $TICKER matches, named-entity matches surface your post in search — separate from the For-You ranker.

The named-entity density tactic (P-10) lifts you in Earlybird search results, which is its own reach pool independent of the algorithmic feed.


14. Confidence inventory — what's published vs not

🟢 Confirmed public (in code or 2023/2026 release):

  • Pipeline structure (4 scorers, 5 candidate sources, 14 filters, 17 hydrators, 9 Grox plans)
  • 7-category PTOS classification
  • 14 Medium-Risk + 3 Low-Risk safety labels
  • 4-level brand-safety verdict
  • Default-to-MediumRisk for non-Grok-scored posts
  • Banger threshold (0.4), reply score range (0–3), classifier rate limit (60s/10k posts)
  • Engagement count cache TTLs (5/10 min)
  • Post age horizon (80h), hourly buckets
  • Dwell saturation (30s)
  • Author-follower buckets (100/1k/10k/100k/1M)
  • Phoenix mini config (128–256 dim, 2–4 layers, 4 heads, 19 actions, 8 continuous)
  • Min posts for ads (5), default spacing (every 3rd)
  • TweepCred threshold (65)
  • 2023 weights: fav 0.5, retweet 1.0, reply 13.5, reply_engaged_by_author 75, profile_click 12, click 10–11, negative_feedback −74, report −369, video_playback50 0.005

🟡 Likely (2023 published, 2026 structurally preserved, exact values may have drifted):

  • Author Diversity floor=0.25 / decay=0.5
  • OON multiplier 0.75
  • Blue Verified 4× in-network / 2× OON
  • Viral threshold ~10 replies in 15 min

🟠 Reasoned (from standard recsys literature):

  • DPP theta typical 0.3–0.7
  • DPP max_selected_rank typical 20–40
  • Phoenix production dimensions 4–8× the mini config

Confirmed NOT public:

  • 2026 production ranker weights (learned, not configured)
  • VMRanker model architecture
  • Phoenix production model dimensions
  • Grox classifier prompt bodies (BangerMiniVlmScreenScore, ReplyScoringSystem, 7 PTOS prompts, PostSafetyDeluxe, SpamSystemLowFollower)
  • TweepCred exact formula and recalculation cadence
  • BotMaker rule definitions (only ID range categories are public)

Sources