# How Visibility-Filtering Makes ALLOW, INTERSTITIAL, or DROP Decisions in the X Algorithm

> Discover how visibility-filtering in the X Algorithm makes ALLOW INTERSTITIAL or DROP decisions using strict hierarchy and context data to control content visibility.

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

---

**Visibility-filtering applies a strict hierarchy where DROP overrides INTERSTITIAL and INTERSTITIAL overrides ALLOW, using hydrated context data and policy-based rule evaluation to determine content visibility.**

The visibility-filtering system in the [xai-org/x-algorithm](https://github.com/xai-org/x-algorithm) repository serves as the gatekeeper for tweet distribution, determining whether content appears directly in user feeds, behind a warning interstitial, or is suppressed entirely. Written in Rust, this module processes every tweet through a multi-stage pipeline that evaluates safety labels, author relationships, and media content against declarative rule sets. Understanding this decision flow reveals how the platform balances content moderation with user choice.

## Core Concepts: RuleSpec, Policy, and Verdict

The architecture rests on three fundamental abstractions that separate rule definition from execution logic:

- **RuleSpec**: A declarative rule that defines both a predicate condition (e.g., "tweet contains NSFW media") and the resulting action. These specifications live in [`visibility-filtering/rules/tweet_rules.rs`](https://github.com/xai-org/x-algorithm/blob/main/visibility-filtering/rules/tweet_rules.rs) and include concrete implementations like `NSFW_MEDIA_INTERSTITIALS` and `NSFW_AUTHOR_INTERSTITIAL`.

- **Policy**: An ordered collection of `RuleSpec` instances evaluated sequentially. The system maintains two primary policies in [`visibility-filtering/rules/registry.rs`](https://github.com/xai-org/x-algorithm/blob/main/visibility-filtering/rules/registry.rs): `INTERSTITIALS` for rules triggering warning screens, and `DROP_AFTER_INTERSTITIAL` for rules requiring permanent suppression.

- **Verdict**: The enumeration result returned after policy evaluation, containing one of three variants: `ALLOW`, `INTERSTITIAL`, or `DROP`.

## The Decision Pipeline: From Hydration to Final Verdict

When a viewer requests a tweet, the system executes a four-stage pipeline to reach a visibility decision:

### 1. Context Hydration

First, hydrators in `visibility-filtering/hydration/` gather all relevant metadata including the tweet content, author information, viewer relationship data (blocks, mutes), and safety labels. This raw data feeds into an in-memory **TestContext** snapshot that rules consume during evaluation.

### 2. Policy Selection

The system selects between two static policies defined in [`visibility-filtering/rules/registry.rs`](https://github.com/xai-org/x-algorithm/blob/main/visibility-filtering/rules/registry.rs):

- **`INTERSTITIALS`**: Contains rules like `NSFW_MEDIA_INTERSTITIALS` that trigger warning screens
- **`DROP_AFTER_INTERSTITIAL`**: Contains rules like `NSFW_MEDIA_DROP` that enforce permanent removal

### 3. Sequential Rule Evaluation

Each policy evaluates its `RuleSpec` array in order against the `TestContext`. The evaluation follows strict precedence rules where the first matching rule determines the initial verdict, though subsequent checks may override it for drop conditions.

### 4. Hierarchy Resolution

The final verdict follows a **DROP > INTERSTITIAL > ALLOW** hierarchy. If any rule in the drop policy matches, the content is suppressed regardless of interstitial eligibility. If no rules match, the default state is `ALLOW`.

## Decision Hierarchy and Precedence

The precedence logic ensures that safety-critical restrictions always take priority over warning screens. As implemented in [`visibility-filtering/filter.rs`](https://github.com/xai-org/x-algorithm/blob/main/visibility-filtering/filter.rs), the `filter_tweets` function orchestrates this hierarchy:

1. Evaluate the `INTERSTITIALS` policy first
2. If the result is `INTERSTITIAL`, subsequently evaluate `DROP_AFTER_INTERSTITIAL`
3. If the drop policy matches, upgrade the verdict to `DROP`
4. If the initial evaluation returns `ALLOW`, skip further checks

This two-phase evaluation ensures that borderline content receives appropriate warnings, while clear policy violations result in immediate suppression.

## Source Code Implementation

The decision logic spans three primary files in the repository:

### visibility-filtering/rules/tweet_rules.rs

This file defines the concrete `RuleSpec` constants that check for NSFW media, author labels, and relationship flags. These specifications contain the predicate logic that inspects the `TestContext` for specific safety labels or user interactions.

### visibility-filtering/rules/registry.rs

The registry aggregates individual rules into policies and provides the `Policy::evaluate` method. It declares the static arrays `INTERSTITIAL_ROWS` and `DROP_AFTER_INTERSTITIAL_ROWS`, then composes them into the `INTERSTITIALS` and `DROP_AFTER_INTERSTITIAL` policy instances used by the filtering engine.

### visibility-filtering/filter.rs

This module exposes the public entry point `filter_tweets`, which accepts a `Viewer` and `Tweet` reference, constructs the `TestContext`, and executes the policy evaluation chain. The function returns the final `Verdict` that downstream systems use to render content, display interstitials, or hide tweets.

## Code Example: The Filtering Flow

Below is the core logic from [`visibility-filtering/filter.rs`](https://github.com/xai-org/x-algorithm/blob/main/visibility-filtering/filter.rs) demonstrating how the hierarchy works in practice:

```rust
pub fn filter_tweets(viewer: &Viewer, tweet: &Tweet) -> Verdict {
    let ctx = TestContext::new(viewer, tweet);
    // First check if content requires an interstitial
    let verdict = INTERSTITIALS.evaluate(&ctx);
    match verdict {
        Verdict::Allow => Verdict::Allow,
        Verdict::Interstitial => {
            // Check if drop rules override the interstitial
            DROP_AFTER_INTERSTITIAL.evaluate(&ctx)
        }
        other => other,
    }
}

```

And the policy definitions from [`visibility-filtering/rules/registry.rs`](https://github.com/xai-org/x-algorithm/blob/main/visibility-filtering/rules/registry.rs):

```rust
static INTERSTITIAL_ROWS: [RuleSpec; 2] = [
    RuleSpec::Tweet { rules: NSFW_MEDIA_INTERSTITIALS },
    RuleSpec::Tweet { rules: NSFW_AUTHOR_INTERSTITIAL },
];
static INTERSTITIALS: Policy = Policy::new(&[&INTERSTITIAL_ROWS]);

static DROP_AFTER_INTERSTITIAL_ROWS: [RuleSpec; 2] = [
    RuleSpec::Tweet { rules: NSFW_MEDIA_DROP },
    RuleSpec::Tweet { rules: NSFW_AUTHOR_DROP },
];
static DROP_AFTER_INTERSTITIAL: Policy = Policy::new(&[&DROP_AFTER_INTERSTITIAL_ROWS]);

```

## Summary

- **Visibility-filtering** determines tweet distribution through a rule-based pipeline that evaluates hydrated context data against declarative policies.
- The system maintains a strict decision hierarchy: **DROP** overrides **INTERSTITIAL**, which overrides **ALLOW**.
- Three core abstractions—**RuleSpec**, **Policy**, and **Verdict**—separate rule definition from execution logic.
- The implementation spans [`visibility-filtering/filter.rs`](https://github.com/xai-org/x-algorithm/blob/main/visibility-filtering/filter.rs) (entry point), [`visibility-filtering/rules/registry.rs`](https://github.com/xai-org/x-algorithm/blob/main/visibility-filtering/rules/registry.rs) (policy aggregation), and [`visibility-filtering/rules/tweet_rules.rs`](https://github.com/xai-org/x-algorithm/blob/main/visibility-filtering/rules/tweet_rules.rs) (rule definitions).
- Context hydration in `visibility-filtering/hydration/` supplies the safety labels and relationship data required for rule evaluation.

## Frequently Asked Questions

### What is the difference between INTERSTITIAL and DROP decisions?

An **INTERSTITIAL** decision places content behind a warning screen that users can click through to view the material, typically used for sensitive but not prohibited content. A **DROP** decision completely prevents the content from appearing in the user's feed, reserved for severe policy violations or blocked relationships. According to the source code, the system checks interstitial rules first, then applies drop rules only if an interstitial was triggered, ensuring that suppression takes precedence over warnings.

### How does visibility-filtering handle multiple conflicting rules?

The system processes rules sequentially within each policy, but the **DROP > INTERSTITIAL > ALLOW** hierarchy resolves conflicts across policy boundaries. If the `INTERSTITIALS` policy flags content for a warning screen, but the `DROP_AFTER_INTERSTITIAL` policy subsequently matches a drop rule, the final verdict becomes **DROP**. This ensures that the most restrictive applicable rule always governs the outcome.

### Where are the NSFW detection rules defined in the codebase?

NSFW-related rules are defined as `RuleSpec` constants in [`visibility-filtering/rules/tweet_rules.rs`](https://github.com/xai-org/x-algorithm/blob/main/visibility-filtering/rules/tweet_rules.rs), including `NSFW_MEDIA_INTERSTITIALS`, `NSFW_AUTHOR_INTERSTITIAL`, `NSFW_MEDIA_DROP`, and `NSFW_AUTHOR_DROP`. These rules inspect the `TestContext` for safety labels applied during the hydration phase, checking both media content and author metadata to determine appropriate visibility restrictions.

### Can the visibility-filtering rules be customized or extended?

Yes, the architecture uses declarative `RuleSpec` structures aggregated in static arrays within [`visibility-filtering/rules/registry.rs`](https://github.com/xai-org/x-algorithm/blob/main/visibility-filtering/rules/registry.rs). Developers can extend the system by adding new rule specifications to [`tweet_rules.rs`](https://github.com/xai-org/x-algorithm/blob/main/tweet_rules.rs) and including them in either the `INTERSTITIAL_ROWS` or `DROP_AFTER_INTERSTITIAL_ROWS` arrays. The `Policy::evaluate` method automatically incorporates new rules into the evaluation pipeline without requiring changes to the core filtering logic in [`filter.rs`](https://github.com/xai-org/x-algorithm/blob/main/filter.rs).