Day 5 — The Codex Key: Defining a Game Record
Name the thing correctly, and the Sanctum stops arguing with itself.
What we set out to build
Today was about identity—not UI identity, but data identity.
A launcher can scan ten different places and “find” the same game five different ways. If we don’t define what a game record is, then everything downstream becomes haunted:
- duplicates in the library
- status changes attaching to the wrong entry
- play sessions drifting away from the right title
- IGDB enrichment binding to the wrong thing
So the goal was simple: define the minimum set of fields that makes a game real in the Codex, and make it stable enough that scanning can improve over time without shattering the library.
What shipped today
✅ Codified the game record’s “spine”: the fields we treat as identity vs. fields we treat as display.
- Display:
display_name,normalized_name - Identity-ish:
launcher_type,steam_app_id(when available) - Launch surface:
executable_path,launch_args,install_dir - State:
is_installed,install_source,backlog_status - Time anchors:
last_detected_at,created_at,updated_at
✅ Committed to a practical identity hierarchy (what we trust most when deduping):
- Steam AppID (when present)
- Executable path for non-Steam installs
- Install dir + normalized name as a fallback, when paths are ambiguous
✅ Clarified the long-term contract: scanning can get smarter later, but it must upsert into the same identity key rather than generating “new games” every time we learn a better detection hint.
Behind the curtain
Here’s the real design choice: we don’t want “a game” to mean “a scan result.”
A scan result is noisy. A game record should be durable.
So we split the mental model into two layers:
- Detection facts (volatile): where we found it, what path was discovered, whether it looks installed, last detected time
- Codex identity (durable): the record that holds your status, your favorites, your play history, and eventually your art/metadata bindings
That’s why we keep both display_name and normalized_name. The display name is what humans see; the normalized name is how the Codex keeps its footing when punctuation, edition text, or launcher naming weirdness changes.
And we treat Steam specially for one reason: Steam already did the hard work of assigning a stable ID. If we have steam_app_id, we should use it as the strongest anchor because it won’t change when the install directory moves, or when a user renames a shortcut.
Rough edges / dragons
- Non-Steam ambiguity is real. Two different editions can share a folder name, or a launcher can tuck executables into odd subfolders. When we lack a platform ID, we’re always balancing false merges vs. duplicate records.
- Paths can change. External drives, library moves, reinstalls—identity can’t be only a path, even if paths are currently our most practical anchor for many launchers.
- Normalized naming is a razor. Too aggressive and we collapse distinct games into one. Too conservative and we fail to dedupe obvious duplicates. This will need careful iteration as the library grows.
Next on the path
Next we step deeper into the Sanctum Scanner: what sources we consider fair and stable, what we refuse to touch, and how we keep detection legal, predictable, and non-invasive.
The Codex now knows what a “game” is. Tomorrow we teach it how to find them without waking the watchdogs.
