# Live Service, DLC, Battle Pass & Companion

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](../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 resolving `upcoming | active | ended` with 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](../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](./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 `evidenceRef`s (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."

```mermaid
flowchart LR
  Sched[live-event-scheduling] -->|active window| Modes[event queues + rewards]
  Dlc[dlc-content-delivery] -->|entitlement + delta plan| Client[V2 client]
  Pass[season-pass-service] -->|XP grants + tiers| Client
  Incident[outage / bug] --> Comp[player-compensation] -->|idempotent ledger| Client
```

### 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](../architecture/security-compliance-and-sister-monorepo-integration.md)
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](./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](./signature-events-and-standalone-modes.md) 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](./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 `V2CompanionCoachAnnotation`s delivered `coach-stream` or `push-preview`
(e.g. an "anti-air gap" or "oki repeat" note a coach attaches to a submitted
replay), `V2CompanionPushNotificationTopic`s 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](../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](./community-store-support-and-ai-services.md)
  — the store, premium currency, community surfaces, support SLAs, and AI
  commentary this live-ops spine feeds
- [Ranked, Esports Circuit & Local Co-op](./ranked-esports-circuit-and-local-coop.md)
  — the ranked ladder and anti-cheat path the pass's replay-evidenced XP sources
  validate against
- [Signature Events & Standalone Modes](./signature-events-and-standalone-modes.md)
  — the limited-time-game-mode scheduling that pairs with the event calendar
- [Relationships, Progression & Creator Suite](./relationships-progression-and-creator-suite.md)
  — Character Mastery and the account-progression ladder the pass sits beside
- [Live-Ops, Store, Progression & Community](../architecture/live-ops-store-progression-and-community.md)
  — the architecture companion: the service topology, GameFeaturePlugin
  delivery, and the economy/community substrates
- The section hub: [../V2_features.md](../V2_features.md)
