starl3xx.fun / algo / 008

Issue № 008 (commit 862a123)

A like weighted a third heavier, a video open cut to under a third of its weight, more credit for time spent on a post, a heavier “not interested”, Brazil’s election list cut to 25 runoff accounts, and an evidence floor for automated enforcement

X Algo Watch

Every Sunday I diff the open-source X ranking code, xai-org/x-algorithm, against last week’s mirror and write down what actually moved. This issue covers cb45b55 to 862a123, which is 5 commits, dated 13 October, 14 October, 15 October, 16 October, 17 October.

Everything below is a default in the code, not a claim about production. The repo’s own README says the two can differ. Every number is copied from the diff; where I’m inferring what a change means for posting, I say so.

If you change one thing this week

  • Keep writing for the reply, but stop quoting forty to one. A like went from 0.5 to 0.66, so a reply now weighs about 7.6 times a like, not ten, and a share via copy link about 30 times, not 40.
  • Make the post worth staying on, not only worth a tap. The weight on predicted dwell time went from 0.004 to 0.006, and a video open from 0.07 to 0.02.

Everything below is the evidence for those two, plus what else moved.

What moved

FavoriteWeight0.5 → 0.66
VideoOpenWeight0.07 → 0.02
ContDwellTimeWeight0.004 → 0.006
NotInterestedWeight-47.52 → -52.272

1. A like weighs a third more, and every other action weighs less against it. In param.rs, FavoriteWeight went from 0.5 to 0.66, in two steps: to 0.6 on 13 October, then to 0.66 a day later, in the same commit that made “not interested” exactly a tenth heavier. It is the first of the nine weights on the /algo ladder to move since this series started reading the code. A post’s score is a plain sum of each predicted action times its weight (compute_weighted_score in scoring.rs), and a positive sum is used as it stands, so the like’s term grows by about a third and every other term stays where it was. Against a like, a share via copy link at 20.0 falls from forty times to about 30, and a reply or a quote at 5.0 from ten times to about 7.6. The ranking service’s own copy in params.rs still says 0.5, and it did not take any of this week’s four moves, so the two copies now disagree on five defaults. Home-mixer’s copy is the one in the score it sends with each post, and the one it serves itself when the call to the service fails, in vm_ranker.rs. The service recomputes from its own copy only once it has loaded its config, which its open-source startup flag leaves off, and both copies read the same switch, rust_home_mixer_favorite_weight, so a value set in that config would override both. The header of param.rs says the file is mirrored from the config’s feature-switch defaults, last synced on 16 October; the service’s file carries no such line. Expect to read “likes matter more now.” A like’s weight did rise, and it is still the lightest of the nine actions on the ladder: the gap narrowed by about a quarter, it did not close. Takeaway write for the same actions as last week; a reply still carries more than seven times a like’s weight, so a post that only collects likes gained a little and one that starts a conversation still wins

2. A video open loses most of its weight, and time spent on a post gains half. In param.rs, VideoOpenWeight went from 0.07 to 0.02, under the 0.05 it held before issue 001 reported it rising. ContDwellTimeWeight went from 0.004 to 0.006. It multiplies Phoenix’s predicted dwell time on the post, a length of time rather than a probability (apply(scores.dwell_time, weights.cont_dwell_time) in scoring.rs), so it does not compare with a like the way the ladder does. The yes-or-no dwell weight, DwellWeight 0.05, did not move. Both copies also gained ReactWithVideoWeight at 0.0, a weight on a new Phoenix prediction, react_with_video_score, that adds nothing at that default. Expect to read “X is burying video.” Nothing in this range filters or demotes a post for carrying video: what moved is what the tap that opens one is worth. Takeaway make the opening worth staying for; a thumbnail that earns the tap and then loses the viewer earns less than at any point this series has read

3. “Not interested” weighs a tenth more, again. In param.rs, NotInterestedWeight went from -47.52 to -52.272 on 14 October, exactly a tenth heavier, the same step issue 006 reported. It multiplies the predicted chance that this viewer marks the post “not interested”. The service’s copy still says -47.52. Because the like rose faster, the penalty is lighter against a like than a week ago: about 79 times a like, down from 95. Takeaway a post that reads as bait to people outside its audience costs a little more than last week, so aim the hook at your followers rather than at everyone

4. Brazil’s election filter shrinks from 2,795 accounts to 25. In brazil_2026_election_filter.rs the test that counts the listed accounts went from 2795 to 25. That is the list issue 005 and issue 006 watched grow by ten and then nine. A new comment in the file says that on 13 October, following an order from Brazil’s electoral court, the list was reduced to the candidates in the 25 October runoff, and the repo’s README.md now dates the list 13 October. A new test names four accounts that were filtered before and no longer are. The rule itself did not change: a post leaves For You when its author, the account it reposts, the account it quotes, or an account earlier in its reply chain is on the list, unless the viewer follows that listed account, and nothing in the filter checks where the viewer is. Takeaway quoting or replying under a first-round candidate who is not in the runoff no longer takes your post out of For You; under one of the 25 it still does, for every viewer who doesn’t follow that account

5. Automated enforcement can be made to show its evidence before it acts. abuse-enforcement-service reads model scores about an account and labels it or its posts, challenges it, or suspends it. In this range it gained a control layer, in action_control.rs. For each model and classifier it can leave the existing rules in charge, record what would have happened without acting, act, or act by confidence level (ControlMode in action_control.rs). In the last mode a score arrives marked low, mid or high, and the level has to be backed by a human review of that model’s hits: a precision floor of 0.70, 0.85 or 0.95, a review no more than 30 days old (DEFAULT_EVIDENCE_MAX_AGE_DAYS in confidence.rs), and enough reviewed cases to pass a binomial test at 0.05. A field the code calls humans is subtracted from the reviewed cases before that test, so it counts the hits the model got wrong. Per the file’s tests, 59 reviews with none of those certify high, and 9 certify only low. Without that backing the action is recorded with the reason weak_evidence and not taken. A named person can override missing evidence for at most seven days, and off_switch.rs turns enforcement off for a whole model or for one of its classifiers, with an optional time to turn it back on. Which models run in which mode is set in config the repo does not include. Expect to read “X can now suspend you on a model’s say-so.” The service could already do that; what this adds is a way to make a model prove itself on reviewed cases first, and a way to stop it. Takeaway nothing here moves a post’s score; it gives X a way to demand a reviewed sample before a model’s label or suspension lands, and whether X uses it is not in the repo

Also in this range, and not worth an item each. EnableAdsAuthorBrandSafetyFallback went from false to true: when a post has no brand-safety label of its own, home-mixer now asks for its author’s, and treats a missing record or a failed lookup as not safe for ads (ads_brand_safety_vf_hydrator.rs). Only the ad blenders read that verdict, to choose which posts an ad may sit beside; ranking does not. Phoenix retrieval can now mark a candidate as coming from a pool of posts with no likes (ForYouPhoenixRetrievalZeroFav in phoenix_source.rs), and a new filter, zero_fav_codivert_filter.rs, would drop posts found only that way for viewers in an experiment unless their author is in its treatment arm; all three of its switches are false. EnablePostEngagers false would send Phoenix, with each candidate, up to 32 accounts that engaged with it positively and 8 negatively, with what each did and how long ago (post_engagers.rs); its hydrator also runs on requests marked as shadow traffic. PhoenixOonRepliesRootOnly false would narrow the out-of-network replies from issue 006, which are still off, to direct replies to a thread’s first post (oon_retweet_reply_filter.rs). The vertical-video carousel from issue 007, still off, gained de-duplication by author, by semantic ID and by embedding similarity at 0.72 (video_carousel.rs), its own scorer (immersive_video_scorer.rs), and now gives way to a who-to-follow module (blender_selector.rs). A request that asks for no videos now also drops quotes of a video (video_filter.rs) and replies whose thread holds one (ancestor_video_filter.rs). Where the service runs its DPP step, which drops candidates too alike to ones above them, it now skips topic feeds once its config is loaded, under TopicDppEnabled false (mod.rs). The visibility filter’s rules were rebuilt as specs run by a new engine (engine.rs), with an explainer that traces which rule produced a verdict (explain.rs); this issue did not compare the old and new rules one by one. Phoenix gained training code for a model that plans a whole page of posts at once (page_rl.py), and a second version of a reply model whose inputs include whether the post’s author liked or replied to the reply, and the reply author’s follower count and verified status (reply_features.py). The repo does not show either one serving For You, and a model reading an input is not the same as the code rewarding it.

The standing numbers

For anyone new here, the ladder moved for the first time this week, at its bottom rung. From param.rs, each one against a like; the service’s params.rs declares the same values for the rest and still 0.5 for the like:

  • share via copy link: 20.0, about thirty times a like
  • reply between two accounts that follow each other: 5.0 plus a 15.0 boost, also about thirty times
  • reply or quote: 5.0, about seven and a half times
  • like: 0.66, the unit

Nothing older than 48 hours enters the For You feed at all: MAX_POST_AGE in config.rs is 48 * 60 * 60 seconds. A reply or a repost from an account a viewer doesn’t follow is dropped outright by oon_retweet_reply_filter.rs at its default, so replies earn their weight from your existing followers rather than from new reach. A quote carries the same weight and does travel out of network. And where the ranking service applies them, two multipliers follow the sum: the repeat-author factor, which keeps 0.625 of your second-best post and 0.4375 of your third-best, and OonWeightFactor 0.75, on a post from an account the viewer does not follow and on a reply or repost from one they do.

Caveats

These are defaults in open-source code, overridable per experiment at runtime. The ranking model itself (Phoenix) is trained, not rule-based; the weights blend its per-viewer predictions and don’t describe what it learned. Reading weights as tactics is inherently lossy. I’d rather you know that than not.

Sources: param.rs, config.rs, params.rs, scoring.rs, vm_ranker.rs, brazil_2026_election_filter.rs, README.md, action_control.rs, action_control.rs, confidence.rs, off_switch.rs, ads_brand_safety_vf_hydrator.rs, phoenix_source.rs, zero_fav_codivert_filter.rs, post_engagers.rs, oon_retweet_reply_filter.rs, video_carousel.rs, immersive_video_scorer.rs, blender_selector.rs, video_filter.rs, ancestor_video_filter.rs, mod.rs, engine.rs, explain.rs, page_rl.py, reply_features.py, all at 862a123.