The Title Was in the Embedding
A user noticed that combining with Rust kept returning games with “Rust” in the name. That turned out to be one visible symptom of a much broader problem: the vectors encoded what a game was called alongside what it was.
Game Combiner represents every game as a 1024-dimensional vector built from its text. Combine two games and we take the midpoint, then look for real games near it. The whole thing rests on those vectors meaning something.
The document we embedded looked like this:
def doc_for(name, genres, tags_json, short, desc):
...
parts = [name] # ← the game's title, first paragraph
meta = ["Genres: ...", "Tags: ..."]
body = description
The title went in first, as its own paragraph. Which means a chunk of every vector's meaning was the literal string of the name.
How it showed up
The clearest evidence came from asking a simple question: what are Minecraft's nearest neighbours in vector space? If the embedding captures gameplay, the answer should be crafting and building games.
0.891 Minecraft: PlayStation 3 Edition
0.812 Minecraft
0.798 Minecraft: Nintendo Switch Edition
0.759 Minecraft: Playstation Vita Edition
0.751 Minecraft: New Nintendo 3DS Edition
0.748 Minecraft: PlayStation 4 Edition
0.732 Minecraft: Xbox 360 Edition
0.708 Minecraft: Xbox One Edition
Eight out of eight are the same game on different consoles. The vector had learned "this is called Minecraft," not "this is a voxel sandbox." For contrast, No Man's Sky — whose entry came from a source with proper descriptive tags — had neighbours like Stars End, Endless Sky and Cubic Odyssey. Actual space games.
Testing before committing
Removing the title means re-embedding the entire catalog, which is an hour of GPU time and a full redeploy. Worth checking the hypothesis first on a handful of games rather than assuming.
We embedded the same four games twice, once with the title and once without, and compared:
| Candidate | sim to NMS | sim to Minecraft |
|---|---|---|
| Cubic Odyssey, with title | 0.713 | 0.502 |
| Cubic Odyssey, without title | 0.770 | 0.513 |
Dropping the name moved Cubic Odyssey's similarity to No Man's Sky from 0.713 to 0.770 — a real sharpening of the gameplay signal, measured before spending the GPU hour.
It's worth being honest that this did not flip the result that prompted the investigation. Cubic Odyssey still lost, because the deciding factor was the Minecraft side, and that was a separate defect about tag quality. Two problems wearing one coat.
The fix, and the part we kept
parts = [] # title no longer embedded
if genres: parts.append(f"Genres: {genres}.")
if tag_str: parts.append(f"Tags: {tag_str}.")
if body: parts.append(body[:6000])
The name argument stays in the function signature, because callers pass
positionally and because same-series suppression is handled separately — by comparing
titles at scoring time, not by hoping the embedding does it implicitly. That distinction matters:
title similarity is a real signal for "these are the same series," and a bad one for "these play
alike." Keeping them in separate mechanisms means each can be tuned without disturbing the other.
Why it was so easy to miss
Including the title feels obviously correct. It's the most identifying text a game has, and in a search index it would be the single most valuable field. The trap is that Game Combiner isn't search. Nobody types a name and expects that game back — they drop two games in and expect a third that plays like both.
For that job, the name is pure noise, and worse, it's confident noise: titles in the same series share tokens, so the model gets a strong, consistent, entirely irrelevant signal that clusters ports and sequels together and crowds out the games that actually belong.
The general lesson is dull but keeps proving itself: a field being informative in principle doesn't make it informative for your task. The way to find out is to look at what the neighbours actually are.