How Weights Are Scaled in the X-Algorithm Scoring System

The X-Algorithm scoring system multiplies configurable weights by predicted probabilities for each action, sums positive and negative contributions separately, and applies an optional offset to produce the final ranking score.

Weight scaling in the x-algorithm determines how candidate posts are ranked in the home-mixer feed. According to the xai-org/x-algorithm source code, the system uses a multiplicative approach where weights act as coefficients on model-predicted engagement probabilities rather than raw engagement counts. This fundamental distinction ensures that high-weight negative actions do not linearly cancel out high-volume positive engagements.

Understanding the Core Weight Scaling Mechanism

The scoring logic resides primarily in home-mixer/scorers/ranking_scorer.rs. For every candidate post, the RankingScorer computes a weighted sum by iterating through configurable action weights defined in home-mixer/params/param.rs.

The mathematical operation follows this pattern:

  1. Multiplication – For each action i, the system calculates weight_i × predicted_i, where predicted_i represents the model's probability estimate for that action (such as favorite, reply, report, or dwell time).
  2. Separation – Positive-action weights and negative-action weights are aggregated into separate sums.
  3. Normalization – If the combined result is negative, the scorer rescales it using the total weight sum (total_sum) and adds a constant NEGATIVE_SCORES_OFFSET to ensure non-negative final scores.

This mechanism ensures that weights scale the likelihood of actions rather than their historical frequency.

Positive vs. Negative Action Weights

Weights are defined as floating-point parameters such as FavoriteWeight, ReplyWeight, ReportWeight, and BlockAuthorWeight in home-mixer/params/param.rs.

  • Positive weights amplify desirable engagement signals (favorites, replies, bookmarks).
  • Negative weights penalize candidates with high probabilities of harmful actions (reports, blocks, mutes).

In RankingScorer::compute_weighted_score, these values are retrieved via ScoringWeights::from_params() and applied to the PostCandidate's PhoenixScores. The negative contributions are summed as a distinct negative term rather than being subtracted from individual positive terms, which preserves the proportional relationship between prediction confidence and weight magnitude.

The Role of Predicted Probabilities vs. Raw Counts

A critical nuance in the x-algorithm scoring system is that weights multiply predicted probabilities, not raw engagement counts.

For example, a post with 10,000 likes but a low predicted report probability will not be significantly penalized by ReportWeight, even if that weight is configured as a large negative value. The weight scales the model's confidence that the report will occur, not the historical report count.

This design prevents high-volume content from being arbitrarily suppressed by low-probability negative signals, maintaining a probabilistic rather than deterministic ranking approach.

Handling Negative Scores and Offset Normalization

When the aggregated negative contributions exceed positive contributions, the raw sum becomes negative. The system handles this in RankingScorer::offset_score through a specific transformation:

  • The negative sum is divided by total_sum (the sum of all absolute weight values).
  • The constant NEGATIVE_SCORES_OFFSET is added to shift the final score into positive territory.

This normalization ensures that even heavily penalized posts receive a comparable score format, allowing the ranking system to maintain consistent sorting behavior across the entire candidate set.

Experimental Weight Perturbation

The scoring system supports dynamic weight experimentation through Gaussian perturbation. By setting the WeightPerturbationSigma parameter via feature switches, developers can inject noise into the weight values per request without modifying the baseline configuration.

The ScoringWeights::perturbed() method generates these variations, enabling A/B testing of weight sensitivities while using the same core RankingScorer::compute_weighted_score logic.

Implementation Examples

Loading and Applying Scoring Weights

// Load weights from feature-switch parameters
let query = /* ScoredPostsQuery with active feature switches */;
let weights = ScoringWeights::from_params(&query.params);

// Compute a weighted score for a candidate post
let candidate = /* PostCandidate populated with PhoenixScores */;
let final_score = RankingScorer::compute_weighted_score(&weights, &query, &candidate);
println!("Weighted score = {}", final_score);

Debugging Applied Weights

let weight_map = weights.applied_weights_map();
for (action, w) in weight_map {
    println!("{} => {:.2}", action, w);
}

Enabling Weight Perturbation

// Enable weight perturbation via feature switches
let sigma = query.params.get(WeightPerturbationSigma);
let perturbed_weights = weights.perturbed(&query);
// Use `perturbed_weights` the same way as `weights`

Summary

  • Multiplicative scaling – Weights multiply predicted probabilities (weight × prediction), not raw engagement counts.
  • Bipolar summation – Positive and negative weights are summed separately before offset application.
  • Non-negative normalization – Negative final scores are rescaled using total_sum and shifted by NEGATIVE_SCORES_OFFSET.
  • Configuration-driven – All weights are defined in home-mixer/params/param.rs and instantiated via ScoringWeights::from_params().
  • Experimental flexibility – WeightPerturbationSigma enables per-request Gaussian noise injection without code changes.

Frequently Asked Questions

The system applies weights to predicted probabilities rather than raw counts. A high ReportWeight scales the model's confidence that a report will occur, not the number of existing reports. Consequently, a post with massive engagement but low negative-action probability maintains its rank because the weight multiplies a small probability value, resulting in a negligible penalty.

What happens when the weighted sum of a candidate post is negative?

When RankingScorer calculates a negative combined score, it triggers the offset normalization logic in offset_score. The scorer divides the negative sum by total_sum (the aggregate of all weights) and adds NEGATIVE_SCORES_OFFSET, ensuring the final output remains non-negative while preserving relative ranking order among penalized candidates.

Where are the configurable weights defined in the codebase?

All configurable weights such as FavoriteWeight, ReplyWeight, and ReportWeight are defined as parameter structs in home-mixer/params/param.rs. The ScoringWeights struct aggregates these values and provides methods like from_params() for instantiation and perturbed() for experimentation, as implemented in home-mixer/scorers/ranking_scorer.rs.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →