# How the X Algorithm Blending Pipeline Interleaves Content and Ads

> Learn how the X Algorithm blending pipeline interleaves content and ads by partitioning inputs, selecting a blender, and assigning ad placements for an optimized feed.

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

---

**The blending pipeline converts raw candidate posts and ads into an ordered `FeedItem` stream by partitioning inputs, selecting a strategy-specific blender via the `AdsBlenderType` parameter, and interleaving items through gap computation and placement assignment before finalizing positions.**

The `xai-org/x-algorithm` repository implements this orchestration logic in the home-mixer service. The **blending pipeline interleaves content and ads** through a three-stage Rust pipeline that separates organic content from promotional material, applies configurable spacing strategies, and assembles the final user feed with deterministic positioning.

## Stage 1: Partitioning Raw Candidates

The process begins in [`home-mixer/selectors/blender_selector.rs`](https://github.com/xai-org/x-algorithm/blob/main/home-mixer/selectors/blender_selector.rs), where the `BlenderSelector::select` method receives a heterogeneous `Vec<FeedItem>` containing mixed candidate types. The internal helper `partition_feed_items` splits this raw input into distinct collections:

- Organic posts
- Advertisements (`ads`)
- "Who-to-follow" modules
- Prompts
- Push-to-home posts
- Frames
- Feed surveys

This separation ensures that each content category can be processed with specialized logic before final assembly. The partitioned vectors are then passed to the appropriate blending implementation based on query parameters.

## Stage 2: Selecting a Blending Strategy

The pipeline determines interleaving behavior through the `AdsBlenderType` query parameter. The selector matches this parameter string to a concrete `AdsBlender` implementation:

- **`safe_gap`** – Uses `self.safe_gap_blender` to enforce minimum safe distances between ads and organic posts
- **`partition_organic_low_risk`** – Employs `self.partition_organic_blender` to place ads in slots that split the safe-post pool evenly with additional safety checks
- **`multi_risk`** – Invokes `self.multi_risk_blender` to place ads based on computed risk scores
- **`time_gap`** – Instantiates a `TimeGapAdsBlender` to adjust ad spacing based on temporal configuration

Once selected, the blender's `blend` method is invoked, which delegates to the strategy-specific `blend_inner` implementation defined in files such as [`home-mixer/ads/safe_gap_blender.rs`](https://github.com/xai-org/x-algorithm/blob/main/home-mixer/ads/safe_gap_blender.rs) or [`home-mixer/ads/partition_organic_blender.rs`](https://github.com/xai-org/x-algorithm/blob/main/home-mixer/ads/partition_organic_blender.rs).

## Stage 3: Core Interleaving Logic

Each blender produces a partial list where ads are strategically positioned among posts. The specific mechanics vary by strategy.

### Safe-Gap Blending

In [`home-mixer/ads/safe_gap_blender.rs`](https://github.com/xai-org/x-algorithm/blob/main/home-mixer/ads/safe_gap_blender.rs), the `blend_impl` function executes a four-step placement algorithm:

1. **`find_safe_gaps`** – Identifies valid insertion points in the organic post sequence
2. **`compute_spacing`** – Calculates optimal distance between advertisements
3. **`assign_ads_to_gaps`** – Maps specific ads to specific gap indices based on spacing constraints
4. **`interleave_and_finalize`** – Merges posts and ads into a single vector, truncates to `RESULT_SIZE`, removes trailing ads if they occupy the final slot, and assigns sequential `position` values

```rust
// safe_gap_blender.rs – blend_impl core logic
let safe_gaps = find_safe_gaps(&scored_posts);
let spacing = compute_spacing(&ads);
let placements = assign_ads_to_gaps(&safe_gaps, ads.len(), &spacing, first_ideal);
interleave_and_finalize(scored_posts, ads, &placements, result_size)

```

The `interleave_and_finalize` helper, shared between safe-gap and time-gap blenders, constructs the final `FeedItem` vector by placing ads at their assigned indices and filling remaining slots with organic content.

### Partition-Organic Blending

The [`partition_organic_blender.rs`](https://github.com/xai-org/x-algorithm/blob/main/partition_organic_blender.rs) implementation uses custom assembly logic rather than the generic interleaving helper. It creates **ad-post triples** (post-ad-post sequences) and distributes filler posts between gaps:

```rust
// partition_organic_blender.rs – blend_impl excerpt
for (i, (ad, above, below)) in triples.into_iter().enumerate() {
    items.push(FeedItem { item: Some(feed_item::Item::Post(above)), .. });
    items.push(FeedItem { item: Some(feed_item::Item::Ad(ad)), .. });
    items.push(FeedItem { item: Some(feed_item::Item::Post(below)), .. });

    // Insert filler posts between ad slots
    for _ in 0..filler_per_gap { /* push filler posts */ }
}

```

This approach ensures that ads never appear consecutively without organic content buffers, while maintaining even distribution throughout the feed.

## Finalizing the Feed Stream

After the core blending completes, the `BlenderSelector` performs final assembly operations:

1. **Position Assignment** – Each `FeedItem` receives a sequential `position` field corresponding to its vector index
2. **UI Element Insertion** – Helper functions `insert_prompts`, `insert_who_to_follow`, `insert_push_to_home`, and related methods inject non-content modules at fixed positions (lines 102-176 in [`blender_selector.rs`](https://github.com/xai-org/x-algorithm/blob/main/blender_selector.rs))
3. **Placeholder Generation** – The `build_non_selected_placeholders` function converts dropped posts and ads into placeholder `FeedItem` objects, storing them in the `non_selected` vector for analytics and feedback loops

```rust
// Final position assignment in safe_gap_blender.rs (lines 94-96)
for (idx, item) in result.iter_mut().enumerate() {
    item.position = idx as i32;
}

```

## Summary

- The pipeline starts in [`home-mixer/selectors/blender_selector.rs`](https://github.com/xai-org/x-algorithm/blob/main/home-mixer/selectors/blender_selector.rs) by partitioning mixed candidates into typed vectors via `partition_feed_items`
- Strategy selection occurs through the `AdsBlenderType` parameter, with implementations located in [`home-mixer/ads/safe_gap_blender.rs`](https://github.com/xai-org/x-algorithm/blob/main/home-mixer/ads/safe_gap_blender.rs), [`partition_organic_blender.rs`](https://github.com/xai-org/x-algorithm/blob/main/partition_organic_blender.rs), and related files
- Core interleaving uses `find_safe_gaps`, `compute_spacing`, and `assign_ads_to_gaps` utilities defined in [`home-mixer/ads/util.rs`](https://github.com/xai-org/x-algorithm/blob/main/home-mixer/ads/util.rs)
- Final assembly combines blended content with UI modules and assigns deterministic positions before returning the completed feed

## Frequently Asked Questions

### What determines which blending strategy is used in the X Algorithm?

The `AdsBlenderType` query parameter controls strategy selection. According to [`home-mixer/selectors/blender_selector.rs`](https://github.com/xai-org/x-algorithm/blob/main/home-mixer/selectors/blender_selector.rs) (lines 52-68), the selector matches string values like `"safe_gap"` or `"partition_organic_low_risk"` to specific blender implementations. If no valid type is specified, the system defaults to the partition-organic blender.

### How does the safe-gap blender ensure minimum distance between ads?

The safe-gap strategy computes valid insertion points through `find_safe_gaps` and calculates spacing via `compute_spacing` in [`home-mixer/ads/util.rs`](https://github.com/xai-org/x-algorithm/blob/main/home-mixer/ads/util.rs). The `assign_ads_to_gaps` function then places ads only at indices that satisfy these distance constraints, ensuring no two ads appear closer than the configured threshold.

### What happens to posts and ads that don't make it into the final feed?

Excluded items are preserved as placeholder `FeedItem` objects. The `build_non_selected_placeholders` method (lines 78-92 in [`blender_selector.rs`](https://github.com/xai-org/x-algorithm/blob/main/blender_selector.rs)) converts dropped candidates into tracking entries stored in the `non_selected` vector, allowing the system to record which content was available but not served.

### Where is the interleaving logic implemented for time-based ad spacing?

The time-gap blender in [`home-mixer/ads/time_gap_blender.rs`](https://github.com/xai-org/x-algorithm/blob/main/home-mixer/ads/time_gap_blender.rs) implements temporal spacing logic. Like the safe-gap blender, it uses the shared `interleave_and_finalize` helper to merge content, but calculates placement gaps based on time-interval configuration rather than raw index spacing.