# Accessibility, Security & Compliance

V5 is one UE5 open-world narrative universe split into six ruleset cells — a
1947-noir **Urban** cell, a Prohibition-era **Period** cell, an 1899
**Frontier**, a Witcher-flavoured **Hunter** cell, a hard-SF **Sci-Fi** cell,
and the cross-cell **Mind Palace** — shipped age-rated, online, and cross-play
across nine day-one platforms. That shape makes accessibility, security, and
compliance not a feature backlog but a **launch precondition**: a platform
holder refuses a build over a missing data-safety form or an unsubmitted
accessibility matrix; a regulator fines over a deletion that fails to cascade or
a moderation action with no statement of reasons; a ranked Sci-Fi ladder rots
the day skill-cheating goes unanswered. This page documents the surface where
all three meet.

The defining architectural choice is the same one V4 made and V5 inherits: **the
enforcement seams live inside the game.** Where V2 and V3 reach sideways into
the sister monorepos and _compose_ the shared `@oshun`, `@themis`, and
`@aphrodite` privacy packages, V5 **reimplements** the accessibility model,
residency, data-subject rights, age-gating, DSA moderation, and anti-cheat as
real Unreal C++ modules (`V5Accessibility`, `V5Compliance`) and a NestJS/Fastify
service tier (`apps/v5/compliance-dsar`, `apps/v5/anti-cheat`) over a shared
runtime, each backed by JSON policy manifests under `V5/legal/` and
`V5/security/`. A repository-wide search finds **zero** V5 imports of
`@oshun/*`, `@themis/*`, or `@aphrodite/*` — so those packages are _not_ this
product's compliance root, and this page says so up front rather than implying a
cross-product wiring that does not exist. The section hub is
[../V5_ARCHITECTURE.md](../V5_ARCHITECTURE.md).

## What ships, honestly

The **two Unreal modules are real, domain-specific code**, not policy stubs.
`V5/ue/Source/V5Compliance/Private/V5ComplianceSystems.cpp` (282 lines) resolves
per-jurisdiction residency, builds 30-day DSAR cases with a computed due date,
cascades an under-13 age gate, and routes DSA moderation with EU/UK-specific
SLAs; `V5/ue/Source/V5Accessibility/Private/V5AccessibilitySystems.cpp` (392
lines) builds the full settings model — subtitle styling, four color-vision
palettes, a photosensitivity clamp, per-cell difficulty scalars, aim-assist, and
a launch QA suite. Both compile on the on-box UnrealEngine-5.5.4 build: object
files exist under
`V5/ue/Intermediate/Build/Linux/x64/UnrealEditor/Development/V5Compliance/` and
`.../V5Accessibility/`, including the test objects, and both also build under
the `V5ArcadeCabinet` target. Each module carries automation specs
(`V5ComplianceTests.cpp`, `V5AccessibilityTests.cpp`) that assert computed
values — a 30-day SLA resolving to `DueUnixSeconds == 2593000`, a 72-hour EU
moderation SLA, a photosensitivity clamp of `≤ 3` flashes — not mere truthiness.
The service tier is equally real: `compliance-dsar.ts` and `anti-cheat.ts` are
Postgres-backed domain stores, and the detection/DSAR math lives in the shared
`apps/v5/service-shared/src/runtime.ts`.

Two honest qualifications run through everything below. **First, V5 owns no
cooked binary content.** The repository carries **zero** `.uasset` files and
zero binary stand-ins — it is a logic-plus-manifest skeleton, exactly as the
Content Pipeline convention in `V5_ARCHITECTURE.md` describes. The C++ is
compiled and unit-tested, but no cert run, no profiled accessibility
playthrough, and no played day-one build can be evidenced from this repo; those
claims are forward-looking by construction.

**Second, the external accessibility audit was fabricated and then retracted,
and the two sources still disagree.** The C++ `BuildExternalAuditEngagement()`
and the default values in `FV5AccessibilityAuditEngagement` still name an
invented counterparty — "AccessForge Accessibility Audit Cooperative", id
`accessforge-a11y` — with `Status = Engaged` and `bConsultantOnboarded = true`.
The legal source of truth, `V5/legal/accessibility-consultant-engagement.json`,
was **corrected on 2026-06-12** to `status: "not_engaged"`, vendor
`[VENDOR TBD]`, every date and outcome `null`, with an explicit `correctionNote`
that "the previous revision recorded a completed external audit by an invented
counterparty … No external engagement was ever executed." Per
`V5/REMEDIATION_2026-06-12.md`, the stale C++ struct default "must not be read
as evidence that a real engagement happened," the validator that codified it was
made fail-closed, and the corresponding backlog task reverted to `[ ]`. The
**one fact both sources honestly share** is the only one that gates release:
`bSignedAuditReceived = false`. The launch QA suite marks the
`qa.accessibility.external_audit` check `ReleaseBlocked`, and the spec asserts
`TestFalse("Signed audit is not falsely claimed", …)` — so release stays blocked
on a signed report that has not arrived, regardless of the stale vendor
metadata. That divergence is on the record here rather than smoothed over.

## Accessibility

`V5Accessibility` is a UE C++ module of `UBlueprintFunctionLibrary` builders
(`V5/ue/Source/V5Accessibility/`) that author the launch accessibility model as
typed, persistable structs. It is deliberately a settings-and-policy library,
not a renderer: it produces the `FV5Accessibility*` profiles the rest of the
game and UI consume.

### The settings model

The breadth is real and per-feature, and the spec pins the behaviour:

- **Subtitles** — `BuildSubtitleStyle` clamps font scale to `[0.8, 1.6]` and
  border to `[0, 6]`px, applies per-speaker color coding (Player / Companion /
  Radio / SFX), keeps an SFX caption track, and carries a period-radio caption
  flag. The spec asserts the high-end clamps (`1.7 → 1.6`, `8.0 → 6.0`).
- **Color vision** — `BuildPalette` remaps the UI palette and the gameplay-cue
  tags (`cue.threat.*`, `cue.clue_trail.*`, `cue.faction.*`) for four modes —
  `Deutera`, `Proton`, `Trit`, `Monochrome` — and any high-contrast or
  monochrome selection enables **Mind Palace shape coding** so deduction cues
  never depend on hue alone.
- **Photosensitivity** — `BuildPhotosensitivityPolicy(true)` drops the flash
  budget from 12 to **3 per five seconds**, removes strobe, dims burst overlays,
  and applies to VR/AR; the spec asserts `MaxFlashesPerFiveSeconds ≤ 3`.
- **Combat audio cues** — `BuildCombatCueSet` emits five events (incoming fire,
  hit confirmation, low health, target lock, vehicle collision) each with a
  MetaSound graph id, a visual-companion id, spatial-marker and vibration
  companions, and per-event disable honoured from the caller's list.
- **Per-cell difficulty** — `BuildDefaultDifficultyProfiles` produces a profile
  for every cell (`GetAllV5Cells()`), with Easy/Normal/Hard/Brutal driving
  concrete `IncomingDamageScalar`, `EnemyAccuracyScalar`, `ResourceScalar`, and
  `PuzzleHintDelaySeconds` (Easy = 0.6 / 0.65 / 1.3 / 12s; Brutal = 1.65 / 1.45
  / 0.65 / 120s), each `bStoredPerCell`.
- **Aim assist** — `BuildAimAssistProfile` clamps per-axis sensitivity to
  `[0.25, 1.5]`, exposes a driving variant with stickiness and a wider
  acquisition cone, and orders the target-priority pyramid **enemy → breakable →
  civilian**.
- **Speech & input** — `BuildSpeechAccessProfile` advertises Coqui TTS over all
  **16 launch cultures** and Whisper STT that **requires opt-in**
  (`bSTTRequiresOptIn`); `BuildInputAccessPlan` enables per-input remapping
  across named Enhanced-Input contexts and one-handed schemes for the **PS5
  Access** and **Xbox Adaptive** controllers.
- **Camera comfort, period-radio captions, Mind Palace contrast** round out the
  set, the last with six evidence/thread shape tokens for color-independent
  deduction.

### The launch QA gate

`BuildLaunchQASuite` assembles **13** checks spanning every surface above,
twelve of them automated under the `V5.Accessibility` filter. The thirteenth,
`qa.accessibility.external_audit`, is `bManualReview` and carries status
`ReleaseBlocked` — the suite encodes that an internal pass is necessary but
**not sufficient**, and that an external, signed audit gates ship. As "What
ships" records, that audit has not been received, so this check is the honest
hard stop: the settings model is real and tested, but the launch readiness it
feeds remains red on the one human-sign-off it cannot fabricate.

## Security, Privacy & Compliance

### Identity, session & data security

The documented security posture is conventional and strict: all client-server
traffic over **TLS 1.3**, save-game encryption under a **per-account key**, and
anti-piracy via signed-execution checks with **no Denuvo** (per `V5_TODOS.md`
§1.2, ADR 0006). At the service edge these are coded seams: every endpoint in
`apps/v5/compliance-dsar/contract.json` and the anti-cheat contract is marked
`requiresJwt: true` and `regional: true`, with regional active-active failover
(`iad / fra / sin` primary, `pdx / dublin / syd` fallback) and
`dataResidencyPinned: true`. Identity itself roots in the platform, not in V5 —
the same OAuth/SSO foundation documented at
[Auth & Identity](../../platform/auth-identity.html); the TLS and
save-encryption lines are architecture-level commitments rather than code
verified on this page.

### Privacy, residency & data-subject rights

This is the clearest example of the reimplement-rather-than-compose decision.
`V5Compliance` normalises a region (`NormalizeRegion` folds `GB`/`EN-GB` → `UK`,
`ZH-CN` → `CN`, `CALIFORNIA` → `CA`) and resolves a residency policy per
jurisdiction: **CN** pins to `cn-shanghai` / `cn-hangzhou` with
`bCrossRegionReplicationBlocked` and `bCNOnly`; **EU** pins to `fra` / `dublin`
with `bEUOnly`; **UK** to `london` / `dublin`; **California** to `pdx`; and the
global default spreads across `iad / pdx / sin / syd` unpinned. The
`BuildLaunchResidencyPolicies` set and `V5/legal/data-residency.json` agree
field-for-field, and the residency spec (`V5.Compliance.ResidencyNoticeCookie`)
asserts EU- and CN-only storage explicitly.

DSAR is rule-driven and time-bounded. `BuildDSARRequest` stamps a **30-day
SLA**, computes `DueUnixSeconds = Created + 30·86400`, routes through the
**companion-app** portal (`/companion/privacy/dsar`), enumerates export scopes
(`account`, `save-games`, `telemetry`, `workshop`, `moderation`), and embeds the
caller's residency policy so an EU subject's export bucket never leaves the EU.
CCPA do-not-sell is an **account-level flag** (`BuildConsentState`), forced on
for California regardless of input and suppressed to privacy-preserving defaults
for under-13. The service tier makes all of this _stateful_:
`apps/v5/service-shared/src/domain/compliance-dsar.ts` is a real
`ComplianceDsarStore` over Postgres — `CREATE TABLE v5_dsar_request`, an
`openRequest` that starts the 30-day clock and pins the residency bucket, a
state machine (`received → verifying → fulfilling → fulfilled / rejected`), and
an `overdueRequests` backlog query — closing the prior gap that kept §71
compliance-dsar at `[~]`. The DSAR/CCPA rule math itself lives in `runtime.ts`
(`slaDays = 30`, `residencyPolicy = regionPolicy`, do-not-sell driving
`saleSharingSuppressed` and `marketingCookiesBlocked`) and is audit-verified
real.

### Age-gating, moderation & region rules

`BuildAgeGateProfile` bands age into Under13 / Teen / Adult and, for under-13,
cascades the full COPPA restriction set in one place: guardian consent required,
social surfaces / voice chat / Workshop publishing / personalized ads all
disabled, telemetry restricted to essential, and DSAR routed through a guardian.
The spec verifies each flag for an 11-year-old.

DSA moderation is region-aware, not decorative. `BuildModerationReport` marks a
report **DSA-eligible only for EU/UK**, and only then sets
human-review-required, an appeal path, a transparency-log id, and a **72-hour**
SLA (vs **120** hours elsewhere). The spec deliberately asserts that a US
profile report is **not** falsely DSA-eligible — the seam refuses to over-claim
a regime that does not apply. Privacy notices are authored for **ten**
jurisdictions (`BuildPrivacyNotices`: Global, CA, EU, UK, CN, BR, JP, KR, AU,
NZ), each disclosing do-not-sell where California/Global applies and DSA
reporting where EU/UK applies; the cookie model defaults to essential-only with
reject-all, requires explicit marketing opt-in for EU/UK/CN/BR/KR, and surfaces
a do-not-sell link only for California. The rating-board matrix
(`V5/legal/rating-boards.json`: ESRB M, PEGI 18, BBFC 18, USK 18, CERO Z, GRAC,
ClassInd, ACB R18+, OFLC) and the platform cert-ban truth table
(`V5/legal/platform-cert-bans.json`, banning `real_money_advantage`,
`uncleared_music`, `under_13_open_social`, `user_generated_nsfw`, and
kernel-anti-cheat where prohibited) are the cert obligations these seams
satisfy. `BuildLaunchProfile` ANDs them into one `bAllReleaseGatesAuthored`
assertion — ≥5 residency policies, ≥10 notices, cookie models mirroring notices,
a 30-day DSAR, a visible DSA appeal path, and a guardian-gated under-13 profile
— so a single missing piece fails the whole launch-coverage check.

### Anti-cheat & competitive integrity

The threat model is skill-cheating on the ranked Sci-Fi and Urban ladders, and
the posture is layered. **Easy Anti-Cheat** is integrated per platform in
`V5/security/anti-cheat/eac-platform-integrations.json`: Windows runs the signed
**kernel driver** and blocks launch if unavailable; Mac/Linux run the userland
module; consoles use an `EACConsoleBridge` `PlatformIntegrityHandshake`; all
require server session attestation, and the signing key is referenced by env
(`V5_EAC_SIGNING_KEY_ID`), never embedded. Above the driver sits **real
detection math** in `runtime.ts`: a `verdictFromRisk` ladder
(`clean / watch / strike / ban-review` at 0.35 / 0.65 / 0.9) over six detectors
— aim plausibility (`(observed − allowed)/allowed`), sub-tick aim snap
(pattern-met floors risk to 0.72), line-of-sight history
(`mismatch·0.6 + damage·0.4`), speed delta (`(ratio − 1)/0.75`), auto-fire
cadence (`interval·0.7 + variance·0.3`), and a weighted **classifier**
(`V5_AntiCheat_ML`, flagged ≥ 0.72). The thresholds are tuned in
`V5/security/anti-cheat/signal-thresholds.json` (720°/s max turn, 42°/55ms snap,
1.15 max speed ratio). `anti-cheat.ts` journals flagged signals per account in
Postgres, accumulates strikes, and drives a **three-strike policy** — warning →
ranked-suspension → ban-review — with a human-reviewed appeal queue on the
companion route (`/companion/support/anti-cheat-appeal`). Crucially, detection
**never auto-bans**: a ban-review verdict is queued for human review, and the
EAC driver itself is an external platform SDK — V5 ships the config validators,
detection models, routing, and ban policy that integrate with it, not the
driver.

```mermaid
flowchart TB
  P[V5 player · 9 platforms] --> A11Y["V5Accessibility (UE C++)<br/>subtitles · color modes · photosensitivity<br/>difficulty · aim · speech · input"]
  P --> COMP["V5Compliance (UE C++)<br/>residency · DSAR · consent · age gate · DSA"]
  P --> AC["anti-cheat service + runtime.ts<br/>6 detectors · classifier · 3-strike"]
  COMP --> DSARSVC["compliance-dsar service<br/>Postgres · 30-day SLA · residency bucket"]
  AC --> EAC["EAC integration manifest<br/>kernel/userland · server attestation"]
  AC --> HUMAN[Human review + companion appeal]
  A11Y --> QA{"Launch QA suite<br/>13 checks"}
  COMP --> GATE{"bAllReleaseGatesAuthored"}
  QA -->|external_audit = ReleaseBlocked| BLOCK[release blocked: signed audit not received]
  nocontent["0 .uasset · logic+manifest skeleton"] -.->|caps cooked claims| BLOCK
```

## Where this connects

- **Sideways to live service:** [Live Service & DLC](./live-service-and-dlc.md)
  — the seasonal calendar, Workshop marketplace, and moderation queue whose UGC
  the DSA reporting and cert-ban surfaces govern, and the store-compliance and
  spend-limit rules the age gate feeds.
- **Sideways to launch quality:**
  [Observability, Performance, Testing & Content Pipeline](./observability-performance-testing-content-pipeline.md)
  — the release-gate aggregation, telemetry opt-out at ingest, and the
  automation harness that runs the `V5.Accessibility.*` and `V5.Compliance.*`
  specs cited here.
- **Platform foundations:** [Auth & Identity](../../platform/auth-identity.html)
  is the OAuth/SSO and account-root V5's JWT-gated, region-pinned services
  compose; the shared `@oshun` / `@themis` / `@aphrodite` privacy packages are
  the cross-product analog V5 **reimplements natively** rather than wiring in —
  noted here so the divergence is on the record.
- The section hub: [../V5_ARCHITECTURE.md](../V5_ARCHITECTURE.md).
