0x00 한

Research / Daily reports

  • Sources read: 4
  • Canon files updated: 2 (services/x.md, radar.md)
  • Radar entries: 2
In one lineX opened a general path in its account-action engine that lets scorers request actions directly. A request runs only if it passes both the action kinds fixed in code and a dynamic allowlist.

Other changes reviewed today:

  • In the same X commit, the VM Ranker (a remote service that re-sorts a bundle of candidates) path drops the local diversity computation and now uses the scores the server returns as they are.
  • X's Following feed also filters out posts that quote or retweet an original author who has blocked the viewer.
  • There were no new sources for Meta and Netflix. On arXiv, WeChat's Tlow and TAGR from an anonymous live-ads platform passed the radar.

1Scorers can now request account actions directly — X

Source xai-org/x-algorithm@0d3cdd8 — xai-org public repository, commit of 2026-08-25T23:20:04Z (47 files, +5,850/−586), public source code. These notes number the X commits after the Gen4 release in sequence, and this commit is Gen4+8. The commit message is only the single line "Open-source X Recommendation Algorithm", as is the convention of the generation series, so the commit content was read only from the file diffs.

Background The Gen4 open-source release of the X For You timeline has had follow-up commits at one- to three-day intervals since the first release on 2026-08-13 (47c1bcd, +363,246/−11,640). This commit landed at 08-25 23:20 UTC; yesterday's (08-26) batch missed it, and today's 27th batch caught up. Whereas the previous commit, Gen4+7 (d011592), deepened the safety stack vertically, Gen4+8 touches six areas side by side.

  • Gen4+7 deepened the safety stack in three ways:
    • The VF (visibility filtering, a safety layer that decides whether content can be shown) verification reference_compare
    • The brand-safety tier extension HighRisk
    • PTOS (policy-based violation category verdict) judge, 3 categories
  • The six areas Gen4+8 touched are enforcement, the ranker, Following, Brazil compliance, Phoenix rankall, and Phoenix training infrastructure.
    • Phoenix is a Grok-based Transformer that predicts the engagement probability of each candidate in X For You.
  • By scale (5,850 lines) it is the largest since Gen4+4 (+3,303). However, 3,379 of those lines are the account data update of the Brazil 2026 election filter.
    • It is a release that is wide because new connections went into 6 subsystems side by side, rather than because the code is new.

This commit (0d3cdd8, 2026-08-25, +5,850/−586, 47 files) opened a path for scorers to request account actions directly, and also touched the ranker, Following, the Brazil filter's account list, and the Phoenix index and training infrastructure.

The README heading also changed.

  • ## Latest Updates became ## Notable Updates.
  • Under it, the Brazil item in the August 14th section gained the text *(Account list updated August 25, 2026.)*.
  • We interpret this heading change as meaning that the section will be kept focused on notable changes rather than always kept current inferred. With follow-up commits arriving daily, it declares that the README will not be updated every day.

1-1. A general path for scorers to request account actions directly was added

AES (abuse-enforcement-service) now accepts and runs action requests that scorers attach directly, in addition to static YAML rules. Only requests that pass the action kinds fixed in code and the dynamic allowlist run, and rejected requests are logged with a reason.

Background abuse-enforcement-service/ (AES) is a sub-repo that was fully revealed at the first Gen4 release. AES is a rule engine that takes model scores and maps them to actual account actions.

  • Examples of the model scores it receives are the BDSM (fraudulent-account detection over account behavior sequences) bot head, the LLM slop label, and PandaReports.
  • The account actions are label / bounce_captcha / bounce_arkose / spam_liveness_check / suspend.

Previously, the AES rules were statically encoded in abuse-enforcement-service/service-lib/rules/enforcement_user.yaml and enforcement_post.yaml. The approach states explicitly, as CEL expressions, a mapping of which action to take when a label is attached. For example:

- id: anchor_campaign_suspend_cse
  when: '"anchor_campaign_suspend_cse" in score.labels'
  then: { kind: act_suspend_user, perm: true, policy: "Cse" }

This approach had the limitation that the AES YAML had to be edited every time a new scorer was added. Gen4+8 broke that coupling.

  • If a scorer attaches a list of requests directly, AES runs only those that pass the fixed allowlist.

    • This general passthrough is connected by generic_actions.rs (663 lines, new) and two corresponding YAML rules (act_requested_actions and platform_row_without_requested_actions).
    • The full path of the new file is abuse-enforcement-service/service-lib/src/generic_actions.rs, and all 663 lines are new.
    • The request list a scorer attaches is the requested_actions list.
  • The action kinds a scorer can request are fixed as code constants.

    • Only 5 kinds can be requested for the user entity and 2 for the post entity. A client cannot invent an arbitrary kind string.

    • At most 16 actions can be requested per message.

      pub const USER_KINDS: &[&str] = &[
          "suspend",
          "label",
          "bounce_captcha",
          "bounce_arkose",
          "spam_liveness_check",
      ];
      pub const POST_KINDS: &[&str] = &["post_label", "suspend_author"];
      pub const MAX_REQUESTED_ACTIONS_PER_MESSAGE: usize = 16;
      
  • Requests go through a double fail-closed (reject if a condition is not met) verification. The verification in action_to_spec(entity_type, action, allowlist) has the following five steps:

    1. The request must pass hardcoded_kinds. If it does not, the result is "unknown_kind", and if the kind belongs to a different entity type, it is distinguished as "entity_type_mismatch".
    2. The kind must be in the dynamic GenericActionAllowlist.kinds. If it is not, the result is "kind_not_allowlisted".
    3. For the suspend or suspend_author kind, the policy must be in allowlist.suspend_policies. If it is not, the result is "policy_not_allowlisted".
    4. For the label or post_label kind, all three conditions must be met.
      • action.labels must not be empty ("no_labels").
      • Every label must be in allowlist.labels ("label_not_allowlisted").
      • ttl_msec >= 0 must hold ("invalid_ttl").
    5. Duplicates are removed. If the same spec is already in the list, the result is "duplicate_action".
  • Rejected actions are not simply discarded but observed.

    • Rejected actions are collected into a SkippedRequestedAction { kind, head, reason, count } struct and attached as JSON to outcome.info["requested_actions_skipped"].
    • They are also aggregated in a separate metric, GENERIC_ACTION_TOTAL{entity_type, kind, outcome=resolved|skipped, reason}.
    • In other words, the reason a request failed to pass is left in the log as is. The scorer team can immediately see why its request was rejected.

Two YAML rules were added as a pair to enforcement_user.yaml.

- id: platform_row_without_requested_actions
  when: '"abuse_platform_requested_actions" in score.labels && size(score.requested_actions) == 0'
  then:
    kind: skip
    reason: platform_row_without_requested_actions

- id: act_requested_actions
  when: "size(score.requested_actions) > 0"
  then:
    kind: act_requested_actions
  • If a scorer has declared the general action pipeline with its own label (abuse_platform_requested_actions) but the actual action list is empty, the request is skipped.
  • If there is at least one action, it is routed to the verification pipeline above through the act_requested_actions decision.
  • enforcement_post.yaml gained only one symmetric rule; the post side has no platform_row skip rule.

The AES decision also gained a new variant that handles the request list.

  • A new Decision::ActRequestedActions variant was added to abuse-enforcement-service/service-lib/src/lib.rs (+276/−19).

  • When run_enforcement_inner meets this variant, it handles it as follows:

    let (decision, mut requested_actions_skipped) = match decision {
        Decision::ActRequestedActions => expand_requested_actions_decision(
            facts.entity_type,
            &facts.score,
            &ctx.dynamic_config.generic_action_allowlist(facts.entity_type),
        ),
        Decision::Skip(reason) => (ExpandedDecision::Skip(reason), None),
        Decision::Act(specs) => (ExpandedDecision::Act(specs), None),
    };
    
  • If no action passes the allowlist, the result is Skip(REQUESTED_ACTIONS_DENIED), and if at least one does, it is Act(specs).

  • In other words, even when all requests are rejected, the outcome is explicitly skip, so what was requested and why it was rejected remain in the JSON in outcome.info.

A path from dynamic_config to generic_action_allowlist was also added.

  • A new method was added to growthbook.rs (+126).
  • GrowthBook appears to be X's dynamic config and feature-flag system inferred.
    • If so, the allowlist, that is, which kinds a scorer may request and which policies and labels it may use, can be gated by A/B at runtime.
    • When attaching a new scorer, allowlist entries can be switched on and off in the GrowthBook console without deploying code.

The first client of this structure, panda_reports_embedding_v10_rough_spam, came in with it. A new rule was added to enforcement_user.yaml.

- id: panda_reports_embedding_v10_rough_spam
  when: '"panda_reports_embedding_v10_rough_spam" in score.labels'
  then: { kind: act_suspend_user, perm: false, policy: "PlatformManipulation" }
  • This rule itself is a static mapping in the old style. However, the label name itself carries new information.
    • panda appears to be the name of X's internal spam detection system inferred.
    • reports_embedding_v10 is the 10th version of a detector based on report embeddings.
    • rough_spam is a verdict that the account is likely spam, though with low confidence.
  • The action is a temporary (perm: false) suspend with the PlatformManipulation policy.
  • In other words, this detector is embedding-based, and its version has reached v10. It can be seen as a continually retrained pipeline.

Canon update Three places in services/x.md were edited.

  1. Added a Gen4+8 row to the Gen4 table.
  2. Expanded the one-line summary paragraph to describe the Gen4+8 commit.
  3. Added a subsection "Gen4+8 (2026-08-25) — AES generic_actions passthrough wiring" after the BDSM section.

Why it matters The meaning of this change is summarized at the end of 1-7, together with the three axes of the whole Gen4+8 release.

1-2. VM Ranker drops local computation and uses the scores the server returns as they are

In the VM Ranker path, the local computation layer that home-mixer (the service that serves X home timeline feed requests such as For You and Following) used to run is gone. Now home-mixer uses the scores returned by the rank server as they are, and diversity is handled by the server-side DPP (a diversity re-ranking technique).

Background VMRanker is a remote gRPC service that acts as the slate reranker in home-mixer. It performs DPP (Determinantal Point Process)-based diversity re-ranking over the candidate scores that Phoenix produced, with parameters θ=0.65, K=150. Until now, home-mixer/scorers/vm_ranker.rs supported two value models.

  • For author_diversity, home-mixer computed locally a value that applies author-diversity decay based on the MPN fold-back and passed it to the rank server.
  • For default, the score returned by the rank server was used as it was.
  • The 7 SID field connections of Gen4+3 (2026-08-18) were attached to this vm_ranker. SID (semantic ID) represents an item as a sequence of discrete token IDs.

Gen4+8 greatly simplified this path. It removed the 88 lines of ranking_scorer::effective_head_weights and the 128 lines of MPN fold-back.

  • The author-diversity value model and the MPN fold-back logic were deleted from the VM Ranker scorer (home-mixer/scorers/vm_ranker.rs, +11/−128).

    • The deleted code:

      // Deleted:
      const AUTHOR_DIVERSITY_VALUE_MODEL_ID: &str = "author_diversity";
      const MPN_FOLD_MULTIPLIER_MAX: f64 = 10.0;
      
      pub struct VMRanker {
          pub client: Arc<dyn VMRankerClient>,
          pub xds_client: Option<Arc<dyn VMRankerClient>>,
          pub author_cold_start: AuthorColdStart,  // deleted
      }
      
      // entire MPN fold-back logic inside score() deleted:
      let fold_weights = (query.params.get(EnableMpnScoring)
          && query.params.get(VMRankerValueModelId) == AUTHOR_DIVERSITY_VALUE_MODEL_ID)
          .then(|| ScoringWeights::from_params(&query.params));
      // ...computes MpnParts.pos/neg × (returned/sent).clamp(0, MPN_FOLD_MULTIPLIER_MAX)
      // ...post-processing with AuthorColdStart.apply
      
  • The only newly added constant is const DPP_VALUE_MODEL_ID: &str = "dpp";. That is, one value model ID (author_diversity) was deleted and replaced with another (dpp).

  • The new score() passes the score returned by VM Ranker straight through and does not recompute it locally. Both the MPN fold-back and the AuthorColdStart post-processing are gone.

    candidates.iter().map(|c| Ok(PostCandidate {
        score: score_map.get(&c.tweet_id).copied().or(c.score),
        ..Default::default()
    })).collect()
    
  • The 88-line method that combined weights for each candidate and sent them to VMRanker was also deleted (home-mixer/scorers/ranking_scorer.rs, +28/−201).

    • The deleted method is ScoringWeights::effective_head_weights.
    • This method was logic that built an xai_vm_ranker_proto::HeadWeights protobuf for each candidate and sent it to VMRanker.
    • It combined weights per candidate, for example the post_unexplored multiplier computation, the low-fav-rate penalty on click_dwell_time, the quoted_vqv duration check, and the per-candidate adjustment of the reply weight, and all of it is now gone.

This simplification has four implications:

  • Diversity computation moved from the client, home-mixer, to the server, VMRanker.
    • Previously, home-mixer built head weights carrying the diversity requirements for each candidate and sent them to the rank server.
    • Now the rank server handles diversity with its own DPP logic, and home-mixer only consumes the returned scores.
  • What the rename from author_diversity to dpp actually amounts to is still unclear.
  • AuthorColdStart did not disappear; it changed place.
    • The file home-mixer/scorers/author_cold_start.rs still exists and was modified by +12/−9.
    • Because it was removed only from the VMRanker post-processing, it may still be applied at other points such as RankingScorer or the Phoenix pipeline.
  • The values the deleted effective_head_weights computed now appear to be computed by the server with its own logic, or the concept of head weights itself appears to have been replaced in another way.
    • The head weights this method computed are favorite, reply, retweet, share, dwell, quoted_vqv, and so on.
    • It is more natural to interpret that VMRanker consumes the original phoenix score as it is and applies only its own DPP inferred.

This simplification extends the main direction of Gen4, that is, the trend of stripping local computation and caches from home-mixer and preferring served outputs. It pairs with how the UseServedSlateContext gate of Gen4+5 moved slate context computation from local to Phoenix serving.

"AUTHOR_DIVERSITY_VALUE_MODEL_ID: &str = "author_diversity"" ← deleted "DPP_VALUE_MODEL_ID: &str = "dpp"" ← new — home-mixer/scorers/vm_ranker.rs

Canon update Three places in services/x.md were edited.

  1. Reflected the value model rename and the deletion of effective_head_weights in the VMRanker description of the ranking section.
  2. Reflected in the diversity section that DPP became the only value model of VMRanker.
  3. Recorded the parameter −29 lines (cleanup of MPN and author_diversity constants) in the parameter change practice.

1-3. The Following feed also follows blocks by quoted and retweeted original authors

The Following feed extends its block-relationship check to quoted authors and retweeted authors. If the original author has blocked the viewer, the viewer does not see the post even when someone the viewer follows quotes or retweets it.

Background The Following surface is a reverse-chron pipeline that shows only the latest in-network posts. Since Following got its own VF hydrator branch in Gen4+3, this pipeline has kept being refined. This time, work was added to extend block-relationship handling to quoted authors and retweeted authors.

  • The new hydrator (a stage that fills in fields on each candidate), FollowingBlockedByHydrator, asks SocialGraphClient which of the quoted author and the retweeted author is blocking the viewer.

    • The file is home-mixer/candidate_hydrators/following_blocked_by_hydrator.rs (65 lines, new).

    • For each candidate, it collects the user_id lists of the quoted author and the retweeted author and asks in one call.

      let user_ids: Vec<u64> = candidates
          .iter()
          .flat_map(|c| c.quoted_user_id.into_iter().chain(c.retweeted_user_id))
          .collect();
      
      let blocked_by_user_ids = self.socialgraph_client
          .check_blocked_by(query.user_id, &user_ids)
          .await?;
      
    • The result is set on two candidate fields. author_blocks_viewer is true if the retweeted author blocks the viewer. quoted_author_blocks_viewer is true if the quoted author blocks the viewer.

  • A new condition was wired into AuthorSocialgraphFilter, a filter already in Gen4, and it now removes the candidate if any of 6 conditions is true.

    • The filter file is home-mixer/filters/author_socialgraph_filter.rs.

    • Previously, it checked only block and mute from the viewer toward the author. Now it expands to six branches, including the direction from author to viewer and the original authors of quote and retweet chains.

      if muted                          // viewer mutes the author
          || blocked                    // viewer blocks the author
          || author_blocks_viewer       // author (= retweeted author) blocks the viewer
          || quoted_author_blocks_viewer  // quoted author blocks the viewer
          || viewer_blocks_quoted_author  // viewer blocks the quoted author
          || viewer_blocks_retweeted_user  // viewer blocks the retweeted author
      {
          removed.push(candidate);
      } else {
          kept.push(candidate);
      }
      
  • The two stages were wired into the reverse-chron pipeline, and the filter was placed before the VF filter (home-mixer/candidate_pipeline/reverse_chron_posts_pipeline.rs, +27/−2).

    let post_selection_hydrators = vec![
        Box::new(FollowingBlockedByHydrator::new(socialgraph_client).await),  // new
        Box::new(VFFollowingCandidateHydrator::new(...)),
        // ...
    ];
    let post_selection_filters = vec![
        Box::new(AuthorSocialgraphFilter),  // new
        Box::new(VFFilter),
        Box::new(AncillaryVFFilter),
    ];
    
    • AuthorSocialgraphFilter sits before the VF filter. That is, candidates filtered out by block or mute skip the VF verdict lookup itself, so performance also improves.
    • SocialGraphClient is a client in the XAI candidate_pipeline component_library. It connects to flock over TLS S2S, and the service itself is not public.

This change has three implications:

  • The meaning of a block has widened transitively.
    • Previously it was "if you do not follow A, A's posts are not shown to you", but now it extends to "even if you follow A, if A retweeted original author B and B has blocked you, the post is not shown".
    • B's block of you is respected regardless of the following relationship.
    • It is a broad-scope policy decision, and we interpret it as a signal that X has started to explicitly block bypass exposure through quotes and retweets inferred.
  • On performance, one more remote lookup to SocialGraphClient is added per request.
    • However, because it is a batch lookup that asks check_blocked_by for the quoted and retweeted user_ids of all candidates at once, the cost grows sub-linearly with the number of candidates rather than being fixed.
  • This hydrator is wired only into Following.
    • The hydrator list of the For You (algorithmic) pipeline does not yet include this hydrator.
    • If the wiring is symmetric, it may be attached to For You in the next commit inferred.

Canon update Two places in services/x.md were edited.

  1. Added a block-extension subsection to the Following surface description.
  2. Updated the AuthorSocialgraphFilter detail in the 21-filter table. It is a filter that already existed, but the update reflects that its meaning was extended.

1-4. The Brazil election filter's account list grew substantially from the TSE source data

The account list of the Brazil 2026 election filter gained +3,379 lines based on public data from the Brazilian electoral authority. The filter's behavior itself did not change.

The filter logic is unchanged from its introduction in Gen4+1 and works in three steps.

  1. It hardcodes the list of reported accounts from dadosabertos.tse.jus.br.
  2. It removes posts from these accounts in the For You pipeline.
  3. It makes an exception for accounts the viewer explicitly follows.

This is a measure to comply with Art. 28 § 1º-A of Electoral Resolution 23.610.

The way the list is included reflects a transparency practice.

// User ids below are obfuscated; usernames are included for transparency.

// @OmarAzizSenador deleted his account at the time this code was written.
// @_ANDREDOPRADO no live account was found.
// @_EDUARDOMANTOAN no live account was found.
// @ADALBERTO_1111 no live account was found.
...
  • The user_id is obfuscated so the internal X ID is not exposed, while the @username stays in the code as is.
  • Next to each account there is even a status comment such as "deleted his account" or "no live account was found".
  • As a compromise between open source and user privacy (preventing leaks of internal user_id), it keeps verifiability while hiding X's internal user_id mapping.
  • The scale appears to be much larger than the 665 accounts in Gen4+1 inferred.
    • The exact number of accounts has to be computed separately by counting diff lines. If each account takes 2–4 lines in a 4947-line file, the scale is roughly 1200–2000 accounts inferred.

Canon update Updated the Brazil2026ElectionFilter entry in services/x.md to state explicitly that the account list is updated on a regular basis.

1-5. The Phoenix index also loads data from before the minimum-age condition is met

For each window that has a minimum age since posting, Phoenix's offline indexing pipeline now also loads data that has not yet met that condition, as a separate snapshot. This change went into the base repository of the Phoenix rankall pipeline.

Background phoenix-rankall/ is Phoenix's offline indexing and aggregation pipeline. It maintains the candidate pool split into several windows, for example 1fav_uec_1day, video_14day, and evergreen_video_1825day. Gen4+8 continued the flow of the two changes below and expanded the base repository of phoenix-rankall itself.

The change consists of new constants and loading logic in phoenix-rankall/src/store/base.rs (+202/−61).

const PREFLOOR_SLACK_SECS: f64 = 6.0 * 3600.0;

// if the window config has min_age:
if wc.min_age.is_some() {
    let pf_name = format!("prefloor_{window_name}");
    let pf_link = self.config.output_dir.join(format!("{pf_name}.parquet"));
    let pf_path = if pf_link.exists() {
        Some(pf_link)
    } else {
        find_latest_versioned_file(&self.config.output_dir, &pf_name)
    };
    // load batches from pf_path...
}
  • If a window has a min_age condition, the data from before min_age that has not yet passed the condition is kept in a separate prefloor_<window>.parquet file and loaded together.
    • An example of a min_age condition is "this pool includes only items at least N hours past posting".
  • PREFLOOR_SLACK_SECS = 6 hours is the slack time during which prefloor data is kept until it crosses the min_age threshold.

Canon update Added the subsection "Gen4+8 (2026-08-25) — rankall prefloor snapshot wiring" to the Phoenix training and index section of services/x.md.

Why it matters This change continues the flow of Gen4+2 removing the favoriteCount>=1 gate in phoenix-rankall-strato. Previously a candidate had to pass the condition to enter the index, but now rankall keeps candidates that have not yet passed in a separate pool so they can reach production immediately when they pass. This is an improvement for cold start and freshness, and it is likely to reduce index latency for new posts inferred.

1-6. The Phoenix download client now actually respects its concurrency cap

An issue was fixed where the actual number of concurrent downloads could exceed the configured cap when Phoenix serving downloads embedding tables and checkpoints. 2 new regression tests were also added.

  • copy_port is the client that downloads embedding tables and checkpoints from object storage (S3/xai-o2) in Phoenix serving.

  • The previous code ran several downloads in parallel with join_all(futures).await.

    • However, when join_all polls the futures sequentially inside a rate limit batch, the actual in-flight concurrency could exceed max_concurrent.
  • After the fix, each future is wrapped in a separate task with tokio::task::spawn. This tokio::spawn hardening fixes the rate limit so it respects the in-flight cap without parallel polling.

    // Before:
    let batch_results = join_all(batch).await;
    
    // After:
    let batch_results = join_all(batch.into_iter().map(tokio::task::spawn))
        .await
        .into_iter()
        .collect::<Result<Vec<_>, _>>()
        .map_err(|e| CopyPortError::Other(format!("copy_port download task join: {e}")))?;
    
    • Wrapped this way, the runtime scheduler actually runs them in parallel.
    • The rate limit logic (join_rate_limited) decides precisely when to issue the next batch based on the in-flight count.
  • The two new regression tests check the following.

    • rate_limit_caps_in_flight_despite_spawn checks whether peak in-flight is exactly 2 when a concurrency=2 cap is applied to 6 downloads.
    • rate_limit_paces_between_spawned_batches checks whether pacing between batches is maintained.

Why it matters This change is hardening that fixes the accuracy of parallel download throttling at serving time, and it pairs with Gen4+7's multi-node hardening of the Phoenix checkpoint loader, which fixed an OOM in the restore path. Both are an extension of the maturation cycle of training and serving infrastructure that followed Muon and GB300 training being formally included in the export in Gen4+6. The fact that such stability fixes attach to commits every day is itself evidence that X keeps devoting organizational resources to keeping the Gen4 open-source release verifiable and trustworthy in production.

1-7. 4 minor changes in grox, engagement counts, and URT, and other cleanups

The rest are small cleanups and extensions.

What we learnedOther changes

Why it matters Across the whole Gen4+8 release there are three axes.

  1. Enforcement practice became more flexible.
    • In addition to hardcoded YAML rules, AES also supports a general action pipeline that scorers request directly. The deployment cycle for attaching a new scorer got shorter.
    • The infrastructure for attaching embedding-based spam detectors such as panda_reports_embedding_v10_rough_spam, which are continually retrained, has settled in.
  2. The ranker path became much simpler.
    • The local computation layer of VMRanker was removed and delegated to the server-side DPP.
    • This is an architecture refactor paired with the Gen4+5 slate context migration; home-mixer plays only the role of a thin aggregator, and the gRPC servers handle the computation.
  3. The policy of the Following surface widened.
    • It also respects block relationships of authors in quote and retweet chains. It explicitly closes the block bypass via quotes.

The overall flow of Gen4 still traces a maturation curve of code release, verification infrastructure hookup, experiment tracking, architecture cleanup, and policy expansion. The fact that commits at intervals of at most three days continued for 12 days through Gen4+8 (08-25) is itself evidence that X maintains this open-source release as a sustained code mirror relationship rather than a marketing event.

↑ Contents

2Tlow raised production CTR with a flow-based tokenizer — WeChat

Source Tlow: Flow-based Item Tokenizer for Recommendation — arXiv 2608.24176, 2026-08-25 v1, paper. There are 6 authors (Nian Li, Chonggang Song, Jingtao Ding, Lingling Yi, Yong Li, Qingmin Liao). The HTML version of the abstract states a production A/B at China's largest social media platform WeChat, so we confirmed the affiliation.

Background The item tokenizer, a core component of the Semantic ID (SID) line, is the module that converts each item's semantic embedding into a sequence of discrete token IDs. The de facto standard is RQ-VAE (Residual-Quantized VAE). After Google's 2023 TIGER paper, several production systems adopted it, including Netflix Foundation Model and Kuaishou PushDualGen. However, RQ-VAE has three known problems.

  • Codebook collapse occurs, so most code slots die and only a few are used.
  • Quantization error accumulates in the residual, so the error grows in deep quantization layers.
  • Because of discontinuity, similar items map to completely different token sequences, which makes training difficult.

A flow-based model transforms the embedding space into a learnable distribution with an invertible neural network and inverts it back. This paper (Tlow) approaches the problems above with a normalizing flow, and the authors claim that flow-based tokenization is better than RQ-VAE on two axes: codebook utilization and semantic locality.

What we learnedA. In the production A/B, the CTR gain was larger for new items

  • In the production A/B, global CTR rose +10.32% and new-item CTR rose +11.64% verified.

    "The retrieval model based on token IDs improves user CTR by 10.32% globally and by 11.64% for new items." — Tlow abstract, 2026-08-25

    • A larger gain on new items suggests it is especially strong at cold start verified — same abstract.
    • The key benefit of the semantic tokenization line, namely obtaining meaningful representations even for cold items, was confirmed in production metrics verified — same abstract.

What we learnedB. The evaluation surface is the WeChat retrieval model, and the detailed surface is not public

  • The evaluation surface is the WeChat retrieval model verified.
  • The abstract does not disclose whether it is ads or organic content, or which detailed surface among Look/Video Channels/Moments verified.

What we learnedC. The author affiliation was confirmed as the Tencent WeChat rec group

  • There is a Tencent-related author name and the abstract states WeChat as China's largest social platform, so we confirmed it as the Tencent WeChat rec group.
    • The Tencent-related author name is Chonggang Song.

Canon update Added the section ### Tlow (WeChat/Tencent) — A flow-based item tokenizer as an RQ-VAE alternative, CTR +10.32% in production to "new this month" in radar.md. It is placed above HEGM and links to the SID thread.

Why it matters

  • It is a new axis for the SID/generative retrieval thread: the tokenizer architecture itself has begun to diverge in production.
    • Until now the SID line has mostly combined RQ-VAE with a downstream model.
    • Tlow is the first statement that replacing the tokenizer layer with a flow-based one still yields effective metric gains in production.
    • It is circumstantial evidence that RQ-VAE's codebook collapse was a real problem in serving inferred, and we interpret it as Tencent having hit this problem and offering an alternative.
  • It is Tencent WeChat's first production claim in a while.
    • WeChat rec has been quiet in recent years.
    • With Tlow, this appears to be a signal that real architecture statements for the organic content surface are resuming.
    • It is worth watching whether a paper on the rec stack of Weixin Video Channels (WeChat's short-video surface) follows.
  • There are two checkpoints to watch.
    • Watch whether code and the detailed block-wise flow structure appear in follow-up material.
    • If a second company such as Kuaishou, ByteDance, or Xiaohongshu states a similar tokenizer alternative, it becomes a topics/ promotion candidate.

↑ Contents

3TAGR raised revenue by +16.1% in live-commerce ads — anonymous platform

Source TAGR: Temporally Adaptive Generative Recommendation for Industrial Live-Streaming Advertising — arXiv 2608.24034, 2026-08-25 v1, paper. There are 10 authors (Wencai Ye, Guangyi Liu, Chaoyi Wang, Wenbin Luo, Shengyu Wang, and others). The author affiliation and platform name are not stated in the abstract. The abstract says only "a large-scale e-commerce live-stream advertising platform".

Background Live-streaming ads place strong freshness requirements on the recommender, because content, products, and user feedback change in real time. So far the generative recommender (SID-based) line has mostly assumed a static catalog. In live streaming, the time scale at which streams open and close is in minutes, so a static token vocab stays valid only briefly. This paper (TAGR) presents generative recommendation tailored to rapidly changing live content, products, and user feedback.

What we learnedA. In the production A/B, entry rate, cart click rate, and revenue all rose

  • The production A/B results are as follows verified.
    • live-room entry rate +8.5%
    • shopping-cart click rate +7.4%
    • revenue +16.1% over production baseline

What we learnedB. The abstract does not give the concrete mechanism for adapting to the time axis

  • The architecture is Temporally Adaptive Generative Recommendation.
    • The abstract describes it as "designed for rapidly changing live content, promoted products, and user feedback".
  • Concrete time-axis adaptation mechanisms such as the tokenizer retraining cycle or online updates do not appear in the abstract. The body text needs to be checked, but we skipped it in this batch.

What we learnedC. The platform cannot be confirmed from author names alone

  • The leading candidates for Chinese e-commerce live-streaming are Kuaishou (Kwai), Alibaba (Taobao Live), Douyin/ByteDance (Douyin E-commerce), and Xiaohongshu, but the author names do not directly match any of these companies inferred.

Canon update Added the section ### TAGR — Anonymous large e-commerce live-stream ads platform, revenue +16.1% to "new this month" in radar.md.

Why it matters

  • A third company joined the live-streaming ranking thread.
  • Generative recommenders are accumulating production claims in fast-changing domains such as ads and live streaming.
    • Previously many claims were based on static short-video or e-commerce catalogs. This one comes from a domain that needs time-axis adaptation.
  • Not being able to confirm the platform is the biggest weakness.
    • If the affiliation is released after v2 or the author email domain can be confirmed, we will reconsider the canon promotion.

↑ Contents

Corrections

None. The new sources in this batch (X Gen4+8, Tlow, TAGR) do not overturn the existing canon.

  • The VM Ranker simplification (Gen4+8) fits the architecture cleanup flow of Gen4.
  • The Following block expansion widens the policy direction, and the Brazil account update maintains the existing compliance practice.
  • Tlow and TAGR attach as new data points to their respective watch threads (SID/generative retrieval, live-stream).

↑ Contents

Radar

  • 2 new:
    • Tlow (Tencent WeChat, arXiv 2608.24176): flow-based item tokenizer, production CTR +10.32%
    • TAGR (anonymous e-commerce live-stream, arXiv 2608.24034): temporally adaptive generative recommendation, revenue +16.1%

Of 30 arXiv cs.IR triage items, 2 passed. The ones that did not pass were mostly offline-benchmark-centered and had no industry provenance. 4 of the failed candidates drew attention.

  • Native Multimodal for CTR: presumably Alibaba, but we could not confirm a production claim.
  • RecGPT-Mobile-V2: Alibaba on-device query prediction. The earlier V1 was not tracked in the canon.
  • WeMM-Embedding: a Tencent WeChat multimodal embedding technical report. It has no retrieval production claim.
  • RetrievalFormer: an index that unifies search and rec with a dual-encoder. The production scale is unclear.

↑ Contents

What to check next

↑ Contents