# V2 String ID System

This document defines the stable string ID system for all player-facing text in
`TODOS.phase-72.72.11.1.1`. It is the naming contract used by source content,
Unreal string tables, translation management systems, voice-over scripts,
screenshots, QA automation, and runtime lookup.

## Canonical Format

Canonical runtime IDs use lowercase ASCII, dot-separated hierarchy, and a
required `loc.` root:

```text
loc.<domain>.<feature_or_asset>.<role>[.<variant>]
```

The canonical regular expression is:

```text
^loc\.(?:ui|hud|quest|npc|dialogue|item|combat|mode|tutorial|system|store|liveops|accessibility|privacy|error|region|audio|online)(?:\.[a-z0-9][a-z0-9_-]*){2,}$
```

Authoring tools may display a short alias such as `quest.main_01.title`, but the
source-of-truth ID stored in content and exported to localization is always the
canonical `loc.quest.main_01.title` form.

## Reserved Domains

Reserved domain prefixes keep IDs predictable across content teams:

| Prefix              | Owner             | Scope                                                       |
| ------------------- | ----------------- | ----------------------------------------------------------- |
| `loc.ui`            | UI                | menus, settings, buttons, modals, option labels             |
| `loc.hud`           | UI                | HUD counters, trackers, combat prompts, notification chrome |
| `loc.quest`         | Narrative         | quest titles, objective text, rewards, quest summaries      |
| `loc.npc`           | Narrative         | NPC barks, greetings, shopkeeper text, ambient chatter      |
| `loc.dialogue`      | Narrative         | authored dialogue lines, choices, subtitles, speaker labels |
| `loc.item`          | Gameplay          | item names, item descriptions, rarity copy, crafting copy   |
| `loc.combat`        | Gameplay          | move lists, tutorial prompts, combat system warnings        |
| `loc.mode`          | Gameplay          | mode names, rules summaries, matchmaking states             |
| `loc.tutorial`      | UX                | lessons, hints, onboarding steps, controller guidance       |
| `loc.system`        | Online            | network errors, save prompts, platform notices              |
| `loc.store`         | Commerce          | storefront labels, bundle copy, purchase confirmations      |
| `loc.liveops`       | Live Operations   | event news, MOTD, battle pass, compensation notices         |
| `loc.accessibility` | Accessibility     | accessibility settings, screen-reader labels, captions      |
| `loc.privacy`       | Privacy and Legal | consent, telemetry, data export, privacy notices            |
| `loc.error`         | Online            | recoverable and fatal error titles, details, actions        |
| `loc.region`        | Legal             | regional content notices and rating acknowledgements        |
| `loc.audio`         | Audio             | VO slate text, announcer callouts, subtitle-only audio text |
| `loc.online`        | Online            | party, lobby, ranked, replay, and anti-cheat text           |

New top-level domains require localization lead approval and a registry update.
Subdomains can be added by the owning team when they stay within the canonical
regular expression and do not collide with another team.

## Required Metadata

Every string ID entry must carry:

- `id`: canonical `loc.*` ID.
- `tmsAlias`: short alias without the `loc.` root for vendor tools.
- `owner`: owning discipline or feature team.
- `textRole`: semantic role such as `title`, `body`, `button`, `subtitle`,
  `choice`, `toast`, `error`, or `screen_reader_label`.
- `sourceLocale`: normally `en-US`.
- `context`: translator-facing description of where the text appears.
- `maxLength`: UI budget when the string is layout constrained.
- `screenshotRef`: stable screenshot or capture reference when available.
- `variables`: named variable list if the string is formatted dynamically.
- `status`: `reserved`, `active`, `deprecated`, or `blocked`.

IDs must be stable across wording changes. Do not include source-language copy,
locale code, punctuation, build numbers, branch names, or actor names that can
change. Use semantic roles instead: `loc.ui.menu.options` is stable;
`loc.ui.menu.open_options_button_text` is too close to English copy and should
be avoided.

## Examples

Canonical examples:

- `loc.quest.main_01.title`
- `loc.ui.menu.options`
- `loc.npc.blacksmith.greeting`
- `loc.item.weapon.ash_saber.name`
- `loc.dialogue.asha.market_intro.line_001`
- `loc.system.network.disconnected.title`
- `loc.store.bundle.fighter_pack_01.cta`
- `loc.accessibility.subtitle.speaker_label`
- `loc.privacy.telemetry.opt_out.body`
- `loc.online.ranked.queue_estimate.body`

These IDs demonstrate hierarchical ownership, asset-level grouping, and role
suffixes without embedding source copy.

## Runtime Rules

Runtime systems resolve player-facing text by canonical ID. Inline text is
allowed only in test fixtures, editor-only debugging, or non-player-facing
developer diagnostics. Shipping UI, dialogue, items, mode names, errors,
notifications, store copy, accessibility strings, and privacy notices must use
registered canonical IDs.

Feature-specific content can keep local fields such as `NameTextId`,
`DescriptionTextId`, `SourceStringId`, or `FormatStringId`, but those fields
must contain canonical `loc.*` IDs. Dynamic insertion uses named variables and
must never concatenate translated fragments at runtime.

## Migration Policy

Existing legacy Unreal string table keys such as `Menu.Play` are treated as
source-table keys until their owning content is migrated. New phase-72
localization work must author canonical `loc.*` IDs first, then emit any legacy
table key as a derived compatibility alias.

The registry at
`V2/ue/Content/Localization/V2/StringTables/StringIdRegistry_V2.json` owns the
reserved prefixes and seed examples. The contract at
`V2/ue/Content/Localization/V2/StringIdSystem_V2_Contract.json` defines the
policy CI validates.

## Verification

Run the focused checker after changing the string ID contract, registry, docs,
or CI wiring:

```bash
python3 V2/ue/Tools/check-v2-string-id-system.py
```

Required release gates:

- `localization-string-id-system-doc-present`
- `localization-string-id-system-registry-schema`
- `localization-string-id-system-canonical-pattern`
- `localization-string-id-system-domain-prefixes`
- `localization-string-id-system-sample-ids`
- `localization-string-id-system-ci-wired`
