- Sources read: 2
- Canon files updated: 2
- Radar entries: 0
Other changes reviewed today:
- X rebuilt the popular posts candidate source, introduced three days earlier in the same commit series, as an offline job based on view counts.
- Meta updated the Facebook Feed system card as of 2026-10-06, and the card's only embedding feature sentence disappeared.
1Expected dwell time terms were added to the ranking score formula — X
Source xai-org/x-algorithm@e62790c — xai-org, 2026-10-06T04:59:30Z, code. These notes number X commits after the Gen4 release in order, and this commit is Gen4+36. It changed 103 files, with +6,916/−1,393 lines. The previous commit is b412112 (Gen4+35) from 2026-10-03.
Background In X's For You ranking, Phoenix (a Grok-based Transformer ranker) predicts dozens of action probabilities for each post, and each prediction is called a head. The value model combines those probabilities into a single score as a weighted sum. The weighted sum includes continuous-value heads such as "dwell time" as well as probability heads such as "probability of a like." Until now, continuous-value heads multiplied the predicted value directly by a weight.
This commit adds a different approach: it predicts "the probability of opening a video" and "the seconds watched on after opening" separately and multiplies them to get expected watch seconds. This kind of split is called a conditional expectation decomposition (total expectation = event probability × expectation given the event occurred). The same commit also completely changed the structure of the popular posts candidate source (PopularPostsSource), released three days earlier.
What we learnedA. The value model gained three expected-dwell-time terms of the form 'probability × conditional seconds'
Three terms that multiply a probability by conditional seconds were added to the value model verified —
xai-value-model/scoring.rs:61-63, 111-128.The first term is "probability of opening a video × seconds watched on after opening," and the third is "probability of a profile click × seconds spent on the profile after the click."
The code that builds the three terms:
fn product(probability: Option<f64>, conditional_value: Option<f64>) -> Option<f64> { Some(probability? * conditional_value?) } ... apply(product(scores.video_open_score, scores.home_video_continuation_secs), weights.video_continuation), apply(product(scores.video_open_score, candidate.user_video_continuation_secs), weights.user_video_continuation), apply(product(scores.profile_click_score, scores.home_profile_visit_secs), weights.profile_visit_secs),
The second term is a value of the user, not of the candidate. It takes the average watch seconds across all candidates in one request, weighted by open probability, and puts the same value into every candidate verified —
scoring.rs:141-158.set_user_video_continuationcomputes this value asΣ P(open)·secs / Σ P(open).- Because the value is the same for every candidate, this term ends up as
weight × (user average watch seconds) × P(open). It has the effect of raising the coefficient on "probability of opening a video" for users who watch videos for longer inferred.
The cron mirror (a file that syncs and publishes production parameter values daily) default for all three weights is 0.0 verified —
vm-ranker/params.rs.- The weights are named
VideoContinuationWeight,UserVideoContinuationWeightandProfileVisitSecsWeight.
- The weights are named
The internal path (
weights_for) in home-mixer, which handles For You feed requests, hardcodes the three values to 0.0 in code verified —home-mixer/scorers/value_model.rs:37-39. Therefore the only place that can turn this term on is VM-Ranker (a separate service that computes the value model directly).Phoenix's list of continuous-value heads gained 'profile visit seconds' and 'video continuation seconds' heads verified —
recsys.proto:594-599.- The list is named
ContinuousActionName, and the new values areHOME_PROFILE_VISIT_SECS = 0andHOME_VIDEO_CONTINUATION_SECS = 3. - Number 3 was previously used by
ACTIVE_SECS_5M_RESIDUAL_NORM(a "5-minute active seconds" residual head that was tied to weight 0). That head was removed from both the proto and the value model.
- The list is named
home-mixer's extraction of the two head values from the Phoenix response is also behind
EnableHomeExcursionScores(default false) verified —home-mixer/scorers/phoenix_scorer.rs:109-117, 141-153.On the training data side, a new aggregation type was added in a previously empty slot verified.
DENSE_WITH_LONG_DWELL_HOME_EXCURSION = 30took the place ofPLACEHOLDER_30.
The README's list of Phoenix predictions also changed verified —
README.md:341."Attention video quality view · dwell · dwell time · click dwell time · video continuation seconds · profile visit seconds"
The same line in the previous version was
... click dwell time · active seconds.
What we learnedB. The popular posts source now only reads a list that offline jobs built in advance
This version removed the Thunder (a store of latest posts based on the follow graph) call from the request path. The version from three days earlier passed "1,000 popular authors" to Thunder as a fake following list on every request and fetched their latest posts.
- Now two offline jobs build the list in advance, and the serving source only reads it verified —
popular_posts_source.rs.- The related code is in
util/popular_posts.rs:36-87,popular_posts_job.rs:21-178andutil/popular_authors.rs:11, 25-40.
- The related code is in
Processing runs in this order:
- The author job runs on a default 1-hour cycle. From the follower-ranking snapshot in the BigQuery table
popular_posting_authors, it selects the number of authors who posted in the last 7 days × 0.00005 authors, that is, the top 0.005% by follower count. If the snapshot is older than 30 hours, it is treated as a failure. - The post job runs on a default 5-minute cycle. It groups those authors in batches of 20, gets up to 50 posts per author from Thunder, and discards replies and retweets.
- It gets the view counts (
view_count) of posts within 24 hours from the engagement counts service, 500 at a time. - The scoring appears to assume that the view rate halves every 8 hours and to scale the views so far up to 24-hour cumulative views inferred.
- The formula is
quality = views × (1 − e^{−λ·24}) / (1 − e^{−λ·max(age_h, 0.5)}), andλ = ln2 / 8(half-life 8 hours). - The denominator is "the fraction accumulated up to the current age," and the numerator is "the fraction that will have accumulated by 24 hours."
- The age floor of 0.5 hours keeps the score of a just-posted post from blowing up.
- The formula is
- It keeps the top 5 per author and the top 500 overall, writes them to Manhattan (a KV store), then reads them back and checks that the creation time matches.
- The serving source reloads the list every 60 seconds, removes only posts the user has already seen, and emits up to 500 candidates.
- The three parameters from the version three days earlier were deleted verified.
PopularPostsTopAuthors(1000)·PopularPostsMaxPerAuthor(3)·PopularPostsMaxRepliesRepostsPerAuthor(0)
- Because the only per-user input is "posts already seen," this source is the same global popular list for every user verified.
- The source itself is still off by default (
EnablePopularPostsSource=false).
What we learnedC. Visibility verdicts gained a fourth grade that 'shows the post with a notice attached'
Visibility filtering (VF) is the service that decides whether a candidate post may be shown to this viewer.
VF verdicts now have four grades verified —
README.md:205-232.NOTICEwas added to the existing three grades.Existing grades:
ALLOW(shown as is),INTERSTITIAL(shown behind a warning screen),DROP(removed)The README describes the new grade like this:
"NOTICE show the post with a notice attached to it"
The internal representation is
SoftIntervention { policy: AppealablePolicy, level, proactive, appeal_submitted }verified —visibility-filtering/models/verdict.rs. The post stays in the feed.
What we learnedD. An "Under the Hood" request returns the pipeline processing record together with per-post scores
- When the Under the Hood flag is on in a request, the response carries both the pipeline processing record and per-post scores verified —
home-mixer/util/under_the_hood.rs.- The request field is
is_under_the_hood_request. - It includes per-stage latency and kept and removed counts, per-post Phoenix head scores, the final score, and the name of the value model used.
- Each stage carries a public code link of the form
github.com/xai-org/x-algorithm/blob/main/home-mixer/.... - The default of the flag
EnableUnderTheHoodis false. - Since the response includes public repository links, it appears to be a feature for a screen that shows "why this post appeared" inferred. Which screen it appears on is not in the repository.
- The request field is
What we learnedOther changes
- The new-author boost (a bonus given to posts from authors who have not yet been shown) has so far been applied only to in-network candidates. With the switch on, it also applies to OON (accounts the user does not follow) candidates verified —
scoring.rs:85-90.- The term is named
post_unexplored, and the switch isPostUnexploredIncludeOutOfNetwork(default false).
- The term is named
RetrievalCandidatesKafkaMaxCandidateschanged from 200 to 100,000 verified. The cap on writing retrieval (candidate generation stage) candidates to Kafka has effectively been lifted inferred.VMRankerClusterIdchanged from"Experiment6"to"Experiment1"verified. The differences between experiment clusters are not public.
Canon update In services/x.md, we revised the following:
- Overwrote the
PopularPostsSourcerow in the source table of theCandidate generationsection with the new structure. - In the head table of the
Weightssection, markedcont_active_secs_5m_residual_normas removed and added rows for the three new terms. - Updated the
VMRankerClusterIdvalue in the VMRanker parameter table. - Created the
### Gen4+36section. Added the reference commite62790cto the Source section.
Why it matters Until now, the continuous-value terms in X's value model had one form, "head value × weight," and this commit adds a second form: probability head × conditional seconds head. The weights are 0, so the serving score has not yet changed verified.
- The weight of the profile click probability (
profile_click) has been 0.0 since the Gen4 release. A separate path now exists that can reward dwell time after the click without rewarding the profile click probability itself inferred. In this term, the probability head is used only as a factor in the product. - Within three days of its release, the definition of the popular posts source (
PopularPostsSource) changed from "latest posts of popular authors" to "posts by popular authors whose view counts grow fast." With the per-request Thunder call gone, the request cost became constant verified.
2The embedding feature sentence disappeared from the Facebook Feed system card — Facebook
Source Facebook Feed AI system — Meta Transparency Center, card label "UPDATED OCT 6, 2026" (2026-10-06), system card (an explanatory document for regulatory compliance). The previous version was dated 2026-06-24.
Background Meta publishes a "system card" for each surface, a document that describes in plain language the stages by which that surface's feed is built, which prediction heads exist, and which input signals go into each head. This repository read this card on 2026-08-09 and built the prediction head and feature lists of the Facebook canon from it. Today we noticed that the card date had changed, rendered the English version with headless Chrome, and reread the full text. The card has no change log.
What we learnedA. The sentence that was the card's only embedding feature is absent from the current version
- The sentence that was the card's only embedding feature is gone observed 2026-10-07.
- The version read on 2026-08-09 had this sentence: "An embedding to represent the viewer".
- The word "embedding" does not appear even once in the full text rendered today.
- All 50 current signals are aggregations of counts, ratios, or time windows.
- The card date changed only once in the meantime, so we infer it was dropped in the 10-06 update inferred. However, we did not keep the original text of the earlier version and Wayback did not respond today, so we could not compare directly.
- The sentence missing from the card does not mean the model stopped using a viewer embedding. The card lists only some of the "significant predictions".
What we learnedB. The card describes integrity handling in two stages
- Integrity (handling of policy violations and problematic content) is described across two stages observed 2026-10-07.
Posts flagged as violations are dropped when candidates are gathered. In the card, this appears under the "Gather inventory" stage.
"First, the system gathers all potential posts shared by friends, Pages you follow and groups you've joined, which excludes posts flagged for going against our Community Standards."
Distribution-reducing handling is in the same paragraph as the stage where a lightweight model selects about 500 posts (pass 0). In the card, this appears under the "Leverage signals" stage.
"A lightweight model is run to select approximately 500 of the most relevant posts. The system also applies certain integrity processes to help reduce the distribution of problematic content." — Facebook Feed AI system, 2026-10-06 version
The canon had been saying "the fb-feed card does not mention an integrity stage." We cannot determine whether the exclusion sentence in the inventory stage is new this time or was missed on 2026-08-09.
What we learnedC. The number and order of heads match the previous version, but the name of head 5 and the lookback windows differed from what the canon recorded
There are 10 prediction heads with 5 signals each, 50 in total. The number and order of heads are the same as in the previous version observed 2026-10-07.
Head 5 is described as the probability of clicking 'Interested' when the interested/not interested options are shown observed 2026-10-07.
"How likely you are to click 'Interested' if the interested/not interested options are presented to you." — Facebook Feed AI system, 2026-10-06 version
- The canon had recorded this head as a 'Show more' click.
- Meta already said that it renamed Show more to Interested on 2025-03-11, so it is the same head. We changed the canon wording to the current name.
The lookback windows (the past periods over which features aggregate) are 1 hour, 2 hours, 1 day, 7 days, 14 days, 28 days, 30 days and 180 days observed 2026-10-07. The "3 months" window that was in the canon is not in the current version.
What we learnedOther observations
A paragraph describing the Instagram app is mixed into the "How to customize" section observed 2026-10-07.
"You can click the Instagram logo on your home screen and then click on either “Following” or “Favorites” on mobile app."
- This appears to be an editing error in which wording from the Instagram card was copied into the Facebook card inferred. The same section has a separate Facebook "See newest content first" item.
This page is rendered with JavaScript, so curl does not return the body, and opening it without
/en-us/returns the Korean version. To reproduce, get the DOM with headless Chrome and extract the text.- The command is
"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" --headless=new --lang=en-US --virtual-time-budget=15000 --dump-dom https://transparency.meta.com/en-us/features/explaining-ranking/fb-feed/.
- The command is
Canon update In services/facebook.md, we revised the following:
- Overwrote the integrity stage bullet in the
Rankingsection with a two-sentence structure. - In the
Prediction headssection, moved the card update date up to 2026-10-06 and replaced head 5 with the 'Interested' original text. - In the
Actual feature namessection, marked the viewer embedding sentence with ⚠ and recorded the observation that it is absent from the current version. Also fixed the lookback window list and recorded the Instagram paragraph mix-in. - Added item 14 (the exact diff of the 10-06 update) to
Open questions.
Why it matters
- ⚠ Claim changed: The canon's "the viewer embedding is the only embedding feature stated on the fb-feed card" does not hold as of the current version. The current card has no embedding feature at all.
- ⚠ Claim changed: "The fb-feed card does not mention an integrity stage" also does not hold as of the current version. Removal-type handling is placed in the inventory-gathering stage, and penalty-type handling in the pass 0 paragraph.
What to check next
- When Wayback returns, get the 2026-06-24 version of the fb-feed card and directly compare the deletion of the viewer embedding sentence and the addition of the inventory exclusion sentence — both are currently inferred. From now on, we need to save the rendered original text when reading the card so the next comparison is possible.
- Check whether X's
HOME_*_SECSweights move from 0 — the day the cron mirror changesVideoContinuationWeightandProfileVisitSecsWeightis when serving actually takes effect. - Keep tracking
EnablePopularPostsSourceto see whether the default ofPopularPostsSourcechanges — if this source is turned on, a global popular list enters For You as OON candidates. - Do a deep dive on X VF's
NOTICEgrade — we have not yet read the rules registry mapping that shows which policies (AppealablePolicy) go to notice. The VF changes in this commit (+4,000 lines or more) were excluded from today's scope.- Relevant files:
filter.rs,hydration/execute.rs,community_source.rs,trusted_friends_client.rs
- Relevant files:
- Find the new path of the research.netflix.com publications list and fix the batch source list —
/publicationsreturns 404.
Lookup failed: research.netflix.com/publications returned HTTP 404. The alternative path /archive opens, but its newest entry is 2026-02-24, so the list appears not to be updated.