Open-World Narrative · Architecture

Accessibility, Security & Compliance

A focused page within the Open-World Narrative Architecture documentation. The full map and every sibling page live in the Architecture hub.

4sections10 minread1diagram

On this page

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.

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:

  • SubtitlesBuildSubtitleStyle 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 visionBuildPalette 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.
  • PhotosensitivityBuildPhotosensitivityPolicy(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 cuesBuildCombatCueSet 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 difficultyBuildDefaultDifficultyProfiles 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 assistBuildAimAssistProfile 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 & inputBuildSpeechAccessProfile 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; 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-GBUK, ZH-CNCN, CALIFORNIACA) 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.

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 — 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 — 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 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.