> For the complete documentation index, see [llms.txt](https://docs.kouch.dev/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.kouch.dev/docs/names_and_keys_plan.md).

# Clean game names, and the art key in Steam Cloud (2026-09-28)

Two owner requests. This plan adds to the others; it doesn't replace them.

## N1 Clean game names, shown automatically

*"automatic cleaning of a game internally, making it not show a 'dirty' rom game, the program automatically rename's the games internally so instead of showing -uwudhc-0.0.0.rom it will show ''"* (the owner named a real game; neutralized here)

* **Display names only. Kouch never renames the user's files.** The file name stays visible in the game page's details.
* **Where a name comes from, best first:**
  1. **The user's own `gamelist.xml`** name, already imported.
  2. **A database match by the file's checksum:** the libretro per-system list Kouch already reads (`metadat.rs`) names each file (`rom ( … crc … )`). The display name is that entry's name without its tag groups (region, revision, language).
  3. **The game's own embedded title,** read by the profile's reader like the title id (G8): a `name` field next to `id`. Examples: a folder game's `meta/meta.xml` long name, or a disc image's header title. Only what the game file itself carries; nothing encrypted is read.
  4. **A database match by name:** the cleaned file-name words are matched against the system's list, and the longest list title that is a prefix of those words wins. That's how `castle-quest-uwudhc-0.0.0` becomes the list's "Castle Quest": the trailing junk token and the version fall away.
  5. **The cleaned file name** when nothing matches:
     * `-`, `_`, `.` and runs of spaces become one space;
     * bracket and paren groups, version tokens (`v1.0`, `1.0.2`, `0.0.0`, `rev 1`), region and language codes and dump flags are dropped;
     * a token made only of hex digits of 6+ characters is dropped;
     * the result is in Title Case, with small words kept lower-case inside.
* **Stored per game:** the display name and where it came from (`title_source`: user list / database / embedded / name match / file name). It's re-derived on every scan, cheaply: a game is re-read only when its file, its profile's reader or its system's list changed. Sort keys and the A–Z rail use the display name.
* **Tests use invented titles only** (ground rule: no game names are committed), e.g. `castle-quest-xk3j9p-1.0.2` → "Castle Quest".
* **Who:**
  * **B:** the library side: cleaning, name match, list match, storage, the re-derive rules, plus `name` in the reader.
  * **C:** `name` readers in the four test profiles, where the game carries one.
  * **A:** the UI: display name everywhere, the file name in details, and the source shown there in small print.
  * **Central:** live checks against the owner's library, read-only, and invented names.

## N2 The SteamGridDB key syncs through Steam Cloud, encrypted (ADR 0021)

*"the steamgriddb api key has to sync encryped with steam cloud"*

* **On this PC:** the key moves out of plain-text `art.json` into the operating system's secret store:
  * Windows: Credential Manager, which is DPAPI-protected;
  * Linux / the Deck: the Secret Service.
  * Where no secret store exists, it goes into a local file encrypted with a machine-bound key.
  * An existing plain key is migrated once and removed from `art.json`.
* **In Steam Cloud:** one small file (`secrets.bin`) through Kouch's Steam Cloud engine (ADR 0013, the API only):
  * encrypted with ChaCha20-Poly1305, the same AEAD `kouch-lan` already uses;
  * under a key derived with HKDF from the Steam account id and a Kouch-held value, so it's bound to that Steam account;
  * it decrypts only for the same account, and a tampered file is rejected.
  * What this protects against, and what it doesn't, is recorded in ADR 0021.
* **Behaviour:**
  * Setting or clearing the key on one PC updates the cloud file.
  * A new PC signed into the same Steam account picks the key up at start and stores it locally.
  * A different account never sees it.
* **Never included:** the key never appears in logs, reports, `.kod` exports, LAN transfers or the UI (the UI only ever sees "key set").
* **Live test:** needs Kouch's own app id, like all of Steam Cloud. Until then: unit tests for the round trip, a wrong account, a tampered file and the migration, plus the engine's local mode.
* **Who:** B (Rust), A (Settings › Game art shows "Synced with Steam Cloud"), central (the ADR, reviews and the live test once the app id exists).

## N3 Stand-in covers seeded by the game itself

*"the stand in gui for the library needs to be different sizes depending on the game file size … or be random, whichever looks better … but if someone else has the same rom it needs to look the same way … like a hash and it does a specific pattern"*

* **The seed.** A game with no art gets a generated cover drawn from `Game.art_seed`, a key taken from the game itself, so the same file looks the same for everyone. In order of preference:
  1. the title id, per system;
  2. a checksum Kouch already knows;
  3. SHA-256 over the file size plus the file's first and last 64 KiB.
* **Never from where the file sits:** the seed never comes from the path, the file name or a row id.
* **The cover.** A seeded generator decides the pattern, the shapes' count, sizes and positions, and the palette (theme tokens, Black and White). Card dimensions stay the same, so the grid stays aligned.
* **Who:**
  * B: the seed.
  * A: the generator.
  * Central: checks that two copies of one file draw the same cover on Windows and the Deck.

## Status

| Part                      | Status                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
| ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| N1 clean names            | **done, verified live 2026-09-28** with the owner's library read-only (counts only): contract `667896b`; library `0029fd0`, `0e599ae`, `e116422` (B); readers `974bb30` (C); UI `38e22a6` (A). Of 135 real games, the disc system (42/42), the handheld system (34/34) and the folder-game system (11/11) are named from the game files themselves. The encrypted system's 48 come from their already-clean file names. The disc system's list (fetched, logged) names the same games when no embedded name exists. |
| N2 key in Steam Cloud     | **done**, B `8b6cccf`, `5ff11f6`, `a1be443`; A `38e22a6`. Verified live on Windows with the owner's key in an isolated config: stored only in Credential Manager under that config's own entry, in no file or log; SteamGridDB pictures offered in every Change artwork slot; clearing leaves nothing behind. The Steam Cloud half waits for Kouch's own app id.                                                                                                                                                    |
| N3 seeded stand-in covers | assigned 2026-09-28: B (`art_seed`), A (the generator)                                                                                                                                                                                                                                                                                                                                                                                                                                                              |


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.kouch.dev/docs/names_and_keys_plan.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
