# Accessibility & Localization

V6 — **Egbe, the agentic-companion universe** — makes two design choices that
collide head-on with accessibility and localization, and the collision is the
whole reason this page exists. First, the game's primary command channel is
**voice**: a steward speaks an objective and Vac parses it. Second, its primary
_content_ is not authored — it is a continuous stream of **generated** agent
dialogue, Chronicle narration, and the Book of the Ori. A player who cannot hear
or speak must lose nothing, and a player in Madrid or Lagos must hear their
companion speak _their_ language and be no less governed for it. Neither of
those is a string table you can hand to a translation vendor. The first is an
input-parity problem the size of the entire control scheme; the second is a
**generation-time** problem that reaches into the cognition kernel itself.

This page describes how V6 meets both — and it draws the same hard line V2–V5
draw between code that runs, gates that machine-check declared facts, and intent
recorded honestly in a manifest. Some of this surface is **real, tested code**
(the Tier-2 fallback client's accessibility surfaces in TypeScript; the VR
comfort options in Unreal C++; the per-locale dialogue seam in the cognition
stack). Some is **machine-checked policy over JSON** (the axe-core gate
artifacts, the region-rating/residency matrix, the readiness gate). And one
load-bearing thing — _natively generated_ localized speech — is a real, tested
seam that **needs a wired hosted model to actually produce native text at
runtime**, which the repository deliberately does not pretend to have. The
section hub is [../V6_features.md](../V6_features.md).

## What ships, honestly

The boundary between "implemented and tested" and "declared intent" runs cleanly
through this cluster, and stating it up front keeps nothing below oversold.

- **The Tier-2 accessibility surfaces are real TypeScript.** The web-fallback
  client (`apps/v6/egbe-web-fallback/src/app.ts`, ~4,900 lines) builds the
  no-microphone capability routes, the speaker-tagged readable transcript with
  live text-scale/contrast/history controls, the cognitive-load reductions, and
  the reduced-motion/reduced-stimulus/plain-language modes as actual rendered
  DOM with computed reductions — not stubs. Its `e2e/egbe-web-fallback.spec.ts`
  (~600 lines) drives those surfaces under Playwright.
- **VR comfort is real, tested Unreal C++.**
  `V6/ue/Source/V6UI/Private/V6VRComfortOptions.cpp` (387 lines) and its header
  build the vignette / snap-turn / seated-play / comfort-intensity panel,
  persist it across V1 identity, and restore it _before the first VR frame_; the
  `V6.XR.VRComfort.OptionsPersistenceReview` automation test (151 lines) was
  built and run on the on-box UnrealEngine 5.5.4 with `Result={Success}`
  (`V6/ue/Saved/CI/v6-vr-comfort-automation-ueagent.log`).
- **The per-locale dialogue seam is real and unit-tested — but template-backed
  in-repo.** `libs/v6/cognition-stack/src/index.ts` carries a genuine native
  generation path through the Iris `CognitionGateway` with a §9.5 quality
  judge/refine (`generateLocalizedAgentDialogueViaGateway`), exercised by
  `localized-dialogue-gateway.spec.ts`. With **no model wired** — the repo's
  state — it falls back to a deterministic per-locale **template** and reports
  that honestly (`generatedNatively: false`, `source: 'template-fallback'`). It
  never claims native generation over a static string.
- **The a11y/loc/region gates are machine-checked JSON.** The seven artifacts
  under `V6/accessibility/` and `V6/localization/`, plus the readiness manifest
  `V6/release/accessibility-localization-security-cert-readiness.v6release.json`,
  are validated by
  `scripts/v6/verify-v6-accessibility-localization-security-cert-readiness.mjs`
  (699 lines). A green gate certifies the declared posture; an axe-core "pass"
  in a manifest is a _declaration the verifier enforces_, distinct from the live
  Playwright run that produces it.
- **The shared `@oshun/i18n` registry is not wired into V6.** It exists
  (`libs/oshun/i18n/src/index.ts`, with `OSHUN_LAUNCH_LOCALES` spanning eight
  RTL-aware platform locales), but V6's _generated_-text localization defines
  its own three-locale profile set in the cognition stack and does not import
  it. Authored-string reuse of the V1 pipeline is doctrine described below, not
  an in-repo V6 dependency edge.

## Accessibility

The named conformance standard is **WCAG 2.2 Level AA** for every web-rendered
and app surface — the Tier-2 fallback client, the Egbe Steward App, Egbe Studio,
and the Chronicle reader — evaluated by **axe-core** in CI alongside the
per-platform console/mobile/VR accessibility checklists for the Unreal client.
The governing V6-specific concern is that voice and generated dialogue must both
be fully operable and fully legible without hearing or speaking.

### Non-voice parity — the load-bearing guarantee

Because Vac is voice-first, the single most important accessibility claim is
that **every Vac capability has a complete non-voice equivalent**. The intent
grammar is authorable through a structured UI — a verb picker, target picker,
and constraint / priority / deadline / forbidden-line fields — that emits the
_identical_ structured intent the voice parser produces; conversation is text
chat; squad comms run fully by text.
`V6/accessibility/vac-no-microphone-a11y.v6a11y.json` enumerates the four
capability routes (`intent-grammar`, `text-dialogue`, `squad-comms`,
`negotiation-routing`), each `completeWithoutMicrophone: true`,
`keyboardOperable: true`, and `axeVerified: true`, with
`microphoneRequired: false` and `passedCapabilityCount: 4`. The verifier asserts
exactly those four pass on desktop- and mobile-chromium. Voice is a convenience,
never a requirement.

### Readable transcripts and cognitive-load controls

All squad comms, dialogue, and negotiation render as **speaker-tagged,
timestamped, scrollable** transcript lines, with live controls for text size,
contrast mode, and history depth. In `app.ts` these are real types
(`VacTranscriptAccessibilitySettings`, `VacAccessibleTranscriptLine`) with
setters wired to the UI; `comms-transcripts-a11y.v6a11y.json` checks nine
boolean guarantees (`speakerTagged`, `timestamped`, `resizable`, `highContrast`,
`historyDepthAdjustable`, …) and ships a `large` / `high` / `full` default.

Cognitive load is controlled by **measured reduction**, not assertion. The
Chronicle's brief mode drops visible beats from 5 → 3; emergent-arc prompts go 3
→ 1 (reduced) → 0 (muted); the homestead-rest pace cuts return milestones 8 → 2
and _cognition spend_ 11,520 ms → 720 ms. The verifier does not trust the
booleans alone — it arithmetically requires
`chronicleBriefBeatCount < chronicleFullBeatCount`,
`emergentMutedPromptCount < emergentStandardPromptCount`, and
`homesteadRestCognitionMs < homesteadNormalCognitionMs`. A control that claimed
to reduce load without reducing the number fails the gate.

### Reduced-stimulus, plain language, and screen-reader support

`reduced-stimulus-screen-reader-a11y.v6a11y.json` records that reduced-motion
dampens 3D scene animation (motion multiplier 1 → 0) and reduced-stimulus lowers
the ambient rendered-agent count 18 → 6, and that the roster, Chronicle,
dossier, intent builder, and Steward App are screen-reader ready. Crucially,
**no game-critical information is color-only or numbers-only**: bond is a
plain-language relationship summary, not a raw meter, and arc state is described
in words — the `AccessibilityRelationshipMode` of `'plain-language'` in `app.ts`
is the concrete expression of that doctrine. This artifact is `verifiedBy` three
runners — `@axe-core/playwright`, `react-native-accessibility-props` (the
Steward App), and `ue-platform-a11y` (the console/VR client).

### VR comfort — real Unreal C++

The intimate VR stewardship surface carries comfort options as genuine engine
code. `FV6VRComfortOptionsSettings` exposes vignette (off/light/strong),
snap-turn (smooth → snap-45), standing/seated play, a seated eye height, and a
0–1 comfort intensity; `FV6VRComfortOptionsPresenter` builds the panel, a
comfort-first preset, and a launch comfort-review report. The settings **persist
across V1 identity, encrypted at rest, and restore before the first VR frame** —
so a motion-sensitive player never sees a single uncomforted frame. The on-box
automation passed, and the `V6/ue/Build/XR/VRComfortOptions.json` contract
records a QA-signed-off comfort review (48 evaluated users, sickness-report rate
0.0417 under the 0.05 threshold). The review numbers are declared QA data; the
widget, persistence, and validation logic are running C++.

## Localization

V6's localization load is different in _kind_ from a normal title's. The
authored surfaces — UI chrome, district names, store copy, the Steward App —
follow the V1 string-translation pipeline as doctrine. But the **bulk of V6's
text is generated**, so its localization is a generation-time concern. V6
launches with exactly three locales — **en-US, es-ES, yo-NG** — pinned in
`region-rating-residency.v6loc.json` (`checkedLocales`). Adding a locale means
adding it to that artifact and passing every per-locale gate.

### Three locales, governed per locale

The cognition stack defines `CognitionLocaleCode = 'en-US' | 'es-ES' | 'yo-NG'`
and a `COGNITION_LOCALE_PROFILES` table giving each locale its language name,
native name (`English` / `Español` / `Yorùbá`), text direction, a
native-language `generationInstruction`, and — the governance hook — an
`isisPolicyLocaleRef` and `sophiaGroundingLocaleRef`. The type carries a
`CognitionTextDirection` of `'ltr' | 'rtl'`, so RTL is representable; all three
launch locales ship `'ltr'`. Per-locale governance is not decorative: every
localized line is run through the same Isis behavior-policy and Sophia grounding
as an English one, keyed to that locale's refs, so a localized agent is **no
less governed and no less grounded**.

### Localizing agent speech — generate, don't translate

This is the heart of the page. V6 does **not** generate English and
machine-translate it. The cognition stack's `LocalizedDialogueSource` type is
precisely `'model' | 'template-fallback'` — there is _no_ `'translation'`
source, and a code comment states the rule outright: V6 never
machine-translates; localized dialogue is either natively model-generated per
locale or a governed per-locale template.

The real path is `generateLocalizedAgentDialogueViaGateway`. It hands the
steward utterance, objective, persona tags, and locale to the Iris
`CognitionGateway`, which generates in the target language, runs the **§9.5
dialogue-quality judge/refine**, and returns a verdict. A `'blocked'` verdict
**withholds the line** (`approved: false`) even when Sophia grounding and Isis
policy would clear it; a gateway error **fails loud** with no template fallback.
The honesty seam is strict: `generatedNatively` is `true` only when a real model
produced the text. In the repository — no model wired —
`generateLocalizedAgentDialogue` serves a deterministic per-locale template
(e.g. _"I can answer in English and keep the market bridge inside consent and
the Ori record."_ / _"Puedo responder en español…"_ / _"Mo lè dáhùn ní
Yorùbá…"_) and reports `generatedNatively: false`,
`source: 'template-fallback'`, `translationFallbackUsed: true`. The committed
`generation-time-localization.v6loc.json` declares the _intended shipped_ state
(`nativeGenerationLocaleCount: 3`, `translationFallbackUsed: false`) — the
target a wired model satisfies. The gateway spec proves the native path works
against an injected provider; producing genuinely native text in CI is what the
wired model, absent here, would add.

```mermaid
flowchart TD
    S[Steward utterance + objective + locale] --> P[cognitionLocaleProfile<br/>en-US / es-ES / yo-NG]
    P --> Q{Hosted model wired?}
    Q -- yes --> G[CognitionGateway.generate<br/>native language]
    G --> J{§9.5 quality judge/refine}
    J -- blocked --> W[Withhold line<br/>approved = false]
    J -- cleared --> A[assembleLocalizedDialogue<br/>generatedNatively = true]
    Q -- no --> T[Deterministic per-locale TEMPLATE<br/>generatedNatively = false]
    T --> A
    A --> SG[Sophia grounding<br/>per-locale ref]
    A --> IP[Isis behavior policy<br/>per-locale ref]
    SG --> D{grounded AND approved AND not blocked?}
    IP --> D
    D -- yes --> SHIP[Ship native line]
    D -- no --> W
```

### Cultural grounding, region ratings, and residency

A grounded backstory references real cultural, historical, and geographic fact —
which reads differently across cultures — so each locale gets an independent
**cultural-accuracy and -sensitivity review**.
`locale-cultural-backstory-grounding.v6loc.json` requires three review roles per
locale (`source-grounding`, `local-cultural-adapter`, `community-advisor`); a
backstory that fails review is **blocked for that locale**, not shipped
softened. These roles are declared human responsibilities, gated by role
coverage, not something the repo can perform on its own.

Region rating and residency are handled independently of locale.
`region-rating-residency.v6loc.json` carries a profile per launch locale: en-US
is **ESRB Mature 17+** (US zone, full emergent drama, Aye age-gated-17); es-ES
is **PEGI 16** (EU residency + compute zone, softened drama); yo-NG is **IARC
12+** (brief drama, Aye **deferred-pending-local-review**, with residency pinned
to the `us` zone). The artifact's invariant
`localeIndependentFromResidency: true` encodes the principle that **choosing
Yorùbá is a content choice, not a data-placement choice** — the V1
account-home-zone residency posture governs where Ori data lives regardless of
language.

### Where the shared i18n stack fits

The platform's `@oshun/i18n` is the authored-string registry — a real, RTL-aware
locale set (`en-US`, `es-US`, `fr-FR`, `de-DE`, `ar`, `he`, `ja-JP`, `pt-BR`)
used by the broader Oshun web apps. V6 does **not** consume it: its three launch
locales are a _generated_-text concern owned by the cognition stack, and its
authored-string side is described as following the V1 workflow rather than
wiring that package. Keeping the two separate is deliberate — a generation-time
locale and an authored-string locale are different artifacts with different
review paths, and conflating them is exactly the kind of shortcut the honesty
convention forbids.

## Verification and the launch bar

Everything above rolls into one launch-blocking gate.
`verify-v6-accessibility-localization-security-cert-readiness.mjs` confirms
every a11y and loc artifact exists and is internally consistent (the
cognitive-load reductions actually reduce, the three locales are native-declared
with no translation fallback, the region profiles meet their ratings, the VR
comfort review is QA-signed), that V6_TODOS sections 39/40/44/45 carry no
unchecked boxes, and that the readiness gate is chained into the CI workflow
after the governance/safety gate. The corresponding launch-readiness line in
V6_TODOS is honestly marked `[~]` — partial — because final certification needs
a cooked, signed, vendor-approved build that a stand-in repo cannot produce, the
same caveat the architecture companion states in full.

This page is one of three under **Trust, Safety, and the Launch Bar**. Its
safety and commerce sibling — persona governance, welfare, operator audit, and
the storefront — is
[./governance-safety-and-commerce.md](./governance-safety-and-commerce.md). The
rollout sibling — region staging, cross-platform certification, and
cross-progression continuity, which consume the region-rating/residency matrix
above — is
[./cross-platform-rollout-and-launch.md](./cross-platform-rollout-and-launch.md).
The architecture companion, which holds the unforgeable view of the readiness
gate and the eval/cost/welfare contract gates, is
[../architecture/performance-build-security-testing-and-launch.md](../architecture/performance-build-security-testing-and-launch.md).
