All four clusters are deliberately off the rollback simulation. They consume versioned match or account evidence and produce governed external effects, but cannot perturb deterministic combat truth.
Everything on this page happens around the match, never inside it. When a
fight ends, V2 hands the moment off to a ring of out-of-match surfaces: the
community team's editorial picks and moderated galleries, the per-platform
storefront that prices a cosmetic differently in São Paulo than in San Jose, the
support desk that triages a lost-account ticket, and — the most architecturally
interesting cluster — the AI services that turn a recorded set into a
produced broadcast with live commentary, translated chat, captions, and a
lip-synced caster face. The throughline is a hard line: every one of these
surfaces is off-rollback. None of them can perturb the deterministic combat
simulation, and the code says so out loud, with mayInfluenceRollback: false
and rollbackPolicy fields stamped on each service's output.
The shape of what ships matters here, because this group spans the full implemented-to-spec spectrum. The web surfaces are versioned JSON data contracts, not React apps. The store's region-aware pricing is genuinely implemented math in two separate engines. The AI services are real orchestration bridges whose generative core is an honest provider-gated seam. And the moderation underneath the galleries composes the shared Kuanyin/Themis trust-and-safety plane that governs every Oshun product. This is the feature-side companion to the "Online, Esports & Live Service" group; the section hub is ../V2_features.md.
What ships, honestly#
- The web surfaces are real but data-shaped.
apps/v2/web/community,apps/v2/web/hub, andapps/v2/web/supportare not standalone apps — each is a single schema-versioned JSON document (community.json→v2.web.community.v1,hub.json→v2.webHub.v1,support.json→v2.web.support.v1) that the shared Oshun shell renders. They are the shipped data contract: Player of the Week, the gallery roster, support SLA tiers, the ambassador languages, and the Hall of Fame inductees are all concrete fields, not lorem ipsum. - The store math is implemented twice, for two economies. Real-money
region-aware pricing (PPP) is a real function,
calculateV2MaatFinanceRegionalPriceMinorin@maat/finance, bridged into V2 by@v2/maat-finance-ledger. The in-game soft-currency economy is a separate, fully-implemented C++ engine,UV2PriceTableLibraryinV2/ue/Source/V2Gameplay/Private/V2PriceTable.cpp. Both carry validators and contract specs. - The AI services are real bridges with a provider-gated core.
iris-commentary-orchestration,iris-realtime-translation,iris-accessibility,isis-commentary-lipsync-pipeline,psyche-commentary-face-animation,psyche-caption-streaming,euterpe-commentary-ducking,calliope-commentator-personas, andpsyche-ai-director-hintsall exist underapps/v2/with real orchestration, latency budgeting, and fallback logic. What is provider-gated is the generation itself — the commentary text, the synthesized voice, the animated face — produced by the shared Iris/Isis/Psyche/Euterpe substrates those bridges call, exactly the fail-loud-when-unconfigured seam the platform uses everywhere. - What is plan, not artifact: the editorial spotlights, the specific brand partners, the newsletter copy. Those are authored/scheduled content the services carry, honestly a roadmap and not engine code.
The architecture-side treatment of these same surfaces lives in two companions: ../architecture/live-ops-store-progression-and-community.md (store, economy, community governance) and ../architecture/esports-companion-and-ai-services.md (the AI broadcast chain). This page stays on the feature surface and dips into code only where a claim needs backing.
Community surfaces#
The web data contracts#
apps/v2/web/community/community.json is the seed for the out-of-game community
page, and its fields map one-to-one onto the source feature list. featured
carries the three editorial picks — player (Player of the Week), crew (Crew
of the Month), and replay (Replay of the Week) — each with a reward flair id
like Flair.PlayerOfTheWeek.2026W22, so the "featured account gets a flair
cosmetic" promise is a concrete grant token, not prose.
apps/v2/web/hub/hub.json is the account-bound player hub: rank, Crown balance,
Battle-Pass tier, faction, a friends panel, a wishlist, a leaderboard slice,
public replays, a moderated gallery strip, two server-validated web micro-games
(Web Frame Quiz, Web Replay Scout), and a news feed whose items are tagged
confirmed | planned | exploratory — the same roadmap-honesty taxonomy the
roadmap surface uses.
Editorial spotlights, galleries & moderation#
Each gallery entry in community.json carries the fields that make a
community gallery safe to ship: a creator, a creatorCode (the
creator-attribution code that also applies at store checkout),
moderation: "approved", consent: true, and a source
(Community Art Gallery, PhotoModeCloud, TournamentArchive). Those two
booleans are load-bearing — nothing surfaces in the gallery until it has passed
moderation and carries explicit consent.
The moderation pipeline the relationships/creator page defers to lives here, and
it is governed rather than ad-hoc. @v2/kuanyin-first-line-moderation is the
primary moderation path — its README is explicit that it replaces Two Hat,
Community Sift, Hive AI, and AWS Rekognition with @kuanyin/precognition and
@kuanyin/foundation as the first-line filter. Public UGC accept-gating (custom
championships, decals, logos, music swaps) runs through
@v2/themis-originality-shields, which composes the full Themis originality
family — @themis/music-shield, @themis/visual-shield, @themis/text-shield,
@themis/video-shield, and @themis/design-shield — so an uploaded decal is
checked for visual originality and an uploaded soundtrack swap for music-rights
collision before it can appear. Crew/faction governance (rule votes, member
reputation, constitution amendments) composes @themis/community through
@v2/themis-community-governance, and community-health signals (temperature
scoring, raid detection, new-user throttles) run through
@v2/kuanyin-community-harmony. Because all of this resolves through the same
audited Themis/Kuanyin path, a community ban and a match-conduct ban are the
same appealable action.
Newsletter, meetups, Discord & journals#
The newsletter block lists eight serviced regions (NA, EU, JP, KR, LATAM, SEA,
India, MENA) and a fixed recap shape (patch highlights, new content,
tournament results, community moments, roadmap teaser). meetups are opt-in and
privacy-first: each entry carries a locationLabel, a subscribable .ics
feed, and noPii: true, so the discovery map never leaks an account's location.
discord enumerates the eight per-region staffed servers, and journalPrompts
seeds the per-account public journal (moderated on the same pipeline as gallery
submissions). Photo-mode tournament submissions and community/jury voting are a
separate bridge, @v2/photo-mode-tournament-voting-bridge (§133), which emits a
v2.photo-mode-tournament-voting-manifest consumed by V2PhotoMode,
V2ReplayTheater, V2CommunityHub, and V2CompanionApp.
Store & region-aware pricing (PPP)#
V2 runs two distinct price engines, and conflating them is the easy mistake. One prices real money (the cosmetic/DLC storefront); the other prices in-game soft currency (the Koin/Crown vendor economy). Both are implemented; they live in different languages and answer to different rules.
Real-money pricing: the PPP ledger#
Real-money region-aware pricing is calculateV2MaatFinanceRegionalPriceMinor in
libs/maat/finance/src/v2-persistence-ledger.ts, bridged into V2 by
buildV2MaatFinanceLedgerSurface in
apps/v2/maat-finance-ledger/src/maat-finance-ledger.ts. The policy struct
V2MaatFinanceRegionalPricingPolicy carries a baselinePriceMinor, a
pppRatioBasisPoints, a priceFloorRatioBasisPoints, and a
priceCeilingMinor, and the function is exactly the "ratio, floored, ceilinged"
rule the source describes:
ratioPrice = round(baselinePriceMinor × pppRatioBasisPoints / 10_000)
floorPrice = round(baselinePriceMinor × priceFloorRatioBasisPoints / 10_000)
regionalPrice = min(priceCeilingMinor, max(floorPrice, ratioPrice))
The contract spec pins this with a worked policy — pppRatioBasisPoints: 6500
(a 0.65 purchasing-power ratio), priceFloorRatioBasisPoints: 4000 (the ratio
× 0.4 floor that blocks inversion attacks, straight from the source), and a
priceCeilingMinor that caps the regional price at baseline. The same function
is reused inside buildV2MaatFinanceLedgerDecision, which is the spend gate: a
spend transaction is rejected with reason region-price-mismatch if the
client's unitPriceMinor does not equal the freshly-computed regional price (so
a VPN-spoofed or stale price cannot transact), and with
regulatory-cap-exceeded if it breaches regulatoryTransactionCapMinor or the
running regulatoryDailySpendCapMinor — and minor accounts get a stricter
minorDailySpendCapMinor. Refunds require a refundReferenceId and fall inside
refundWindowDays, or they fail refund-reference-required /
refund-window-expired. The whole decision is offline-tolerant: it can
approve against an in-engine ledger cache (approved-offline-cache) and
reconcile on the next online sync, which is why support.json's refund ticket
shows a "Maat finance review queued" history line.
In-game economy: the C++ price table#
The soft-currency vendor economy is UV2PriceTableLibrary::QuotePriceTable in
V2/ue/Source/V2Gameplay/Private/V2PriceTable.cpp — a real BlueprintPure
resolver, not a lookup. A quote resolves a base price for the Buy/Sell kind,
then applies a regional override (FV2PriceTableRegionalOverride can
override the buy price, the sell price, or apply a RegionalMultiplier), then
optional dynamic pricing that multiplies the entry's
Demand × Supply × Event factors against the request's, clamps the result to
the entry's Min/Max bounds, and finally scales by quantity. Every stage
records an itemized FV2PriceTableIssue (RegionalOverrideApplied,
DynamicPriceApplied, PriceEntryResolved) so a quote is auditable.
ValidatePriceTable is the gate that keeps the catalogue honest — it rejects
duplicate price-entry ids, duplicate item|currency pairs, currencies absent
from the catalogue, non-positive prices, a sell price exceeding the buy price,
and multipliers outside (0, 10], each as a blocking issue with a
FailureTag. This is the engine behind the persistent-world economy and the
Krypt/vendor shops, and it is fully separate from the real-money ledger above —
nothing it prices touches a payment rail.
The per-platform storefront#
Real-money purchases route through each platform's native store. hub.json's
commerce block is the surfaced contract: allowed, a region (e.g. US),
platformPaymentRulesPermit: true, and a refundPolicy pointer (V2.86.5).
The platform store is the exclusive path for any item that grants gameplay
state on that platform; the non-item flows (coaching marketplace, donations,
esports prize pools) are the TRC-permitted exceptions that route through
Stripe/Adyen, and they are kept ledger-separate from earned currency for
store-compliance reasons. Premium currency (Crowns) buys transparent items —
no real-money loot boxes — under the daily spend caps the ledger enforces.
Customer support, ambassadors & Hall of Fame#
apps/v2/web/support/support.json is the support contract, and its
priorityTiers are the SLA spine: critical (lost account / refund dispute /
harassment) at 1h first response / 24h resolution under 24/7 coverage,
high (ban appeal / cheat report / payment failed) at 8h/72h, normal
(cosmetic loss / UI bug) at 48h/14d, and low (feature request) at 7d.
regions pins per-region hours and locale coverage (eight regions, from
en-US/es-MX in NA to ar-SA/en-AE in MENA); knowledgeBase ships real KB
articles (account recovery, platform refunds, harassment escalation,
rollback-quality troubleshooting); ambassadors declares the vetted program
(eight regions, ten languages, a quarterly-review term, an
Community Ambassador flair); coaches carries the certified-coach roster with
per-coach ratings; and hallOfFame enumerates the inducted champions,
record-holders, and community legends. The live ticket list (tickets)
demonstrates the routing — SUP-1025's history shows a refund dispute handed to
"Maat finance review," closing the loop back to the PPP ledger.
Support does not stand alone: when an outage or mispriced item harms players,
@v2/player-compensation-service issues incident-scoped, evidence-backed,
approval-gated make-goods; @v2/patch-notes-service publishes the structured,
required-category change record that pairs with each balance hotfix; and
@v2/message-of-the-day-service pushes announcements (events, downtime, patch
notes) to the shipped client without a patch, with per-account dismissal —
the same dismissal keys community.json's announcements block carries.
AI services: a produced broadcast#
This is V2's integration showcase. A match can be cast by AI in real time, and
the pipeline is a chain of thin apps/v2/ bridges over shared Oshun substrates
— V2 supplies fighting-game context and consumes a produced broadcast. The
unifying invariant is the rollback boundary.
The off-rollback boundary#
Every AI service stamps its output as gameplay-inert. The commentary plan's
rollbackBoundary literally sets gameplayInertOutput: true,
feedsSimulationState: false, allowedOutputChannels: ['audio', 'subtitle'],
and rejectsRollbackFrameOrigin: true; requestV2AICommentaryCue in
apps/v2/iris-commentary-orchestration/src/v2-ai-commentary.ts validates that a
cue is never called from inside a rollback frame (fromRollbackFrame is a
hard rejection). The translation, caption, lip-sync, face-animation, and ducking
bridges each carry the matching mayInfluenceRollback: false / off-rollback-*
policy. The one AI service that does touch the deterministic path,
@v2/psyche-ai-director-hints, does it safely: in rollback-with-CPU modes it
samples a tendency vector at match load, serializes tendency-vector + seed
into the match-start input vector, and then runs rollback-deterministically with
no further RPCs — mid-match Psyche updates are queued for the next match
start.
Real-time commentary#
requestV2AICommentaryCue composes createMatchCommentaryStream from
@iris/conversation-orchestration in off-rollback-only determinism mode. The
headline number is a 800 ms KO-trigger latency budget
(V2_AI_COMMENTARY_KO_TRIGGER_LATENCY_BUDGET_MS = 800), and
buildV2AICommentaryLatencyBudget splits it across the Iris LLM round trip (420
ms), persona TTS render (240 ms), Psyche lip-sync render (100 ms), and a 40 ms
safety margin — and the validator refuses a request whose sub-budgets don't fit
inside the total. When the envelope is missed, the client falls back to a
pre-recorded bank line keyed by the deterministic tuple
(cueKind, ruleset, commentatorId, seed), so a slow generation never leaves
dead air. Streams are scoped
local-peer | host-peer-canonical | broadcast-canonical. The commentator roster
itself is validated by @v2/calliope-commentator-personas, which loads
commentator-personas.json and verifies every persona has cleared @iris/voice
clone metadata, signed talent approval, brand metadata, and deterministic
fallback-bank metadata before exposing the Iris commentator ids the orchestrator
uses.
Post-match experience#
buildV2AIPostMatchExperiencePlan (section 135) assembles the after-match
surface. The highlight reel is a real selection: candidates are sorted by
score descending (ties broken by earliest frame) and the top five taken, the
plan requiring all five moment kinds — longest-combo, counter-hit-punish,
power-play, dramatic-comeback, ko — and emitting mp4, gif, and
vertical-9:16 share formats with trim/filter/music/caption controls. The
analysis screen pins six panels (damage-by-move, combo breakdown, meter usage,
corner-pressure win rate, mistake-frame timeline, matchup-specific advice) plus
a rolling 10-match strength/weakness summary, and the auto-clip library tags an
AI-suggested caption and title. Every output carries the compliance block:
machineGeneratedLabel: true, a per-output opt-out, an EU AI Act
cross-reference (80.4), and manualTrainingDataReview: true — and post-launch
procedural fighter dialogue is flagged manualReviewRequired /
signedOffBeforeDeployment, so generation accelerates authoring but never ships
an unreviewed line.
Translation, captions, face & mix#
The rest of the chain makes the broadcast multilingual and accessible.
buildV2IrisRealtimeTranslationSession (@v2/iris-realtime-translation)
composes @iris/voice to translate spectator chat and commentary across
four surfaces (spectator-chat, commentary-localization, broadcast-overlay,
companion second-screen), registering per-locale receiver participants and
reporting per-delivery success/fail counts with honest reason codes when a
provider returns failures. @v2/iris-accessibility owns the accessibility
semantics and, until Iris owns live captions end to end, drives the real-time
caption engine through @psyche/caption-streaming (bottom-center, low-latency,
speaker-aware). @v2/isis-commentary-lipsync-pipeline (composing
@isis/visual-dubbing) and @v2/psyche-commentary-face-animation (composing
@psyche/avatar-lipsync + @psyche/avatar-expressions) turn commentary audio
into a lip-synced, ARKit-curved caster face, and
@v2/euterpe-commentary-ducking (composing @euterpe/accompany +
@euterpe/master) sidechains the music bus so the VO sits properly in the mix.
Each of these is independently droppable — if the face-animation provider is
absent, the audio/subtitle cue still ships.
How it connects#
These surfaces are the connective tissue between the fight and the player's life around it. The galleries moderate and sell the cosmetics, CAWs, and arenas authored in ./relationships-progression-and-creator-suite.md; the storefront's PPP ledger and the battle-pass/DLC economy are two halves of one monetization story, the other half of which — seasons, the battle pass, Twitch drops, and the read-only companion app — lives in ./live-service-dlc-battle-pass-and-companion.md. The AI broadcast chain feeds the esports/spectator surfaces and the director-cam, and its full substrate topology (Iris/Isis/Psyche/Euterpe/Nous) is the subject of the architecture companion ../architecture/esports-companion-and-ai-services.md, while the store, economy, and community-governance plumbing is detailed in ../architecture/live-ops-store-progression-and-community.md. The one constant across all of it: off-rollback, gameplay-inert, audited. The section hub is ../V2_features.md.
Related#
- The feature hub: ../V2_features.md
- Live Service, DLC, Battle Pass & Companion — the seasons, battle pass, Twitch drops, and read-only companion that share this group's economy and community spine
- Relationships, Progression & Creator Suite — the UGC and cosmetics the galleries here moderate and the storefront sells
- Esports, Companion & AI Services — the architecture-side AI broadcast chain and substrate topology
- Live-Ops, Store, Progression & Community — the store, economy, and Kuanyin/Themis governance plumbing