# How the Representation Scorer (RSX) Manages and Serves SimClusters Embeddings for Scoring

> Learn how the Representation Scorer RSX system manages SimClusters embeddings and serves similarity scores through on-the-fly pair-embedding computations in Twitters algorithm.

- Repository: [X (fka Twitter)/the-algorithm](https://github.com/twitter/the-algorithm)
- Tags: how-to-guide
- Published: 2026-03-03

---

**The Representation Scorer (RSX) is a StratoFed service that manages SimClusters embeddings through a unified, decider-gated façade and serves similarity scores via on-the-fly pair-embedding computations.**

The RSX system in Twitter's open-source algorithm repository centralizes access to SimClusters embeddings—dense vector representations of users, tweets, and topics—behind a robust serving layer. This architecture enables low-latency scoring for arbitrary entity pairs (User↔Tweet, Tweet↔Tweet) while providing runtime configurability through feature gates and timeout controls.

## Architecture Overview

The RSX embedding management pipeline operates across three distinct layers:

1. **Embedding ingestion and storage** – Unifies legacy Representation Manager Service (RMS) stores under a single routing façade
2. **Embedding retrieval and gating** – Applies decider-based feature flags and latency timeouts
3. **Scoring pipelines** – Computes similarity metrics on-demand via pair-embedding stores

## Embedding Ingestion and Storage

### The Unified SimClustersEmbeddingStore

At the foundation of RSX lies the `SimClustersEmbeddingStore`, defined in [`src/scala/com/twitter/simclusters_v2/stores/SimClustersEmbeddingStore.scala`](https://github.com/twitter/the-algorithm/blob/main/src/scala/com/twitter/simclusters_v2/stores/SimClustersEmbeddingStore.scala). This component acts as a router that maps `(EmbeddingType, ModelVersion)` tuples to specific underlying storage implementations.

The `EmbeddingStoreModule` in [`representation-scorer/server/src/main/scala/com/twitter/representationscorer/modules/EmbeddingStoreModule.scala`](https://github.com/twitter/the-algorithm/blob/main/representation-scorer/server/src/main/scala/com/twitter/representationscorer/modules/EmbeddingStoreModule.scala) constructs this mapping using a legacy RMS client (`LegacyRMS`). Each entry points to a concrete store implementation handling specific entity types:

- Tweet-based embeddings
- User-interested-in embeddings  
- Author embeddings
- Topic embeddings

### Legacy RMS Integration

The system maintains backward compatibility by wrapping the legacy Representation Manager Service. The `EmbeddingStoreModule` injects the `LegacyRMS` client and constructs a `Map[(EmbeddingType, ModelVersion), ReadableStore[SimClustersEmbeddingId, SimClustersEmbedding]]` that routes requests to the appropriate legacy backend based on the embedding identifier's type and version parameters.

## Embedding Retrieval and Gating

### Decider-Based Feature Gating

The unified store is wrapped in a `DeciderableReadableStore`, enabling runtime feature gating. As implemented in `SimClustersEmbeddingStore.buildWithDecider`, each underlying store can be toggled via decider keys following the pattern `enable_<EmbeddingType>_<ModelVersion>`.

The decider constants are defined in [`representation-scorer/server/src/main/scala/com/twitter/representationscorer/common/DeciderConstants.scala`](https://github.com/twitter/the-algorithm/blob/main/representation-scorer/server/src/main/scala/com/twitter/representationscorer/common/DeciderConstants.scala). When a decider is disabled, the store short-circuits to `Future.None`, preventing unnecessary downstream calls and allowing for graceful degradation during incidents.

### Timeout and Observability Wrappers

The `EmbeddingStoreModule` further wraps the decider-gated store in `ReadableStoreWithTimeout`, controlled by the deciders `enable_sim_clusters_embedding_store_timeouts` and `sim_clusters_embedding_store_timeout_value_millis`. This adds hard latency bounds to embedding retrieval operations.

Finally, an `ObservedReadableStore` wraps the entire chain, injecting Finagle `StatsReceiver` instrumentation to emit metrics on latency, success rates, and cache hit ratios.

## Scoring Pipelines

### Pair-Embedding Similarity Stores

The `ScoreStore` class in [`representation-scorer/server/src/main/scala/com/twitter/representationscorer/scorestore/ScoreStore.scala`](https://github.com/twitter/the-algorithm/blob/main/representation-scorer/server/src/main/scala/com/twitter/representationscorer/scorestore/ScoreStore.scala) receives the unified embedding store via dependency injection. It constructs a family of **pair-embedding** stores using `SimClustersEmbeddingPairScoreStore.build*` methods.

Each pair-embedding store implements `ReadableStore[SimClustersEmbeddingPairScoreId, Score]` and supports multiple similarity metrics:

- **Cosine similarity**
- **Dot product**
- **Jaccard similarity**
- **Euclidean distance**
- **Manhattan distance**
- **Log-cosine** (logarithmically scaled cosine)
- **Exp-scaled cosine** (exponentially scaled cosine)

These stores operate lazily: when queried, they fetch both embeddings from the unified `SimClustersEmbeddingStore`, compute the requested similarity function, and return the resulting `Score` object.

### The ScoreFacadeStore Interface

Individual pair-embedding stores are aggregated into a `ScoreFacadeStore` exposed as `uniformScoringStore`. This façade maps a `ScoreId`—which encodes the algorithm type, source entity, and target entity—to a `Score`.

A `StitchOfReadableStore` wrapper (`uniformScoringStoreStitch`) exposes this as a Stitch RPC interface, enabling efficient concurrent request handling. The `Scorer` class in [`representation-scorer/server/src/main/scala/com/twitter/representationscorer/twistlyfeatures/Scorer.scala`](https://github.com/twitter/the-algorithm/blob/main/representation-scorer/server/src/main/scala/com/twitter/representationscorer/twistlyfeatures/Scorer.scala) invokes this interface when answering RPC calls.

## Runtime Execution Flow

When a downstream service (e.g., Tweet-Mixer) requests RSX scores for a user-tweet pair, the following sequence executes:

1. **Request ingestion** – The `Scorer` class receives the request and fetches recent engagement signals from the User-Signal-Service (USS).

2. **Score ID construction** – For each tweet, the Scorer builds a `ScoreId` identifying the desired algorithm (e.g., `PairEmbeddingCosineSimilarity`) and the two `SimClustersEmbeddingId`s (source user, target tweet).

3. **Facade routing** – `uniformScoringStoreStitch` routes the request to the appropriate pair-embedding store within `ScoreFacadeStore`.

4. **Embedding retrieval** – The pair-embedding store queries `SimClustersEmbeddingStore`, which:
   - Selects the correct underlying store based on `embeddingType` and `modelVersion`
   - Checks the decider gate (`enable_<type>_<version>`); if disabled, returns `Future.None`
   - Applies the timeout wrapper if `enable_sim_clusters_embedding_store_timeouts` is true
   - Returns the `SimClustersEmbedding` vector

5. **Similarity computation** – With both embeddings retrieved, the store computes the requested similarity metric (cosine, dot-product, etc.) and returns the `Score`.

6. **Response aggregation** – The Scorer merges raw similarity scores with USS engagement counts to compute `SimClustersRecentEngagementSimilarities`, returned to the caller.

All stages emit Finagle metrics via `ObservedReadableStore` wrappers, enabling monitoring of latency distributions, success rates, and decider states.

## Implementation Examples

The following patterns demonstrate how to interact with the RSX embedding and scoring infrastructure:

```scala
// Obtain the unified embedding store via Guice injection
@Singleton
class MyComponent @Inject() (
  embeddingStore: ReadableStore[SimClustersEmbeddingId, SimClustersEmbedding]
) {
  // Fetch a single embedding (subject to decider/timeout controls)
  def getEmbedding(id: SimClustersEmbeddingId): Future[Option[SimClustersEmbedding]] =
    embeddingStore.get(id)
}

```

```scala
// Build a cosine-similarity pair-embedding store (as implemented in ScoreStore)
val cosineStore: ReadableStore[SimClustersEmbeddingPairScoreId, Score] =
  SimClustersEmbeddingPairScoreStore
    .buildCosineSimilarityStore(embeddingStore)   // Lazily fetches both embeddings
    .toThriftStore

```

```scala
// Use the public Stitch façade to score a tweet-tweet pair
val scoreId = ScoreId(
  algorithm = ScoringAlgorithm.PairEmbeddingCosineSimilarity,
  embeddingPair = SimClustersEmbeddingPairScoreId(
    source = SimClustersEmbeddingId(embeddingType = LogFavBasedTweet, modelVersion = Model20m145k2020, internalId = InternalId(12345L)),
    target = SimClustersEmbeddingId(embeddingType = LogFavBasedTweet, modelVersion = Model20m145k2020, internalId = InternalId(67890L))
  )
)

val scoreStitch: Stitch[Score] = scoreStore.uniformScoringStoreStitch(scoreId)

```

```scala
// High-level Scorer usage (simplified)
val rsxResult = scorer
  .get(userId = 111L, tweetIds = Seq(222L, 333L)) // Returns SimClustersRecentEngagementSimilarities

```

## Summary

- **RSX** is a StratoFed service that computes similarity scores for entity pairs using **SimClusters embeddings**.
- The **SimClustersEmbeddingStore** acts as a unified routing layer, selecting the appropriate legacy RMS store based on `(EmbeddingType, ModelVersion)` tuples.
- **DeciderableReadableStore** wrappers enable runtime feature gating via decider keys (`enable_<type>_<version>`), while **ReadableStoreWithTimeout** adds latency bounding.
- **SimClustersEmbeddingPairScoreStore** implementations compute similarities (cosine, dot-product, Jaccard, Euclidean, Manhattan, log-cosine, exp-scaled cosine) on-demand by fetching embeddings through the unified store.
- The **ScoreFacadeStore** (`uniformScoringStore`) aggregates all pair-embedding stores and exposes them via a **Stitch** RPC interface for efficient concurrent access.
- The **Scorer** class consumes these raw scores and merges them with User-Signal-Service (USS) engagement data to produce final similarity metrics.

## Frequently Asked Questions

### How does RSX handle embedding store failures or high latency?

RSX implements multiple resilience mechanisms. The `DeciderableReadableStore` wrapper allows operators to disable specific embedding types or model versions via decider keys (e.g., `enable_LogFavBasedTweet_Model20m145k2020`) when degradation is detected. Additionally, `ReadableStoreWithTimeout` enforces hard latency bounds configured via `sim_clusters_embedding_store_timeout_value_millis`. When timeouts occur or deciders are disabled, the store returns `Future.None`, allowing the Scorer to fall back to default score values or omit the signal gracefully.

### What similarity metrics does RSX support for SimClusters embeddings?

RSX supports eight distinct similarity calculations through `SimClustersEmbeddingPairScoreStore` builders: **cosine similarity**, **dot product**, **Jaccard similarity**, **Euclidean distance**, **Manhattan distance**, **log-cosine** (logarithmically scaled cosine), and **exp-scaled cosine** (exponentially scaled cosine). Each metric is implemented as a separate `ReadableStore[SimClustersEmbeddingPairScoreId, Score]`, allowing the `ScoreFacadeStore` to route requests to the appropriate algorithm based on the `ScoringAlgorithm` enum value in the request's `ScoreId`.

### How are SimClusters embeddings routed to the correct storage backend?

The `SimClustersEmbeddingStore` in [`src/scala/com/twitter/simclusters_v2/stores/SimClustersEmbeddingStore.scala`](https://github.com/twitter/the-algorithm/blob/main/src/scala/com/twitter/simclusters_v2/stores/SimClustersEmbeddingStore.scala) implements a routing layer that maps `(EmbeddingType, ModelVersion)` tuples to specific underlying storage implementations. When `EmbeddingStoreModule` initializes the system, it constructs a `Map` where keys are embedding type/version combinations and values are `ReadableStore` instances backed by the legacy Representation Manager Service (RMS) client. At runtime, the façade inspects the `SimClustersEmbeddingId`, extracts the `embeddingType` (e.g., `LogFavBasedTweet`, `UserInterestedIn`) and `modelVersion` (e.g., `Model20m145k2020`), and routes the request to the corresponding legacy store.

### What is the role of the Stitch RPC interface in RSX scoring?

The Stitch RPC interface, exposed via `uniformScoringStoreStitch` in [`ScoreStore.scala`](https://github.com/twitter/the-algorithm/blob/main/ScoreStore.scala), provides a high-performance, concurrent access layer to the scoring infrastructure. Stitch is Twitter's RPC framework that allows for efficient asynchronous composition of requests. The `StitchOfReadableStore` wrapper converts the `ScoreFacadeStore` (a `ReadableStore[ScoreId, Score]`) into a `Stitch` interface that the `Scorer` class invokes. This enables the `Scorer` to batch and parallelize score lookups for multiple tweet-user pairs while maintaining low latency and backpressure handling, which is critical for serving the high-throughput demands of Twitter's recommendation pipeline.