Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 15 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ This repository contains the core code that determines which posts a viewer sees

## Table of Contents

- [Latest update](#latest-update--august-13th-2026)
- [Notable Updates](#notable-updates)
- [August 14th, 2026](#august-14th-2026)
- [August 13th, 2026](#august-13th-2026)
- [Overview](#overview)
- [System Architecture](#system-architecture)
- [Request Path](#request-path)
Expand All @@ -23,7 +25,16 @@ This repository contains the core code that determines which posts a viewer sees



## Latest update — August 13th, 2026
## Notable Updates

### August 14th, 2026

Notable updates:

- **How weights work.** There's a common misconception about how weights related to actions (e.g. Like, Share, Block, Report, etc) work in ranking. The weights scale the predicted probabilities of such actions (or predicted continuous values, e.g. dwell time) — they do *not* scale the raw engagement counts, so e.g. it'd be incorrect to see that a report has 468 times higher weight than a like and conclude that e.g. "1 report cancels out 468 likes". The weights are a multiple on your own predicted probability of Liking, Reporting, etc, which is substantially driven by your own behavior. We've [added comments](home-mixer/params/param.rs) [to the code](home-mixer/scorers/ranking_scorer.rs) so that LLMs or people reading it are more likely to understand it correctly.
- **Brazil 2026 Elections.** As [announced by X](https://x.com/XBR/status/2088341967864320507?s=20), in accordance with Brazilian electoral law, For You now runs `Brazil2026ElectionFilter`, which removes posts from accounts reported to Brazil's Electoral Court for the 2026 election, unless the viewer explicitly follows the account. *(Account list updated August 27, 2026.)* A benefit of open-source is that you can see that changes like this exist, and exactly how they work — take a [look at the code](home-mixer/filters/brazil_2026_election_filter.rs).

### August 13th, 2026

This release:

Expand Down Expand Up @@ -329,6 +340,8 @@ Final Score = Σ (weight_i × P(action_i))

Positive actions carry positive weights, negative actions negative ones. The weights are in [`home-mixer/params/param.rs`](home-mixer/params/param.rs); the arithmetic is in [`home-mixer/scorers/ranking_scorer.rs`](home-mixer/scorers/ranking_scorer.rs).

There is a common misconception to be aware of about the weights: they scale the predicted probabilities (or predicted continuous values, e.g. dwell time) — they do *not* scale the raw engagement counts, so e.g. it'd be incorrect to see that a report has 468 times higher weight than a like and conclude that e.g. "1 report cancels out 468 likes". The weights are a multiple on your own predicted probability of Liking, Reporting, etc, which is substantially driven by your own behavior.

Three adjustments follow:

- **Author Diversity**: each post after an author's first is multiplied by a decaying factor, down to a floor.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# mirrored from GrowthBook dynamic config; last sync 2026-08-06T16:20:00Z
# mirrored from GrowthBook dynamic config; last sync 2026-08-25T16:15:48Z

for_entity: post

Expand Down Expand Up @@ -75,6 +75,11 @@ rules:
perm: true
policy: Cse

- id: act_requested_actions
when: "size(score.requested_actions) > 0"
then:
kind: act_requested_actions

- id: post_no_actionable_label
when: "true"
then:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# mirrored from GrowthBook dynamic config; last sync 2026-08-12T16:22:21Z
# mirrored from GrowthBook dynamic config; last sync 2026-08-26T16:31:18Z

for_entity: user

Expand All @@ -15,6 +15,13 @@ rules:
kind: skip
reason: user_not_found

- id: very_high_follower_count
# Prod uses a different follower count floor; this is a mock value to reduce gaming.
when: cred.follower_count >= 12.34
then:
kind: skip
reason: very_high_follower_count

- id: high_follower_count
# Prod uses a different follower count floor; this is a mock value to reduce gaming.
when: cred.follower_count >= 12.34
Expand Down Expand Up @@ -42,6 +49,12 @@ rules:
when: '"anchor_campaign_suspend_cse" in score.labels'
then: { kind: act_suspend_user, perm: true, policy: "Cse" }

- 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" }



- id: already_spam_high_recall_labeled_llm_slop
when: '"llm_slop_user" in score.labels && "SpamHighRecall" in user.labels'
then:
Expand Down Expand Up @@ -201,6 +214,17 @@ rules:
labels: ["SpamHighRecall"]
ttl_msec: 2592000000

- 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

- id: act_suspend
when: "true"
then:
Expand Down
6 changes: 4 additions & 2 deletions abuse-enforcement-service/service-lib/src/ais_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -471,8 +471,10 @@ mod tests {
"additionalInfo": []
}}),
json!({"bounceViaSelection": {
"userId": 1,
"uncheckedTags": ["FAKE"]
"target": {"user": {"userId": 1}},
"tags": [],
"uncheckedTags": ["FAKE"],
"bounceActor": {"simpleService": {"serviceName": "xai-abuse-enforcement-service"}}
}}),
],
"RtpPlugin",
Expand Down
125 changes: 25 additions & 100 deletions abuse-enforcement-service/service-lib/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,25 +38,14 @@ pub struct Config {
#[arg(long, env = "SOCKS_PROXY")]
pub socks_proxy: Option<String>,

#[arg(
long,
default_value = "/s/kafka/phoenix-kafka-scram-bootstrap",
env = "KAFKA_DEST"
)]
pub kafka_dest: String,
#[arg(long, default_value_t = false, env = "KAFKA_CONSUMER_ENABLED")]
pub kafka_consumer_enabled: bool,

#[arg(long, default_value = "SCRAM-SHA-512", env = "KAFKA_SASL_MECHANISM")]
pub kafka_sasl_mechanism: String,
#[arg(long, default_value = "phoenix", env = "KAFKA_CONSUMER_MTLS_CLUSTER")]
pub kafka_consumer_mtls_cluster: String,

#[arg(
long,
default_value = "scram-client-phoenix",
env = "KAFKA_SASL_USERNAME"
)]
pub kafka_sasl_username: String,

#[arg(long, env = "KAFKA_SASL_PASSWORD")]
pub kafka_sasl_password: Option<String>,
#[arg(long, default_value = "atla", env = "KAFKA_CONSUMER_MTLS_ZONE")]
pub kafka_consumer_mtls_zone: String,

#[arg(
long,
Expand All @@ -68,39 +57,12 @@ pub struct Config {
#[arg(long, env = "KAFKA_CONSUMER_GROUP_ID")]
pub kafka_consumer_group_id: Option<String>,

#[arg(long, env = "KAFKA_CONSUMER_DEST")]
pub kafka_consumer_dest: Option<String>,

#[arg(long, env = "KAFKA_CONSUMER_SASL_MECHANISM")]
pub kafka_consumer_sasl_mechanism: Option<String>,

#[arg(long, env = "KAFKA_CONSUMER_SASL_USERNAME")]
pub kafka_consumer_sasl_username: Option<String>,

#[arg(long, env = "KAFKA_CONSUMER_SASL_PASSWORD")]
pub kafka_consumer_sasl_password: Option<String>,

#[arg(long, default_value_t = 256, env = "KAFKA_MAX_MESSAGES_PER_POLL")]
pub kafka_max_messages_per_poll: usize,

#[arg(long, default_value_t = 64, env = "KAFKA_MAX_IN_FLIGHT")]
pub kafka_max_in_flight: usize,

#[arg(long, env = "KAFKA_PRODUCER_DEST")]
pub kafka_producer_dest: Option<String>,

#[arg(long, env = "KAFKA_PRODUCER_SASL_MECHANISM")]
pub kafka_producer_sasl_mechanism: Option<String>,

#[arg(long, env = "KAFKA_PRODUCER_SASL_USERNAME")]
pub kafka_producer_sasl_username: Option<String>,

#[arg(long, env = "KAFKA_PRODUCER_SASL_PASSWORD")]
pub kafka_producer_sasl_password: Option<String>,

#[arg(long, default_value_t = false, env = "KAFKA_PRODUCER_MTLS_ENABLED")]
pub kafka_producer_mtls_enabled: bool,

#[arg(long, default_value = "coredata", env = "KAFKA_PRODUCER_MTLS_CLUSTER")]
pub kafka_producer_mtls_cluster: String,

Expand Down Expand Up @@ -257,61 +219,7 @@ pub struct Config {
pub api_keys_json: Option<String>,
}

#[derive(Debug, Clone)]
pub struct KafkaConnConfig {
pub dest: String,
pub sasl_mechanism: String,
pub sasl_username: String,
pub sasl_password: Option<String>,
}

#[derive(Debug, Default)]
struct KafkaConnOverride {
dest: Option<String>,
sasl_mechanism: Option<String>,
sasl_username: Option<String>,
sasl_password: Option<String>,
}

impl KafkaConnConfig {
fn with_overrides(self, overrides: KafkaConnOverride) -> KafkaConnConfig {
KafkaConnConfig {
dest: overrides.dest.unwrap_or(self.dest),
sasl_mechanism: overrides.sasl_mechanism.unwrap_or(self.sasl_mechanism),
sasl_username: overrides.sasl_username.unwrap_or(self.sasl_username),
sasl_password: overrides.sasl_password.or(self.sasl_password),
}
}
}

impl Config {
fn kafka_common(&self) -> KafkaConnConfig {
KafkaConnConfig {
dest: self.kafka_dest.clone(),
sasl_mechanism: self.kafka_sasl_mechanism.clone(),
sasl_username: self.kafka_sasl_username.clone(),
sasl_password: self.kafka_sasl_password.clone(),
}
}

pub fn kafka_consumer(&self) -> KafkaConnConfig {
self.kafka_common().with_overrides(KafkaConnOverride {
dest: self.kafka_consumer_dest.clone(),
sasl_mechanism: self.kafka_consumer_sasl_mechanism.clone(),
sasl_username: self.kafka_consumer_sasl_username.clone(),
sasl_password: self.kafka_consumer_sasl_password.clone(),
})
}

pub fn kafka_producer(&self) -> KafkaConnConfig {
self.kafka_common().with_overrides(KafkaConnOverride {
dest: self.kafka_producer_dest.clone(),
sasl_mechanism: self.kafka_producer_sasl_mechanism.clone(),
sasl_username: self.kafka_producer_sasl_username.clone(),
sasl_password: self.kafka_producer_sasl_password.clone(),
})
}

pub fn kafka_group_id(&self) -> String {
self.kafka_consumer_group_id
.clone()
Expand All @@ -326,10 +234,27 @@ mod tests {
use super::Config;

#[test]
fn coredata_producer_mtls_defaults_pin_atla() {
fn kafka_defaults_preserve_consumer_and_watchdog_behavior() {
let config = Config::parse_from(["xai-abuse-enforcement-service"]);

assert!(!config.kafka_consumer_enabled);
assert_eq!(config.kafka_consumer_mtls_cluster, "phoenix");
assert_eq!(config.kafka_consumer_mtls_zone, "atla");
assert_eq!(config.kafka_group_id(), "xai-abuse-enforcement-service");
assert_eq!(config.kafka_max_messages_per_poll, 256);
assert_eq!(config.kafka_max_in_flight, 64);
assert!(config.kafka_self_delete_enabled);
assert_eq!(config.kafka_watchdog_interval_secs, 15);
assert_eq!(config.kafka_watchdog_stale_secs, 120);
assert_eq!(config.kafka_watchdog_self_delete_secs, 240);
assert_eq!(config.kafka_watchdog_error_rate_per_sec, 2.0);
assert_eq!(config.kafka_watchdog_error_self_delete_secs, 60);
}

#[test]
fn coredata_producer_defaults_use_mtls() {
let config = Config::parse_from(["xai-abuse-enforcement-service"]);

assert!(!config.kafka_producer_mtls_enabled);
assert_eq!(config.kafka_producer_mtls_cluster, "coredata");
assert_eq!(config.kafka_producer_mtls_zone, "atla");
}
Expand Down
1 change: 1 addition & 0 deletions abuse-enforcement-service/service-lib/src/decision.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
pub enum Decision {
Skip(String),
Act(Vec<ActionSpec>),
ActRequestedActions,
}

#[derive(Debug, Clone, PartialEq, Eq)]
Expand Down
Loading