# Platform, Accessibility, Localization & Production

```mermaid
flowchart TB
  Feature[Versioned gameplay and content candidate] --> Age[Age parental and time-played policy]
  Feature --> A11y[Input visual audio cognitive and motion accessibility]
  Feature --> Locale[Strings VO fonts layout ratings and regional variants]
  Age --> Build[Platform build cook and package]
  A11y --> Build
  Locale --> Build
  Build --> Cert[Automated budgets and platform certification]
  Cert --> Region[Eligible platform region and account cohort]
  Region --> Observe[Telemetry support incident and rollback evidence]
```

Accessibility, localization, account policy, and certification are inputs to the
build and rollout—not documentation added after gameplay is complete. Each
supported platform and locale earns its applicable evidence.

A fighting game ships in front of three audiences a marketing page never
mentions: the platform cert reviewer who can refuse to publish, the regulator
who can fine, and the parent who controls the account. V2 treats all three as
first-class engineering, not paperwork bolted on at the end. This page covers
the cluster that makes V2 _shippable and lawful in every territory it launches
in_ — the **parental-controls / age-gating / time-played** feature set, the
**accessibility** surface, the **localization, voice-over, and region-rating**
pipeline, and the **production / platform-compliance** layer that wraps them.
The unusual thing about V2's implementation, as everywhere in this codebase, is
how much of it is _real, validated Unreal C++ and TypeScript_ rather than a
policy PDF: parental controls are a self-validating `USTRUCT` feature set with a
contract spec, the 22-locale launch catalogue is built in code, the eight region
SKUs are real data assets asserted at boot, and the compliance obligations that
_are_ genuinely policy (the rating-board matrix, the cert checklists) compose
shared Oshun / Aphrodite / Themis services rather than being re-invented. Where
a piece is a documented obligation or a provider-gated seam, this page says so
in code. The section hub is [../V2_features.md](../V2_features.md).

## What ships, honestly

The boundary between "shipped and tested" and "documented obligation" runs
cleanly through this cluster.

- **Parental controls are a validated C++ feature set.**
  `FV2ParentalControlsFeatureSet` (`V2OnlineServicesTypes.h:10619`) bundles five
  sub-configs — age-gate policy, parental dashboard, time-played reports,
  spending limits, legal disclosures — each with its own `IsValidConfig`, built
  by `BuildDefaultParentalControlsFeatureSet()`
  (`V2OnlineServicesBlueprintLibrary.cpp:10068`) and pinned by the spec
  `V2.Online.ParentalControls.AssetContract` (§68), which asserts the _negative_
  case: removing the `US.COPPA` profile fails validation.
- **Localization is real C++ data, not just strings.**
  `FV2LocalizationVoiceOverFeatureSet` enumerates **22 launch-locale configs**
  (`BuildDefaultLocalizationVoiceOverFeatureSet`, `V2UIConfigAsset.cpp:4868`)
  and is validated in the `V2.UI.Module` spec. The `V2/loc/` workspace directory
  the repository surfaces table lists is **planned — not yet created**; the
  canonical localization data lives in C++ plus the `Content/Localization/V2/`
  contract layer.
- **Region rating variants are real data assets, asserted at boot.** Eight
  `DA_RegionVariant_*.uasset` files exist under `V2/ue/Content/V2/Regions/`, and
  `UV2RegionVariantBootSubsystem::EvaluateBootAssert()` refuses a build whose
  staged SKU stamp does not match the loaded variant (§54.2).
- **Accessibility is a first-class, tested surface** — covered in depth by the
  architecture companion
  [../architecture/ui-hud-vr-ar-and-accessibility.md](../architecture/ui-hud-vr-ar-and-accessibility.md);
  this page summarizes its player-facing shape and the one rule that governs it.
- **The compliance _seams_ are coded; the _obligations_ are documented.** Age
  verification, consent, and PII handling compose `@aphrodite/*`, `@themis/*`,
  and `@oshun/*` through thin `apps/v2/` surfaces; the rating-board matrix, the
  per-region SLAs, the DRM removal-plan window, and the platform TRC/XR/lotcheck
  checklists are cert obligations those seams satisfy. See
  [../architecture/security-compliance-and-sister-monorepo-integration.md](../architecture/security-compliance-and-sister-monorepo-integration.md).

## Parental controls, age gating & time-played (§68)

### One feature set, five configs, one validator

The whole parental surface hangs off `FV2ParentalControlsFeatureSet`, whose
`IsValidFeatureSet()` (`V2OnlineServicesTypes.cpp:10601`) requires a stable
`FeatureSetId == "ParentalControls.V2"` and then delegates to all five
sub-validators — a single failure anywhere fails the set. The build-default is
concrete data, not a flag soup, and the spec reads the runtime values back.

### Age gating per region law

`FV2AgeGatePolicyConfig` (`:10438`) carries a `RegionProfiles` array and a
`HasRequiredRegionProfiles()` check that demands **all five** legal regimes be
present — `US.COPPA`, `EU.GDPRK`, `KR.GameRatingBoard`, `CN.MinorStandardSku`,
and `AU.NZ.RatingAck`. The booleans encode the source's region rules exactly:
`bBootTimeAgeConfirmation` (the gate runs at boot),
`bPlatformAccountAgePassThrough` (it trusts the platform account's age first),
`bCoppaUnder13NoChatUgcMatchmakingWithoutConsent`,
`bGdprKUnder16PerMemberState`,
`bKoreaMinorOvernightPlayBlockedWithoutParentApproval`,
`bChinaMinorStandardSkuOnly`, `bChinaIdentityVerificationRequired`, and
`bAustraliaNzRatingAckScreens`. The China minor daily limit is a hard integer:
`ChinaMinorDailyPlayLimitMinutes = 60`, and the validator rejects any value
other than 60, so the one-hour cap can never silently drift. The spec asserts
each of these and then proves the failure path by removing `US.COPPA`.

The runtime _decision_ — what content a given account actually sees — is a
backend concern, and V2 does not hand-roll it. `@v2/aphrodite-age-gate`
(`apps/v2/aphrodite-age-gate/src/`) composes `@aphrodite/age-verification`
through `buildV2AphroditeAgeGateSurface()`: it controls gore tier, adult
fatalities, and region-conditional cinematics (`controlsGoreTier`,
`controlsAdultFatalities`, `controlsRegionConditionalCinematics`), uses the
**mature-game** age-gate profile and explicitly _rejects_ the adult-content
profile (`usesMatureGameAgeGateProfile`, `adultContentAgeGateProfileRejected`),
keeps 2257 / performer-protection workflows out of game content gating, and
hands minor-account decisions to platform family controls
(`parentalControlHandOffRequired`). The Aphrodite brand is never shown to
players, it emits `v2.age-gate.decision.created` /
`v2.content.gore-tier.changed` topics, and it is `mayInfluenceRollback: false` —
a content gate, off the deterministic path. The CI gates
`check-v2-aphrodite-age-gate.py` and `check-v2-age-gate-fitness-audit.py` pin
it.

### The parental dashboard

`FV2ParentalDashboardConfig` (`:10483`) is the PIN-gated control surface. Two
coverage predicates make it real: `HasRequiredPlatformIntegrations()` requires
the four console family systems — `SonyFamilyManagement`,
`MicrosoftFamilySafety`, `NintendoParentalControls`, `SteamFamilyView` — and
`HasRequiredChildControls()` requires all nine toggles the source promises:
`OnlinePlay`, `VoiceChat`, `TextChat`, `UgcVisibility`, `CustomContentDownload`,
`CosmeticShopSpendingLimit`, `DailyPlaytimeLimit`, `WeekendsOnlyMode`, and
`BedtimeAutoShutoff`. On top of those, `bParentPinGated`,
`bPerChildGoreTierMildOffOverride`, and `bPerChildFinisherDisableOverride` let a
parent set per-child gore tier (the
`EV2GoreTier { Off, Mild, Standard, Extreme }` ladder from `V2VFXTypes.h:22`)
and disable finishers for one child without touching another's account.
`check-v2-parental-controls.py` gates the surface.

### Time-played reports

`FV2TimePlayedReportConfig` (`:10511`) is the wellness half. Its
`PlaytimeNudgeAfterConsecutiveHours = 2` is the break-nudge threshold (the
validator rejects a non-positive value), and the booleans build the weekly
report: `bWeeklyPerAccountEmail` and `bInGameDashboard` are the two delivery
channels; `bHoursPerMode`, `bHoursPerFighter`, `bPeakPlaytimeHour`, and
`bComparisonToPriorWeek` are the breakdown; `bParentVisibleForChildAccounts`
exposes a child's report to the parent; and `bOptionalBreakNudgePopup` is the
in-session nudge. This is the same responsible-play posture that
`@v2/lakshmi-responsible-play-spend-insight` carries on the spend side.

### Spending limits and legal disclosure

`FV2SpendingLimitConfig` (`:10549`) sets real default caps on premium currency —
`DefaultDailyPremiumCurrencyCapMinor = 1000`, weekly `5000`, monthly `15000`,
plus a `KoreaMinorDailyPremiumCurrencyCapMinor = 1000` — and the validator
enforces the _ordering_ (daily ≤ weekly ≤ monthly, all positive), so a
misconfigured cascade fails the build. `bParentSetPerChildLimits`,
`bPinGatedLimitChanges`, `bPerRegionMaximumLimits`, and
`bKoreanMinorAccountLimits` cover the parent-set, PIN-gated, per-region, and
Korean-minor rules. `FV2LegalDisclosureConfig` (`:10587`) closes the loop with
the disclosures law requires of a real-money game that deliberately has _no_
loot boxes: `bLootBoxAbsenceStatementInStoreListing` and
`bLootBoxAbsenceStatementInSettings` (the explicit no-surprise-mechanics
statement), `bInGamePurchasesLifetimeSummary` and `…Last30DaysSummary`,
`bPlatformRefundFlow`, `bHealthSafetyWarningScreen`, and
`bPhotosensitivityWarningBundled`. Per-feature data consent — telemetry, voice
processing, behavioural profiling — is a separate seam,
`@v2/aphrodite-consent-surfaces`, which composes `@aphrodite/consent-engine`,
requires consent receipts when a feature is enabled, defaults missing opt-ins to
privacy-preserving fallbacks, and stays off rollback.

## Accessibility

Accessibility is the largest single surface in V2's interface layer, and it is
genuine C++ with WCAG-anchored constants — the colour-blind palette (17
indicator roles × 5 modes, ≥ 4.5:1 contrast), the photosensitivity filter (a
hard 3-flash/ second cap), visual sound indicators, the camera-shake slider, the
screen-reader bridge, reduced motion, high contrast, fonts, text scaling, and
caption streaming. Everything reads from one self-normalizing struct,
`FV2UIAccessibilitySettings` (`V2UITypes.h:9135`), and a 3,894-line
`V2.UI.Module` automation test plus a 61-strong `check-v2-*` Python gate family
verify the _behaviour_, not the existence. Because that whole stack is
documented end-to-end in the architecture companion
[../architecture/ui-hud-vr-ar-and-accessibility.md](../architecture/ui-hud-vr-ar-and-accessibility.md),
this page states only the load-bearing rule and the service ownership.

**The determinism boundary.** Accessibility accommodations are
_presentation-only and must never alter the deterministic simulation_ — V2 is a
rollback-netcode fighter, so a visual setting that changed one frame of hit-stop
would desync a match. The camera-shake slider may only _attenuate_ authored
intensity, never amplify it, and is marked `bTournamentSafe`. The policy that
separates "I changed how the game looks" from "I changed how the game plays" is
`EV2AccessibilityRankedEligibility`: visual accommodations (reduced motion,
colour- blind palette, high contrast) keep ranked eligibility, while motor
_assist macros_ that change outcomes (auto-combo, auto-block/parry/tech, easy
fatalities) flip a per-tier ranked flag and route the player into
assist-eligible queues — the same mechanism the combat and local-co-op pages
describe.

**Service ownership.** Two TypeScript surfaces own the cross-client and
companion side: `@v2/iris-accessibility` composes `@iris/accessibility`
(dyslexia typography, cognitive-load reduction, screen-reader semantics,
native-UE hooks) and declares `certGateBlocksRelease: true` with the event topic
`v2.accessibility.cert-gate.failed` — accessibility failure is a first-class,
release-blocking event. `@v2/psyche-caption-streaming` plans a real-time caption
session across five surfaces (in-match HUD, spectator overlay, replay viewer,
companion second-screen, broadcast observer) with `offRollback: true`. The
documented VPAT-style report lives at `V2/docs/accessibility/`. Live OS
screen-reader announcement (NVDA, JAWS, VoiceOver, TalkBack) is reached through
a real, validated tree-export model whose actual OS-runtime hookup is the
platform integration seam.

## Localization, voice-over & region rating variants (§54.2)

### The launch-locale catalogue, in code

V2's localization is not a `.po` file pile — it is a validated data structure.
`BuildDefaultLocalizationVoiceOverFeatureSet()` (`V2UIConfigAsset.cpp:4868`)
constructs **22 `FV2LaunchLocaleConfig` entries** (`V2UITypes.h:10237`)
representing the source's 18 languages with regional variants split out: English
(US/GB), French (FR/CA), Spanish (ES/419), Portuguese (BR/PT), German, Italian,
Polish, Russian, Turkish, Arabic, Hebrew, Japanese, Korean, Chinese (Hans/Hant),
Thai, Vietnamese, and Indonesian. Each entry carries a `ScriptId` that selects a
real font-fallback chain — `Script.CJK` → `Font.NotoSansCJK`, `Script.Arabic` →
`Font.NotoNaskhArabic`, `Script.Hebrew` → `Font.NotoSansHebrew`, Latin → the
Atkinson/OpenDyslexic-led chain — so a missing glyph never renders as tofu. RTL
locales (Arabic, Hebrew) set `bRtlLayout`, `bRtlUiMirroring`, and
`bRtlFocusNavigationMirroring` together; calendar systems are per-locale
(`Hijri`, `Hebrew`, `JapaneseEra`, `KoreanDangi`, `Buddhist`); and the QA flags
(`bStringLengthCapValidation`, `bTextExpansionQaGate`, `bCulturalReview`,
`bSubtitleTimingQa`, `bVoiceLineLipSyncQa`) record the per-locale pipeline. The
`V2.UI.Module` spec asserts the set `IsCompleteFeatureSet()`, that the
externalized string root is `V2/ue/Content/Localization/V2/`, and that region
variants and the typography/formatting/workflow sub-configs all validate.

### Voice-over plan

`FV2VoiceOverLocalizationPlan` (`V2UITypes.h:10317`) splits the locales by VO
status. **Nine** locales ship per-fighter voice banks at launch
(`LaunchVoiceOverLocaleIds`: en-US, fr-FR, es-ES, pt-BR, de-DE, it-IT, ja-JP,
ko-KR, zh-Hans), guarded by `MinimumLaunchVoiceOverLocaleCount = 8`; the
remaining **13** are `SubtitleOnlyPatchLocaleIds` with
`bRemainingLocalesSubtitleOnlyWithPatchPlan` — the documented VO patch plan from
the source. `bPerFighterVoiceBankAtLaunch`, `bIterationPickupProcess`,
`bPickupSessionDiffsTracked`, and `bLipSyncRetimingPerLocale` model the
composition → recording → pickup → per-locale lip-sync pipeline, and per-fighter
banks hot-swap on patch. Spectator chat and commentary localization at runtime
is a separate, presentation-only service: `@v2/iris-realtime-translation`
composes `@iris/voice` to deliver translated chat, subtitles, and broadcast
overlays — never feeding rollback state.

### Region rating variants and the boot assert

Per-region content rules are stored as `URV2_RegionVariant` data assets — eight
real `.uasset` files under `V2/ue/Content/V2/Regions/`
(`DA_RegionVariant_{US,EU,DE,JP,KR,AU,NZ,BR}.uasset`) — described by
`FV2RegionVariantRule` (`V2UITypes.h:10355`): a `VariantId`, `RegionId`,
`RatingBoardId`, a `BuildPipelineSkuTag`, a `ContentPolicy`, and a
`RequiredContentAdjustments` list. `Tools/stage-region-rating-config.py` writes
the SKU stamp at cook time, and at boot
`UV2RegionVariantBootSubsystem::EvaluateBootAssert()`
(`V2RegionVariantBootSubsystem.cpp:8`) refuses to proceed unless the staged
region and SKU tag match the loaded variant — a German USK-18 build can never
boot wearing the global SKU. The spec `V2.UI.RegionVariantBoot.AssetContract`
pins the expectation table that mirrors `V2/legal/rating-boards.json`: DE
(`SKU.DE.USK18.GoreRestricted`, gore-restricted, fatalities substituted), JP
(`SKU.JP.CEROZ`, dismemberment reduced, X-Ray alternate), KR (`SKU.KR.GRAC19`,
chat filter, loot-box disclosure), AU/NZ (R18 rating-ack screens), and BR
(`SKU.BR.DJCTQ18`, Portuguese-BR VO). Editor/local builds carry no stamp and are
not asserted. A large JSON-contract layer under `Content/Localization/V2/`
(locale-fallback chain, RTL mirroring, CJK layout, plural forms, pseudo-loc,
continuous-localization CI, TTS fallback for missing VO) plus ~30 `check-v2-*`
localization gates back the spec.

## Production & platform compliance

The studio-production story — multi-studio org chart, mocap booking, SAG-AFTRA
compliance, VO casting, composer pipeline, IP/NIL/licensing — is a _documented
obligation_ in the source, but its data plane is real services. The mocap
pipeline ships as `@v2/aja-studio-mocap-pipeline` (Vicon/markerless capture
path) and `@v2/aja-markerless-capture-pipeline`, and every capture clears
consent before ingest through `@v2/aja-consent-nil-ledger`, which wires Aja
capture consent to the Themis NIL ledger — a revocation blocks future processing
for dependent clips. LiveLink export to the engine runs through
`@v2/aja-bellona-livelink-export`. The rights manifest verified at cook (no
asset ships without cleared rights or original-IP status) and the
per-jurisdiction publicity-rights review are the policy obligations these seams
enforce.

Platform certification is where policy becomes a gate.
`FV2PlatformComplianceChecklistPolicy` (§72.21.1.14, built by
`BuildDefaultPlatformComplianceChecklistPolicy()` and pinned by
`V2.Online.PlatformComplianceChecklist.AssetContract`) requires coverage of
PlayStation **TRC**, Xbox **XR**, and Nintendo **lotcheck**, carries machine-
readable evidence records (`bExportsMachineReadableStatus`), and _excludes
proprietary platform text_ (`bExcludesProprietaryPlatformText`) so the checklist
can live in a public repo without leaking NDA'd cert language. The rating-board
matrix (ESRB M, PEGI 18, CERO Z, USK 18, ACB R18+, GRAC, DJCTQ 18, OFLC R18)
lives in `V2/legal/rating-boards.json`, and `check-rating-descriptors.py` /
`check-v2-region-rules.py` gate it. The deeper compliance program —
GDPR/CCPA/DSA data-subject rights, PII strip-at-ingest, per-region residency,
the DRM removal- plan window — composes Oshun/Themis services and is detailed in
the security/ compliance architecture companion and the launch sibling page.

## How it connects

The through-line is the same one the rest of V2 follows: encode the _decision_
in a validated value type, encode the _enforcement_ in a validator and a CI
gate, and compose shared platform services for anything that must resolve
consistently across every Oshun product. Parental controls, the locale
catalogue, and the compliance checklist are all self-validating C++ structs
pinned by contract specs that would fail on a stub; the region SKUs are real
data assets the engine asserts at boot; the age-gate, consent, accessibility,
translation, and mocap-consent surfaces are real TypeScript that compose
`@aphrodite/*`, `@iris/*`, `@psyche/*`, and `@themis/*` and stay off the
rollback path; and the genuinely-policy parts — the cert checklists, the rating
obligations, the studio org chart, the DRM window — are documented and audited
rather than fabricated as code. The section hub is
[../V2_features.md](../V2_features.md).

## Related

- [Racing Crossover, Open World & Ops](./racing-crossover-open-world-and-ops.md)
  — the racing component's parallel accessibility/auto-throttle assists and the
  live- ops surfaces this platform layer wraps
- [Balance Ops, Privacy, Wellness & Launch](./balance-ops-privacy-wellness-and-launch.md)
  — the telemetry/PII program, the responsible-play spend insight, the
  data-subject-rights UI, and the launch-readiness gate
- [Online Services, Network & Tournaments](./online-services-network-and-tournaments.md)
  — the `V2OnlineServices` module the parental-controls and compliance-checklist
  feature sets live in
- [UI / HUD, VR / AR & Accessibility](../architecture/ui-hud-vr-ar-and-accessibility.md)
  — the architecture companion for the full accessibility, settings, and VR/AR
  stack summarized here
- [Security, Compliance & Sister-Monorepo Integration](../architecture/security-compliance-and-sister-monorepo-integration.md)
  — identity, consent, residency, DSR, and the cert-blocking compliance posture
- The section hub: [../V2_features.md](../V2_features.md) </content>
