# Ranked, Esports Circuit & Spectator Modes

```mermaid
stateDiagram-v2
  [*] --> Unranked
  Unranked --> Provisional: eligible ranked placement begins
  Provisional --> Ranked: placement evidence completes
  Ranked --> Promoted: rating crosses protected threshold
  Ranked --> Demoted: rating and hysteresis cross lower threshold
  Promoted --> Ranked: visible rank updates
  Demoted --> Ranked: visible rank updates
  Ranked --> Decaying: inactivity policy applies
  Decaying --> Ranked: eligible activity resumes
  Ranked --> Frozen: tournament edition or integrity hold
  Frozen --> Ranked: governed resolution
  Ranked --> SeasonClosed: immutable season snapshot
```

Hidden rating, visible rank, promotion/demotion hysteresis, inactivity decay,
tournament freezes, disputes, and season closure are separate. Broadcast and
spectator views project this ledger without owning it.

A fighting game's competitive surface is judged by two things players can feel
but rarely see: whether the ladder they climb is honest, and whether the
broadcast they watch is _produced_. V2 treats both as first-class engine data,
not marketing copy. This page covers the three clusters that turn a
deterministic 1v1 into a season-long sport — the **ranked season architecture**
(90-day seasons, eight visible rank families over a hidden TrueSkill2/Glicko-2
pool, hysteresis, decay, and anti-throw integrity), the **esports circuit** (the
TO admin console, the Tournament-Edition rule freeze, the Crown Pro Tour points
overlay, and the public result archive), and the **streamer / speedrun / coach /
spectator modes** that wrap a match for an audience. The unusual thing about
V2's implementation is how much of this is _real, validated Unreal C++_ in the
`V2OnlineServices` module rather than a backend stub: the season catalogue, the
ten-part esports feature set, and their cross-checking validators all ship and
are pinned by contract automation specs. Where a piece is a designed contract or
a provider-gated capability, this page says so in code. The section hub is
[../V2_features.md](../V2_features.md).

## What ships, honestly

The line between "shipped" and "designed" runs cleanly through this cluster, and
it is worth stating up front.

- **The ranked season is a validated C++ catalogue.**
  `FV2RankedSeasonArchitectureCatalog` (`V2OnlineServicesTypes.h:12494`) is a
  real `USTRUCT` carrying every season number — length, placements, tiers,
  regions, rewards, and four sub-policies (MMR, decay, Crown overlay,
  anti-throw). It is built by `BuildDefaultRankedSeasonArchitectureCatalog()`
  (`V2OnlineServicesBlueprintLibrary.cpp:10419`), gated by a cross-checking
  validator (`IsValidCatalog`, `HasAllVisibleRankTiers`), wired into
  `UV2OnlineServicesSubsystem::ConfigureRankedSeasonArchitecture()`
  (`V2OnlineServicesSubsystem.cpp:622`), and exercised end-to-end by the spec
  `V2.Online.RankedSeasonArchitecture.AssetContract`
  (`V2/ue/Source/V2Tests/Private/Online/RankedSeasonArchitecture.spec.cpp`).
- **The esports/streamer/coach/speedrun surface is one validated feature set.**
  `FV2EsportsTournamentFeatureSet` (`V2OnlineServicesTypes.h:7913`) bundles ten
  sub-configs — spectator policy, TO admin, broadcast control,
  Tournament-Edition snapshot, Crown ranking, streamer privacy, coach session,
  speedrun support, caster API, and pro-ghost tutoring — each with its own
  `IsValid…` method, and an `IsCompleteFeatureSet()` that requires all ten. The
  module spec (`V2Tests/Automation/OnlineServices.Module.spec.cpp:2267`) builds
  it, validates every part, and configures it through the subsystem.
- **The ranked \*tuning numbers live in C++, not in `V2/balance/online`.** That
  directory currently holds only `world-boss-community-raid.json`; the ranked
  season's curves are the build-default catalogue above. The honest read is that
  ranked tuning is a code-default today, not yet a hot-editable JSON.
- **The broadcast/result _operations_ are real TypeScript surfaces.**
  `apps/v2/web/esports/results` is a static result archive and
  `apps/v2/esports-tools` (`@v2/esports-tools`) is the operator broadcast
  pipeline — both shipped, both explicitly _off the deterministic path_.
- **What is designed, not shipped:** the kernel anti-cheat client
  (`V2/ue/Plugins/V2AntiCheat/`) and the `libs/proto/v2/online` gRPC contract
  are absent (see
  [../architecture/online-backbone-and-competitive-integrity.md](../architecture/online-backbone-and-competitive-integrity.md)),
  and the AI-produced broadcast (commentary, lip-sync, translation) is a
  provider-gated capability the orchestration calls, not a model V2 trains (see
  [../architecture/esports-companion-and-ai-services.md](../architecture/esports-companion-and-ai-services.md)).

## Ranked season architecture (§75)

### One catalogue, four policies, one validator

The whole season hangs off `FV2RankedSeasonArchitectureCatalog`. Its scalar
frame is concrete and asserted: `SeasonLengthDays = 90`,
`PlacementMatchesAtSeasonStart = 10`, `OffSeasonTournamentCycleDays = 14`, plus
the booleans that encode the design's promises —
`bPerRegionSeasonOverlapEnabled`, `bOffSeasonTournamentCycleUsesSandboxedMMR`,
`bVisibleRanksUseHysteresis`, `bPlacementUsesPriorSeasonMMRSeed`, and
`bLegendIsTop100Global`. Hanging off it are four arrays/policies — the visible
tiers, the region seasons, the season rewards, and the `MMRPolicy`,
`DecayPolicy`, `CrownOverlay`, and `AntiThrowIntegrity` sub-structs. The spec
asserts the _negative_ cases as well as the positive: it constructs the default,
checks `IsValidCatalog`, then drives the subsystem and reads the runtime
snapshot back, demanding `RankedSeasonVisibleTierCount == 18` and
`RankedSeasonRegionCount == 5`. That round-trip — build → configure → snapshot —
is what makes this a checked spec rather than decorative data.

### Visible tiers over a hidden rating

The visible ladder is **eight families** —
`EV2RankedVisibleTierFamily { Bronze, Silver, Gold, Platinum, Diamond, Master, Grandmaster, Legend }`
(`V2OnlineServicesTypes.h:128`) — expressed as **18 `FV2RankedVisibleTierSpec`
entries** (`:12203`). The default builder lays them out as
Bronze/Silver/Gold/Platinum/Diamond each in three divisions (a `MaxDivision = 3`
family) climbing on `MinimumHiddenMMR` from 0 up through 2250, then the three
apex singletons: Master (2400), Grandmaster (2600), and Legend (2850, the only
tier with `bTop100Global = true`). `HasAllVisibleRankTiers()`
(`V2OnlineServicesTypes.cpp:12329`) is not a length check — it iterates the five
divisional families requiring each of divisions 1-3 at `MaxDivision == 3`, then
requires a distinct Legend tier, so dropping Gold 2 or collapsing Diamond's
divisions fails validation outright. Every tier carries
`PromotionHysteresisMatches = 3` and `DemotionHysteresisMatches = 3` with
`bRequiresMinimumRankChangeMatches`, the field that implements the source's
"hysteresis prevents rapid promotion/demotion oscillation," and a
`bPublicRankIconEligible` flag the provisional system reads.

The rating that actually drives matchmaking is hidden.
`FV2RankedSeasonMMRPolicy` (`:12308`) pairs a `PrimarySkillModel = TrueSkill2`
with a `SecondarySkillModel = Glicko2` (the same rating family the platform's
`@oshun` services use), keeps both behind hidden profile ids with
`bHiddenMMRNeverShown = true`, seeds a new season from the prior one at
`PriorSeasonMMRSeedCarryoverPercent = 65`, and unifies the pool across
`{ PC, PlayStation, Xbox, Switch }` with `bUnifiedCrossPlatformMMRPool`,
`bCrossPlatformLeaderboard`, and `bPlatformIconLabels`.
`SupportsLaunchPlatforms()` verifies all four are present — the spec calls this
"cross-platform unified MMR covers PC PS5 XSX Switch2."
`bSmurfDetectionBlocksLowRankFarming` is the hook that keeps a sharp new account
out of Bronze.

### Placement, reset, decay, provisional

The per-ladder runtime lives in `FV2RankedLadderConfig` (`:11900`) and
`FV2RankedPlayerState` (`:11946`): `PlacementMatchCount`,
`StartingRating = 1000`, `SeasonalResetFloorRating = 900`,
`SeasonalResetCarryoverPercent = 50`, and a `TierThresholds` array resolved by
`ResolveTierId(Rating)`. The seasonal reset is a **real deterministic
algorithm**, not a flag —
`UV2OnlineServicesBlueprintLibrary::ApplyRankedSeasonReset()` computes the
rating offset from the ladder's starting rating, scales it by the carryover
percent, floors the result at `SeasonalResetFloorRating`, re-resolves the
visible tier, and re-arms the placement requirement:

```cpp
const int32 RatingOffset = CurrentState.SkillRating - LadderConfig.StartingRating;
const int32 ResetRating  = LadderConfig.StartingRating
    + (RatingOffset * LadderConfig.SeasonalResetCarryoverPercent) / 100;
OutResetState.SkillRating = FMath::Max(LadderConfig.SeasonalResetFloorRating, ResetRating);
OutResetState.TierId      = LadderConfig.ResolveTierId(OutResetState.SkillRating);
```

`FV2RankedSeasonDecayPolicy` (`:12356`) implements the rest of the lifecycle:
decay applies only to `{ Grandmaster, Legend }` after
`MasterPlusInactivityDays = 14` (`bDecayAppliesAboveMaster`), reactivation costs
one placement match, `ProvisionalMatchesRequired = 25` keeps the public rank
icon hidden for new accounts (`bRankIconHiddenDuringProvisional`), and
`WeeklyRetentionBonusPoints = 15` rewards consistent weekly play. Each is
asserted by the spec, which demands the provisional gate be exactly 25 and the
retention bonus be non-zero.

### Anti-throw integrity

The competitive-integrity layer specific to _ranked behaviour_ (as distinct from
the netcode anti-cheat covered in the
[online-services sibling page](./online-services-network-and-tournaments.md)) is
`FV2RankedSeasonAntiThrowIntegrityConfig` (`:12444`). It tracks loss streaks
against opponents more than `LowerMMRDeltaThreshold = 250` rating below you,
flags an `AnomalousLossStreakThreshold = 3`, queue-penalizes chronic decliners
above a `ChronicDeclineRatePercent = 35` for `QueuePenaltyMinutes = 15`, and
detects collusion when the same opponent recurs past
`CollusionRepeatOpponentThreshold = 2`. The booleans —
`bSandbaggingThrowDetection`, `bAutoDerankConfirmedThrowing`,
`bMatchAcceptanceDeclineRateTracked`, `bCoordinatedThrowDetection`,
`bUsesFairPlaySignals` — encode the source's "sandbagging / throwing detection,
match acceptance/decline rate tracked, coordinated-throw detection for
tournament play." Critically, `bUsesFairPlaySignals` means this consumes the
same fair-play event stream the ML classifiers do, and — matching the platform's
review-only posture — confirmed throwing _de-ranks_ rather than silently
banning; discipline routes out to the shared trust-and-safety plane.

## The esports circuit (§55)

### The TO admin console and the rule freeze

A tournament organizer drives V2 through `FV2TournamentAdminEventConfig`
(`:7433`): bracket, seed-manifest, schedule, broadcast run-of-show, and
auto-result webhook ids, a `SupportedBracketFormats` list over
`EV2TournamentBracketFormat { SingleElimination, DoubleElimination, RoundRobin, Swiss, Gsl }`,
a `NoShowTimeoutSeconds = 300`, a `MaxRoundExtensionSeconds = 600`, and the
TO-control booleans (`bManualSeedingEnabled`, `bDisqualificationEnabled`,
`bRoundExtensionOverrideEnabled`, `bAutoResultReportingEnabled`). The single
most important integrity feature is the **rule freeze**:
`FV2TournamentEditionRuleSnapshot` (`:7557`) captures a `RulesHash`, a
`ReplayHeaderId`, the `ImportedRulesFileName`, and the locked-down competitive
toggles — `bClassicControlsOnly`, `bDefaultStagesOnly`, `bDefaultCostumesOnly`,
`bDisablesMercyFriendshipBabality`, `bForcedP1LeftP2Right`,
`bFinisherPolicyLocked` — and stamps them with `bSavedInReplayHeader = true`.
This is the determinism dividend the architecture leans on everywhere: because
the match runs on an integer-frame simulator, freezing the TO's ruleset into the
replay header makes a recorded set reproducible against the exact conditions it
was played under. The cryptographic _pull-and-verify_ of third-party results
(Start.gg / Challonge / Battlefy) against that replay hash is the designed
server-authoritative contract — the replay-hash determinism that backs it is the
part that is architecturally real today.

### Crown Pro Tour points

The season-long competitive ranking is the **Crown overlay**.
`FV2RankedSeasonCrownOverlayConfig` (`:12394`) wraps a
`FV2CrownProTourRankingConfig` (`:7628`) and layers points from four sources —
`EV2RankedSeasonPointSource { Ranked, Tournament, Invitational, EvoBadge }` —
weighted `RankedPointWeight = 1`, `TournamentPointWeight = 3`,
`InvitationalPointWeight = 5`, `EvoBadgePointWeight = 2`, so a deep run at a
major outscores a month of laddering. The ranking config sets a
`QualificationCutoff = 32`, awards points from both official and partnered
tournaments, surfaces an in-game Crown leaderboard widget and a profile badge,
and exposes a read-only third-party API.
`bYearEndGrandFinalInvitesTopCrownPlayers` closes the loop: the season's top
Crown players are invited to the year-end Grand Final. The broader per-region
major/regional calendar the source describes (NA/EU/JP/KR/LATAM/SEA…, qualifier
→ regional final → world final) is layered on top of this points engine; the
racing modes carry their own parallel `FV2RacingEsportsBroadcastCatalog`
(`:26074`) with explicit per-region series, validated separately in the module
spec.

### The public result archive

`apps/v2/web/esports/results` is the shipped, static face of the circuit
(§55.8). Its `results.json` carries a `v2.esports.resultsArchive.v1` schema with
per-event, per-match, per-player, per-fighter records and `rankingWeights`
(championship 120, major 90, regional 55, local 25, plus an `8`-point win bonus
and a `2`-point replay bonus); `results.js` filters by fighter, player, date, or
event and computes the Crown-linked community power ranking. Its README is an
integrity statement as much as a description: the archive exposes _only_ public
competitive results — never raw account identifiers, contact information,
private moderation notes, or unpublished replay links.

## Streamer, speedrun, coach & spectator modes (§55)

These four player-facing modes are the remaining sub-configs of the one
validated `FV2EsportsTournamentFeatureSet`, each with a real cross-checking
validator.

### Spectator & broadcast

`FV2EsportsSpectatorPolicy` (`:7383`) caps in-match observers at
`MaxInMatchObservers = 8` (clamped), throttles spectator chat to
`ChatMessagesPerMinute = 6`, sets an `AntiLeakDelaySeconds = 120` anti-spoiler
buffer, and enables the production toolkit — director-cam, scriptable cuts,
picture-in-picture, the side-by-side stick cam, drawing tools, freeze-frame,
slow-motion, name plates, and the score overlay. The caster's surface is
`FV2BroadcastControlSurface` (`:7499`): a manual control surface with
configurable `SupportedDelaySeconds` (0/30/60/120), output integrations over
`EV2BroadcastOutputIntegration { Obs, Ndi, Spout, BrowserSource, JsonWebSocket }`,
replay-marker clip-cut, a post-match recap reel, and a documented public SDK at
`apps/v2/web/dev-portal/caster-api/schema.json`. Third-party overlay developers
consume `FV2CasterOverlayApiContract` (`:7828`) — a documented WebSocket route
(`/v2/caster-api/ws`) and REST route, gated by `bPerEventApiTokenRequired` so
only a verified TO's per-event token can read live match state. The _operator_
side of this — the actual program/clean-feed switcher, multiviewer, and
stream-health dashboard — is the shipped `@v2/esports-tools` package
(`apps/v2/esports-tools/esports-broadcast-pipeline.ts`), which composes
`@uzume/broadcast` and tags itself `off-rollback-broadcast-operations`; its OBS
WebSocket use is scoped to "streamer-mode-notification-suppression-only," and
result-reporting journalism runs through `@veritas/fact-checking`. None of it
can perturb the sim.

### Streamer mode & stream-safe music

`FV2StreamerModePrivacyProfile` (`:7672`) is the broadest of the validators.
`IsValidProfile` (`V2OnlineServicesTypes.cpp`) refuses the profile unless the
anti-stream-snipe match-start delay is configurable inside 1-5 minutes
(`MinAntiStreamSnipeDelaySeconds = 60`, `Max = 300`, with `Min <= Max`) _and_
every privacy flag is set: hide handles and region, show the opponent as
"Opponent," default voice chat off, blur non-friend avatars/emotes/lobby chat,
suppress capture-aware notifications, auto-activate stream-safe music, and
persist the pause/main-menu quick toggles. A second clause requires the streamer
toolkit — the overlay generator, Twitch/YouTube/Kick channel binding, OBS
browser-source widgets, subscriber-tier cosmetic gift triggers, and stream-aware
notification suppression. The "stream-safe music automatically swaps licensed
tracks for cleared analogues" promise is a _different module_:
`FV2StreamerSafeMusicCatalog` (`V2Audio/Public/V2AudioTypes.h:6205`) carries
per-track license metadata (`bPerTrackLicenseMetadataRequired`), a DMCA-safe
toggle, and a `ResolveTrack()` that returns a cleared replacement for a
restricted track, with `bAutoApplyDefaultPresetInStreamerMode` wiring it to the
privacy profile's `bAutoActivatesStreamSafeMusic`. It is validated by its own
`FV2StreamerSafeMusicSpec`.

### Coach mode & async coaching

`FV2CoachSessionConfig` (`:7746`) models both halves of the source's coaching
story. The live half binds a `PlayerAccountId` and `CoachAccountId` into a
training lobby (`bTrainingOnlineLobby`) where the coach gets a separate camera
(`bCoachSeparateCamera`), can record and play back dummy inputs
(`bRecordPlaybackDummyInputs`), annotate moments (`bMomentAnnotations`), and
push notes to the player (`bPushNotesToPlayer`). The async half is
`bAsyncReplayAnnotations` with `bPlayerNotifiedForAnnotatedReplay`: a coach
attaches annotations to a submitted replay and the player is notified to watch
it back. The deterministic replay pipeline this rides on is documented in the
[mode catalogue & replay page](./mode-catalog-training-and-replay.md).

### Speedrun support

`FV2SpeedrunSupportConfig` (`:7790`) ships the built-in run timer
(`bBuiltInRunTimer`) with per-mode split definitions
(`SplitDefinitionSetId = "Speedrun.Splits.LaunchModes"`), a pace tracker against
personal best, and two integration seams: a local LiveSplit bridge on PC
(`bLiveSplitLocalWebSocketPc`, `LiveSplitLocalWebSocketPort = 16834`) and a
_read-only_ ingest from the speedrun.com partner program
(`SpeedrunPartnerProgramId = "speedrun.com.partner.readonly"`). The read-only
framing is deliberate — V2 displays community speedrun standings without letting
an external surface write into the competitive record. (The _Speedrun Race_
multiplayer stipulation — racing the Arcade ladder side-by-side — is a separate
mode-catalogue spec, `FV2SpeedrunRaceModeSpec`, covered in
[signature events & standalone modes](./signature-events-and-standalone-modes.md).)

## How it connects

Ranked seasons and the esports feature set are both `V2OnlineServices` C++
catalogues validated by contract specs, and they share a spine: the
deterministic, integer-frame match. That determinism is what lets the
Tournament-Edition snapshot freeze a ruleset into a replay header, lets the
anti-throw layer and the server validators re-derive a result from inputs, and
lets the AI-produced broadcast sit entirely off the simulation path. The numbers
that tune the ladder are a C++ build-default today, not yet hot-editable JSON;
the kernel anti-cheat client and the gRPC wire contract are designed, not
present; and the generative half of the broadcast is a provider-gated capability
the orchestration calls. Everything player-facing here — the eight rank
families, the ten-part esports feature set, the streamer privacy profile, the
public result archive — is shipped and pinned by a spec that would fail on a
stub. The section hub is [../V2_features.md](../V2_features.md).

## Related

- [Online Services, Network & Tournaments](./online-services-network-and-tournaments.md)
  — the matchmaking backbone, netcode selection, anti-cheat, and TO tooling this
  ladder rides on
- [Community, Store, Support & AI Services](./community-store-support-and-ai-services.md)
  — the season rewards, the companion app, and the AI-produced commentary the
  broadcast consumes
- [Mode Catalogue, Training & Replay](./mode-catalog-training-and-replay.md) —
  the deterministic replay pipeline behind coach annotations and the broadcast
  recap reel
- [Signature Events & Standalone Modes](./signature-events-and-standalone-modes.md)
  — the EVO Top 8 / King of Iron Fist event catalogue and the Speedrun Race
  stipulation
- [Esports, Companion & AI Services](../architecture/esports-companion-and-ai-services.md)
  — the architecture companion for the broadcast/spectator stack and the
  provider-gated AI services
- [Online Backbone & Competitive Integrity](../architecture/online-backbone-and-competitive-integrity.md)
  — the backbone, the replay-hash integrity check, and the designed-not-present
  surfaces
- The section hub: [../V2_features.md](../V2_features.md) </content> </invoke>
