# How Weights Are Scaled in the X-Algorithm Scoring System

> Learn how weights are scaled in the X-Algorithm scoring system. Understand how configurable weights and predicted probabilities create final ranking scores for actionable insights.

- Repository: [SpaceXAI Org/x-algorithm](https://github.com/xai-org/x-algorithm)
- Tags: deep-dive
- Published: 2026-09-12

---

**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`](https://github.com/xai-org/x-algorithm/blob/main/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`](https://github.com/xai-org/x-algorithm/blob/main/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`](https://github.com/xai-org/x-algorithm/blob/main/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

```rust
// 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

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

```

### Enabling Weight Perturbation

```rust
// 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`](https://github.com/xai-org/x-algorithm/blob/main/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

### How does the X-Algorithm prevent high-weight negative actions from canceling out popular content?

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`](https://github.com/xai-org/x-algorithm/blob/main/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`](https://github.com/xai-org/x-algorithm/blob/main/home-mixer/scorers/ranking_scorer.rs).