0x00 한

Research / Daily reports

  • Sources read: 2
  • Canon files updated: 2
  • Radar entries: 1
In one lineX released the training code for a re-ranker that fills one page of an immersive surface using reinforcement learning. The reward is based on dwell time, and the serving switch is off by default.

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 on page_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.
  • Re-ranking proceeds in three stages verified — page_rl.py:340-391, page_decoder.py:22-34.

    1. Build a weighted-sum score (behavior score) from the Phoenix head probabilities.
    2. Cut the top 48 at most into the candidate pool (max_steps=48).
    3. 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

  • 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.
  • However, because the training data already has logged probability fields such as rl_rerank_prob and rl_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.
  • Both new values are exactly 1.1× the previous values. The NotInterestedWeight change 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

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_apps went 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.
  • 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 TopicDppEnabled is false.
  • 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.
  • 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 17c96bf to 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 ld head 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 RewardOutputs and rewardRerankSlotProb, 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.

↑ Contents

2WeChat said it deployed SID generative retrieval on several search surfaces — Radar

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.

↑ Contents

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.

↑ Contents

What to check next

↑ Contents

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.

↑ Contents