- Sources read: 2
- Canon files updated: 2
- Radar entries: 1
Other changes reviewed today:
- In the same commit, X raised two home-mixer mirror weights, like and not interested, by the same 1.1×.
- X cut the account list of its Brazil election filter to 25 accounts related to the runoff.
- A paper reported that WeGR, WeChat Search's generative retrieval, has been deployed on several search surfaces.
1Training code released for a re-ranker that fills a page with reinforcement learning — X
Source xai-org/x-algorithm@17c96bf — xAI public repository, commit of 2026-10-14 03:41 UTC, code. These notes number the X commits after the Gen4 release in order, and this commit is Gen4+41. It changed 53 files, about +7,745/−6,964 lines by diff.
Background In X's For You feed, the ranking model Phoenix predicts the probability of actions such as like, reply, and report for each candidate, and candidates are sorted by the weighted sum of those probabilities. Then a separate service called VM-Ranker re-adjusts the order with DPP. DPP (determinantal point process) is a diversity technique that selects at the set level, cutting the score when similar items are picked together. Because this approach scores each item separately, it cannot directly address the question "at which position should this item go so that the user views the page to the end?"
Slate (a bundle of items shown at once) level reinforcement learning is a way to address this question. The policy (actor) fills slots one at a time. The value function (critic) improves the policy by predicting "the sum of rewards from the remaining slots from this point on." This commit is code showing that X is actually training this structure.
What we learnedA. The re-ranker consists of a page decoder trained on a dwell-time reward and a twin critic
A new page-level RL training config for the immersive surface was added verified —
configs/xrecsys.py:388-417, 477-483.- In the code, this re-ranker is named
page_rl. - The config name is
immersive_page_rl. It turns onpage_rl=PageRlConfig(enabled=True)on the home ranker base. - A separate Kafka topic for training data,
user_action_sequence_immersive_page_rl, was also created.
- In the code, this re-ranker is named
Re-ranking proceeds in three stages verified —
page_rl.py:340-391,page_decoder.py:22-34.- Build a weighted-sum score (behavior score) from the Phoenix head probabilities.
- Cut the top 48 at most into the candidate pool (
max_steps=48). - The page decoder picks one at a time, starting from the first slot (autoregressive decoding). Serving fills 12 slots (
serve_steps=12).
The logit the decoder assigns to a candidate at each step is the sum of three terms verified —
page_decoder.py:85-119, 233-247.- The dot product of the candidate embedding and a state that summarizes the items chosen so far with attention
- The behavior score standardized within the pool (weight 1.0)
- A penalty: a negative weight times whether the author matches an already chosen item and how many levels of the SID (semantic ID: an item represented as a hierarchical code) prefix overlap
The reward is based on per-slot dwell time verified —
page_rl.py:51-59, 100-158.- A slot viewed for 3 seconds or more gets
0.1 × min(dwell seconds, 300) × (1 + min(engagement count, 3)). - If a slot has any of not interested, report, block, mute, or see less, its reward is 0.
- If all slots of the page are impressed and the last slot has a video quality view (VQV), a completion bonus of 1.0 is added.
- A discount rate of γ=0.8 pulls later slot rewards forward to build the return.
rewarded = impressed_mask & (dwell >= config.min_dwell_s) reward = jnp.where(rewarded, dwell_weight * dwell * mult, 0.0).astype(jnp.float32)—
page_rl.py:121-122(code), 2026-10-14- A slot viewed for 3 seconds or more gets
Two critics are used, and the smaller of the two values is taken verified —
page_critic.py:18-25, 121-139, 174-193.- This setup is called a twin critic, a common practice to prevent overestimation.
- The target is TD(λ=0.9), and the loss of pages from exploration traffic gets weight 9.0.
- A continuation head that predicts whether the page continues to the next slot is also trained.
The actor loss has four terms verified —
page_decoder.py:37-48, 495-592,page_rl.py:80-88.- An advantage term based on critic Q values. It targets only candidates within 0.6 of the top behavior score.
- A KL term that keeps the policy from drifting too far from the existing ordering policy. The existing ordering policy is a softmax (τ=0.2) of the behavior score. It sets a target KL of 0.35 and automatically adjusts the coefficient β between 0.1–3.0.
- A penalty term applied when the same author or similar SIDs are placed consecutively (weight 0.5).
- A behavior cloning loss that imitates the logged actual impression order (weight 0.25).
Serving decoding splits into two approaches depending on the temperature value verified —
page_decoder.py:427-477.- If temperature is 0, it builds 4 beams and picks the beam with the largest sum of critic values.
- If temperature is above 0, it explores with Gumbel sampling.
The behavior score computation has its own weights as config defaults, different from the home-mixer mirror verified —
page_rl.py:62-77.- The home-mixer mirror is a file that transcribes by cron the production defaults of the home-mixer service, which assembles the For You feed.
- Values such as share 40.0, not_interested −500, and report −1000 differ greatly in magnitude from the home-mixer mirror (share 2.0, not_interested −52.272, report −234).
- Because the mirror has no comment, we cannot tell whether they are serving values inferred.
The switch for using the decoder in serving is off by default, and no code in home-mixer uses the decoder output verified —
inference/model_runner.py:3984.- The switch added to the serving runner is
serve_page_decoder: bool = False.
- The switch added to the serving runner is
However, because the training data already has logged probability fields such as
rl_rerank_probandrl_decode_prob, we infer that probabilistic re-ranking is already running on some traffic and leaving logs inferred.- Log probabilities used for off-policy training (training a different policy from the logs of the served policy) come only from the policy that was actually served.
What we learnedB. Two home-mixer mirror weights, like and not interested, were both raised by exactly 1.1×
- The like and not-interested weights changed in the home-mixer mirror verified —
home-mixer/params/param.rs:320, 414-419.- Like (
FavoriteWeight): 0.6 → 0.66 - Not interested (
NotInterestedWeight): −47.52 → −52.272 - The mirror sync time is
2026-10-13T16:00:30Z.
- Like (
- Both new values are exactly 1.1× the previous values. The
NotInterestedWeightchange from −43.2 to −47.52 in the 09-29 commit (Gen4+31) was also 1.1×. - This appears to be a rollout practice of raising weights by 10% in steps inferred. There is no evidence beyond the same ratio appearing three times.
- The two values in the VM-Ranker mirror did not change verified —
vm-ranker/params.rs:3, 108-113.- favorite stays at 0.5 and not_interested at −47.52.
- The number of weights on which the two mirrors diverge is now 5.
What we learnedC. The Brazil election filter was reduced to 25 runoff-related accounts
The account list the filter references was reduced to 25 accounts related to the runoff verified —
brazil_2026_election_filter.rs:17-74.- The filter is named
Brazil2026ElectionFilter. It removes posts related to accounts on the list from the feed unless the viewer follows that account. - The comment cites an official letter from the Brazilian electoral court (TSE) as the basis.
"Following the TSE’s Ofício GAB-PRES No. 4720/2026 and Despacho 3814449 (SEI proceeding No. 2026.00.000013846-8), on Oct 13, 2026 the list was reduced to the candidates in the Oct 25 runoff." —
brazil_2026_election_filter.rs:17(code comment), 2026-10-14- The filter is named
What we learnedOther changes
- The user-installed-apps feature was turned off in the home ranker base verified —
configs/xrecsys.py:300.- The setting value
enable_user_installed_appswent from True to False. - After turning it off yesterday in two-tower retrieval (a structure that finds candidates by the dot product of a user vector and a post vector), it was turned off in the ranker as well.
- The setting value
- VM-Ranker skips DPP by default for topic requests (topic feeds) verified —
vm-ranker/scoring/mod.rs:85-87.- The default of the new switch
TopicDppEnabledis false.
- The default of the new switch
- It started recording, as a per-request metric, the candidate count of one retrieval channel introduced yesterday verified —
sources/phoenix_source.rs.- The channel is named
ZERO_FAV, and we presume it collects posts with zero likes.
- The channel is named
- We did not read the following three changes, judging them not directly related to feed behavior inferred.
- An abuse-enforcement (account enforcement service) refactor. The diff is about 7,900 lines.
- A hydration cleanup of VF (visibility-filtering, a service that decides per post whether it may be shown to this viewer).
- An FA4 attention kernel change.
Canon update
- services/x.md: Introduced a Gen4+41 section. Updated the favorite and not_interested rows of the weight table and added the reduction to the Brazil election filter entry in the filter section. Linked the training-side substance to the reward head item in open questions and added a deep-dive-needed item. Added the reference sha
17c96bfto the sources section. - topics/feed-diversity.md: Introduced a section "5. A learned slate decoder" in the X case. Added to the DPP section that DPP is skipped for topic requests, and updated the Who uses it section.
Why it matters This release confirms that the next step exists as training code: generating slates with RL and learning the size of the diversity penalty together with the dwell reward verified. The previous understanding was "X's re-ranking is score sort + author decay + DPP". Because the serving switch is off by default, it does not overturn the existing understanding.
- The reward is dwell time multiplied by an engagement multiplier, not an engagement probability verified. Following the CREAD dwell loss on 10-08 and the retrieval
ldhead on 10-13, the trend of putting dwell time at the center of the objective has extended to the re-ranking stage inferred.- CREAD trains, as a binary classification, whether dwell time exceeded each of several thresholds.
- The purpose of
RewardOutputsandrewardRerankSlotProb, which had appeared only as proto in the 08-19 commit (Gen4+4), was revealed as training code two months later inferred. The evidence is circumstantial: the names and log fields match.
2WeChat said it deployed SID generative retrieval on several search surfaces — Radar
Source WeGR: Unified Generative Retrieval for Industrial Search Systems in WeChat — arXiv, 2026-10-12 v1, paper.
Background Generative retrieval represents an item as a sequence of SID tokens, and a model retrieves candidates by generating those tokens in order. This repository collects production claims of this family in the radar's generative retrieval / semantic ID thread. X also released an SID retrieval service on 10-02. This paper covers WeGR, the generative retrieval used in WeChat's industrial search system.
What we learned
- WeGR combines an SID tokenizer and an RL method verified(abstract).
- The SID tokenizer CoCo-VAE incorporates collaborative signals and prevents codebook collapse (only some codes being used).
- The RL method DHPO solves the problem of sparse reward, which arises because reward is given only on an exact SID match, by widening the reward range per SID layer.
- The abstract reports 2-month online A/B results and states that WeGR was deployed on several search surfaces verified(abstract).
- In WeChat e-commerce search, orders were +2.539%, CTR +1.508%, and conversion rate +1.381%, and CPU and GPU usage were −25.5% and −26.1%.
Canon update Not folded into the canon. Added one line as additional evidence to the generative retrieval / semantic ID thread of radar.md.
Why it matters It is the second SID production claim from WeChat/Tencent, following Tlow (a flow-based item tokenizer). It also adds an RL design axis, "partial reward per SID layer". However, it is a search surface, so it is far from feeds. We did not read the body.
Radar
- WeGR (WeChat, arXiv 2610.16979) combined SID generative retrieval with layer-wise partial-reward RL and reported orders +2.5% in a 2-month A/B. Added to the SID thread of radar.md.
What to check next
- Find the serving path with
serve_page_decoderon and the home-mixer stage that consumes the decoder output — whether it is deployed remains inferred. - Find the behavior policy that produced
rl_rerank_probandrl_decode_prob— we need to check whether it is the same asrewardRerankSlotProbin the 08-19 commit (Gen4+4). - Check whether the 1.1× ratio repeats in the next mirror change — it would give grounds to confirm or discard the inferred that it is a rollout practice.
Sources checked
- X: One commit after 2026-10-14,
17c96bf(2026-10-14 03:41 UTC). There is no release. - Meta: The latest post in the engineering.fb.com RSS is the 2026-10-13 GEM post, and there is nothing new. The latest post on ai.meta.com/blog is from 2026-07.
- Netflix: The latest post in the netflixtechblog.com RSS is from 2026-09-25, and there is nothing new.
- The WebSearch cross-check ("X For You algorithm update October 2026") found no new announcement with a primary source.
- arXiv cs.IR: 30 parsed, 1 passed (WeGR). Two narrowly missed.
- Kwai Summary Attention V2 is from Kuaishou but concerns LLM KV cache compression, so it is unrelated to recommendation.
- HASTE deals with SID hierarchical loss and has only public benchmarks.
- Because it was Thursday, we skipped the industry blog sweep.