A fighting game in 2026 is not a box you finish — it is a service you keep
making. V2's post-launch product is the part of the game that ships after
launch and keeps shipping for years: paid DLC fighters, free balance patches,
seasonal cosmetic drops, a 60-tier battle pass with daily and weekly challenges,
limited-time events wheeled on and off the calendar, make-good grants when
something breaks, and a read-only phone companion that follows the player out of
the match. This page is the feature-side companion to the "Online, Esports &
Live Service" group, and it is unusually honest about a split that runs straight
through the middle of the subject: the live-ops machinery is real, shipped
TypeScript under apps/v2/, while a good deal of the content that machinery
is built to deliver — the specific Year-1 roster, the five-faction weekly war —
is design and balance data the services are designed to execute, not engine
artifacts on disk. Where a claim is backed by code this page names the package
and function; where it is a plan it says so. The section hub is
../V2_features.md.
What ships, honestly#
Four live-ops service packages are real, validated, test-backed TypeScript
libraries, each with a co-located .spec.ts:
@v2/season-pass-service(apps/v2/season-pass-service/src/season-pass-service.ts) — the battle pass: a 60-tier, 90-day XP track with free and premium lanes, server-authoritative idempotent XP grants, an XP-source model, and a daily/weekly challenge rotation. Fully implemented.@v2/dlc-content-delivery-service(.../dlc-content-delivery-service.ts) — entitlement-gated, delta-aware download planning for fighter, story, and cosmetic packs. Fully implemented.@v2/live-event-scheduling-service(.../live-event-scheduling-service.ts) — a server-authoritative event calendar resolvingupcoming | active | endedwith conflict validation. Fully implemented.@v2/player-compensation-service(.../player-compensation-service.ts) — incident-scoped, evidence-backed, approval-gated make-good campaigns with an idempotent grant ledger. Fully implemented.
The content-delivery mechanism is real engine tech — Unreal's
GameFeaturePlugin system — but the arch companion is explicit that only three
.uplugin files exist on disk and none are the V2Event_* / DLC-pack plugins
the Year-1 roadmap describes; those are target artifacts. The MKX-style
five-faction system (Lin Kuei, Black Dragon, Special Forces, Brotherhood of
Shadow, White Lotus, with a weekly faction war) is spec plus balance data,
not one of these services — and the one faction package that is real,
@v2/aje-faction-governance, is a different thing entirely (an opt-in fan-token
governance gate, not the progression ladder; see the naming caveat below).
Character Mastery is grounded in real balance CSVs. The companion app is
real but, by deliberate design, read-only and not a play surface. The
architecture-level treatment of all of this lives in the arch companion
../architecture/live-ops-store-progression-and-community.md.
Live service & DLC#
Content delivery: the three live-ops services#
Post-launch content rides three of the four services. The
dlc-content-delivery-service models a DLC pack as a typed
V2DlcContentPack carrying a platformSku, an entitlement:dlc:* reference, a
sha256:-prefixed manifestHash, and a list of assets that each mount under
/Game/ from an https:// URI. Its default catalogue ships one of every pack
kind the validator requires — a Nyx Fighter Pack (~620 MB), a Storm Market
Story Expansion (~1.25 GB), and a Golden Gi Cosmetic Pack (~90 MB) — and
validatePackKindCoverage throws if any of fighter-pack, story-expansion,
or cosmetic-pack is missing. The load-bearing function is
planV2DlcContentDownload: it first verifies the account holds the pack's
entitlement (returning lockedReason: 'entitlement-required' and a zero-byte
plan if not), then computes a delta download by filtering out any asset
whose contentHash is already in installedContentHashes, and sums
totalDownloadBytes over only what is genuinely pending. Every plan is stamped
serverAuthoritative: true and requiresClientPatch: false — the core live-ops
promise that content reaches the player without a client rebuild.
The live-event-scheduling-service runs the calendar. A
V2LiveEventScheduleDefinition carries startsAt / endsAt, an optional
visibilityStartsAt (so an event can be revealed before it goes live),
regions, activationTags, per-event game modes (each with a queueId,
rulesetId, and optional minimumClientVersion), and rewards. The default
schedule defines a global Summer Rivals Weekend (2026-06-24 → 06-30) and a
region-scoped Storm Trials (NA/EU/APAC, 2026-07-04 → 07-11).
resolveNormalizedScheduleState derives upcoming | active | ended purely from
the current time against the window, and validateGameModeWindowConflicts
refuses to build a schedule where two time-overlapping events share a modeId
or queueId — so the calendar cannot accidentally double-book a queue. This is
the same scheduling shape the signature-event cluster leans on through
@v2/limited-time-game-mode-service (see
./signature-events-and-standalone-modes.md).
When live service goes wrong, the player-compensation-service is a
first-class capability, not an afterthought. A V2PlayerCompensationCampaign is
scoped to an incidentId, tagged with a reason of bug or outage (the
validator requireDefaultReasonCoverage insists the system carries both),
backed by per-player evidenceRefs (telemetry pointers) and a severity of
minor | major | critical, and approval-gated — every campaign must carry
at least one approval record naming approvedBy, approvedAt, and an
approvalReason. The two default campaigns model exactly the live-ops reality:
a ranked-reconnect make-good (a bug, 500 season-credits plus a reconnect
cache to two affected accounts) and a matchmaking-outage apology (an outage,
250 fight-coins plus an apology banner to one critically-affected account).
planV2PlayerCompensationGrants mints a deterministic
comp:<campaign>:<account> grant id per affected player and skips any already
in processedGrantIds; applyV2PlayerCompensationGrant then folds the bundle
into a per-account ledger, returning applied: false, duplicate: true on a
replayed grant. That idempotency is the difference between "we compensated you"
and "we compensated you four times because the job retried."
The Year-1 shape, the plugin lifecycle, and the no-coming-soon rule#
The roadmap the services execute — 4 character DLC packs, a mode-expansion
DLC, two-paid-fighters-per-year minimum, quarterly cosmetic drops, and a free
side of balance patches, stages, tower content, tutorials, and accessibility —
is honestly a plan, the split that keeps the competitive base unified
(everyone gets balance and stages) while monetising cosmetics and roster. A DLC
plugin's documented lifecycle (authored → certified → staged → live → sunset),
the hot-removal of license-conditional content, and the "every advertised mode
ships content-complete, no coming-soon panels" promise are product commitments
the GameFeaturePlugin mechanism is built to satisfy; the
requiresClientPatch: false flag the delivery service emits is the code-level
expression of the "staged plugins unlock at the calendar date without a patch"
behaviour. A canary-failed patch's automatic rollback to the prior signed
manifest, and the premium-currency spend/refund/region rules (owned by
@maat/finance per the monolith), live across the
Security & Compliance
and store layers rather than in these four packages. One honest note on
currency: the implemented services traffic in earned/grant currencies
(season-credits, fight-coins); the premium store currency (the design docs'
"Crowns"/"Krystals") and its spend ledger are an @maat/finance concern, not
hardcoded here.
Battle pass, daily/weekly challenges & factions#
The battle pass — fully implemented#
The season-pass-service is the deepest of the four. Its default season,
season-2026-summer-rivals ("Summer Rivals", 2026-06-21 → 2026-09-19), is a
V2_SEASON_PASS_MAX_TIERS = 60, V2_SEASON_PASS_MAX_DURATION_DAYS = 90 track
where each tier's xpRequired is index × 1000 (tier 1 at 0 XP, tier 60 at
59,000), and every tier carries both a free and a premium reward — the
validator normalizeTierDefinitions rejects a track whose tiers are
non-sequential, non-monotonic in XP, or missing a lane. buildRewardUnlocks
walks tiers up to the player's current tier and marks each premium reward
claimable only when premiumEntitlement is true, otherwise stamping
lockedReason: 'premium-entitlement-required' — the code-level guarantee that
the premium track grants cosmetics, titles, and emotes but never gates a
competitively relevant item behind a paywall. Tier position is computed by
resolveV2SeasonPassTierProgress, which caps total XP at the final tier and
reports xpIntoTier, xpToNextTier, and a completionPercent.
XP is server-authoritative and idempotent. applyV2SeasonPassXpGrant
short-circuits and returns the unchanged state if a grantId is already in
processedGrantIds, so a retried grant never double-credits. The XP-source
model (V2_DEFAULT_SEASON_PASS_XP_SOURCE_DEFINITIONS) defines four sources,
each serverAuthoritative: true, with a base and a hard per-grant ceiling:
match-completion (150 base / 500 max), daily-challenge (500 / 1000),
weekly-challenge (1500 / 2500), and event-bonus (250 / 2000). The
match-and-challenge sources are flagged replayEvidenceRequired and
antiCheatValidated — the source-side hook for "the client attaches the
deterministic replay as evidence and the server validates completion against it"
(cross-ref the anti-cheat path in
./ranked-esports-circuit-and-local-coop.md).
calculateV2SeasonPassXpGrantFromSource clamps every award to
min(baseXp × multiplier, maxXpPerGrant), so an event multiplier can never blow
past the ceiling.
Daily and weekly challenges#
The challenge system is a real deterministic rotation, not a random shuffle.
buildV2SeasonPassChallengeSystemSurface draws from a typed challenge pool
(five daily, four weekly entries by default — "Win 6 rounds", "Land 8 special
moves", "Complete 5 ranked sets", "Land 40 combo finishers", and so on), each
tagged with a cadence, a category (combat | engagement | ranked | event),
an objectiveKey, a targetValue, a weight, and XP/currency rewards.
selectRotatingChallenges scores each candidate by
buildHashUnit(<rotationId>:<challengeId>) / weight and takes the lowest — a
weight-biased but fully deterministic selection keyed to the rotation id, so
the same UTC day reproduces the same dailies and a heavier-weighted challenge is
more likely to surface. buildChallengeRotationWindow snaps the daily window to
UTC midnight and the weekly window to the preceding Monday (the source's
"dailies rotate at 00:00, weeklies rotate Monday"). The spec
(season-pass-service.spec.ts) pins this precisely — one test asserts dailies
auto-rotate while weeklies stay stable during the same UTC week. Completion
runs through completeV2SeasonPassChallenge, which issues both an XP grant
(routed to the matching daily-challenge / weekly-challenge source) and a
season-credits currency grant under one deterministic, idempotent
challenge:<season>:<account>:<rotation>:<challenge> key. Because the daily
challenge's XP feeds the same pass track, "one objective set feeds both" is
literal here, not aspirational.
The faction system — spec, with one real namesake to disambiguate#
This is the page's sharpest honesty line. The MKX-style five-faction war the
monolith describes — pick one of five factions at first launch, every match
contributes faction XP to a global leaderboard, a weekly faction-vs-faction
event grants the winning faction an exclusive cosmetic, a 7-day switch cooldown
forfeits the week's contribution — is not implemented in these services. The
season pass's XP sources are match/daily/weekly/event; there is no
faction-quest source and no faction-war leaderboard in the live-ops packages.
The faction concept surfaces only as balance data (faction quests appear in
V2/balance/progression/quest-log-catalog.csv). The one package whose name
collides — @v2/aje-faction-governance — is a genuinely different system: an
opt-in, off-rollback fan-token governance gate (fan_token_gated_gameplay)
that links an external token balance to faction votes, with a loud consent
warning before it exposes anything outside the client. It is not the progression
ladder; treating it as the MKX faction system would be a category error, so this
page flags the collision the way the
signature-events page flags the
KOF. prefix trap.
Character Mastery, by contrast, is grounded: fighter-mastery-tracks.csv
defines a per-fighter Curve.Mastery.Standard to max_level = 30, each
pointing at mastery-level-rewards.csv and a seasonal boost_rotation_theme —
the 1-30 mastery ladder unlocking intros, poses, color slots, and the Mastery-30
signature kit (cross-ref
./relationships-progression-and-creator-suite.md).
The companion app#
The companion is a shell-native iOS/Android app that is read-only by design,
real on disk at apps/oshun/mobile/v2/ (V2CompanionApp.tsx,
companionAppModel.ts, a V2CompanionLaunchTile.tsx, and a .test.tsx). Its
V2CompanionModel types out the out-of-game surfaces the monolith promises: a
V2CompanionSecondScreenMode (a low-fidelity stream with a timeline scrubber,
chapter tags, and coach-note review — cosmetic-only, no gameplay effect), a
list of V2CompanionCoachAnnotations delivered coach-stream or push-preview
(e.g. an "anti-air gap" or "oki repeat" note a coach attaches to a submitted
replay), V2CompanionPushNotificationTopics for the per-category opt-out push
handoff (match-end, party-invite, tournament-round, daily-challenge, pass-tier),
plus wearable glances and cross-feature deep links. The arch companion is blunt
about the boundary: a phone is not a deterministic match client, so the app is
explicitly not a play surface and not a cross-play participant — kept
entirely outside the competitive path, composing the same backbone (auth,
replay, store) read-side only.
The public API is a real artifact too: libs/openapi/v2/companion.yaml ("V2
Companion Public API", ~30 KB) is the typed contract the app and third-party
integrations read. It carries x-ratelimit-limit / x-ratelimit-window-seconds
headers on its endpoints and an authenticated tournament-organizer
bracket-creation endpoint (single/double-elimination and round-robin), which is
the OpenAPI expression of the monolith's rate-limit tiers (100 req/min
unauthenticated, 1000 for a registered app, 30 per account on personal data) and
TO webhooks. The knowledge surfaces (/v2/wiki, /v2/glossary, /v2/roadmap)
and the broader companion/AI-broadcast story are covered in
../architecture/esports-companion-and-ai-services.md.
How it connects#
The through-line is consistent with the rest of V2: the machinery is real service code composing the shared Oshun economy, governance, and content substrates, and the page is precise about where shipped TypeScript ends and the Year-1 roadmap (and the faction war) begins. Entitlements and cross-progression that bind a pass, a vault, and a DLC unlock to one identity are the online backbone's; the spend limits, region pricing, and hotfix-rollback mechanics are the compliance layer's; the limited-time-mode scheduling these events share is the signature-event cluster's.
Related#
- Community, Store, Support & AI Services — the store, premium currency, community surfaces, support SLAs, and AI commentary this live-ops spine feeds
- Ranked, Esports Circuit & Local Co-op — the ranked ladder and anti-cheat path the pass's replay-evidenced XP sources validate against
- Signature Events & Standalone Modes — the limited-time-game-mode scheduling that pairs with the event calendar
- Relationships, Progression & Creator Suite — Character Mastery and the account-progression ladder the pass sits beside
- Live-Ops, Store, Progression & Community — the architecture companion: the service topology, GameFeaturePlugin delivery, and the economy/community substrates
- The section hub: ../V2_features.md